146 lines
3.5 KiB
C
146 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 <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "libcig.h"
|
|
#include "scsh_aux.h"
|
|
|
|
/* Make sure our exports match up w/the implementation: */
|
|
#include "dirstuff1.h"
|
|
|
|
extern int errno;
|
|
|
|
/* 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
|