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
 |