/* Here is stuff for interfacing to directories. ** Copyright (c) 1993, 1994 by Olin Shivers. */ #include #include #include #include #include #include #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