scsh-0.5/scsh/dirstuff1.c

145 lines
3.5 KiB
C

/* Here is stuff for interfacing to directories.
** Copyright (c) 1993, 1994 by Olin Shivers.
*/
#include <sys/types.h>
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "libcig.h"
#include "scsh_aux.h"
/* Make sure our exports match up w/the implementation: */
#include "dirstuff1.h"
/* Linked list of malloc'd entries. */
struct scm_dirent_struct
{ char *fname; /* File name */
struct scm_dirent_struct *next;}; /* Next pointer */
typedef struct scm_dirent_struct scm_dirent_t;
void free_dirent_list(scm_dirent_t *entry)
{
while(entry) {
scm_dirent_t *next = entry->next;
Free(entry);
entry = next;
}
}
/* Returns [err, fnames, len]
** err is 0 for success, otw errno.
** fnames is a vector of strings (filenames), null terminated.
** len is the length of fnames.
*/
int open_dir(const char *dirname, char ***fnames, int *len)
{
scm_dirent_t *dep, *entries;
struct dirent *dirent;
char *fname, **dirvec, **vecp;
DIR *d;
int num_entries;
int e; /* errno temp */
if( NULL == (d = opendir(dirname)) ) {
fnames = 0; len = 0;
return errno;
}
entries = NULL; num_entries = 0;
while( NULL != (dirent = readdir(d)) ) {
if((strcmp(dirent->d_name,".") == 0) || (strcmp(dirent->d_name,"..") == 0))
continue;
if( NULL == (dep=Alloc(scm_dirent_t)) )
{e=errno; goto lose2;}
if( NULL == (fname=copystring(NULL, dirent->d_name)) ) goto lose1;
dep->fname = fname;
dep->next = entries;
entries = dep; num_entries++;
}
closedir(d);
/* Load the filenames into a vector and free the structs. */
if( NULL == (dirvec = Malloc(char *, num_entries+1)) )
{e=errno; goto lose3;}
for(dep=entries, vecp=dirvec; dep; vecp++) {
scm_dirent_t *next = dep->next;
*vecp = dep->fname;
Free(dep);
dep = next;
}
dirvec[num_entries] = NULL;
*fnames = dirvec;
*len = num_entries;
return 0;
lose1: e = errno; Free(dep);
lose2: closedir(d);
lose3: free_dirent_list(entries);
fnames = 0; len = 0;
return e;
}
#define DOTFILE(a) ((a) && *(a) == '.') /* Not a function. */
/* a <= b in the Unix filename ordering:
** dotfiles come first, lexicographically ordered.
** others come second, lexicographically ordered.
**
** This is for sorting filenames in directory listings.
*/
static int compare_fname(const void *aptr, const void *bptr)
{
char const *a = * (char const * *) aptr;
char const *b = * (char const * *) bptr;
if( DOTFILE(a) )
return DOTFILE(b) ? strcmp(a+1,b+1) : -1;
return DOTFILE(b) ? 1 : strcmp(a,b);
}
void scm_sort_filevec(const char **dirvec, int nelts)
{
qsort((char *) dirvec, nelts, sizeof(char*), compare_fname);
}
#if 0
/* This one is a little more complex, but we don't use it because we
** never try to sort lists of filenames with . or .. in the list.
*/
/* Boolean function: a <= b in the Unix filename ordering:
** . comes first
** .. comes second
** Other dotfiles come next, lexicographically ordered.
** Non-dotfiles come last, lexicographically ordered.
**
** This is for sorting filenames in directory listings.
*/
static int comp1(const void *aptr, const void* bptr)
{
char const *a = *(char const **)aptr;
char const *b = *(char const **)bptr;
if(streq(a,b)) return 0;
if(DOTFILE(a))
if( DOTFILE(b) )
return streq(a, ".") ||
(!streq(b, ".") && (streq(a, "..") || (!streq(b, "..") &&
(strcmp(a,b) <= 0))))
? -1 : 1;
else return -1;
else return DOTFILE(b) ? 1 : strcmp(a,b);
}
#endif