getsdir.c
上传用户:tianjinjs
上传日期:2007-01-05
资源大小:309k
文件大小:11k
源码类别:

Modem编程

开发平台:

Unix_Linux

  1. /*
  2.  * getsdir.c
  3.  *
  4.  * Get and return a sorted directory listing
  5.  *
  6.  * Copyright (c) 1998 by James S. Seymour (jseymour@jimsun.LinxNet.com)
  7.  *
  8.  * This code is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU General Public License
  10.  * as published by the Free Software Foundation; either version
  11.  * 2 of the License, or (at your option) any later version.
  12.  *
  13.  * Note: this code uses "wildmat.c", which has different copyright
  14.  * and licensing conditions.  See the source, Luke.
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <errno.h>
  23. #include "port.h" /* from minicom: for needed for _PROTO macro only */
  24. #include "getsdir.h"
  25. _PROTO(extern int wildmat, (char *, char *)); /* pattern matcher */
  26. /* locally defined constants */
  27.  
  28. #define MAX_CNT 100 /* number of entries to hold in holding buf */
  29. typedef struct dat_buf { /* structure of input buffers */
  30.     struct dat_buf *nxt; /* pointer to next buffer */
  31.     unsigned cnt; /* data count in present buffer */
  32.     GETSDIR_ENTRY data[MAX_CNT]; /* data in present buffer */
  33. } DAT_BUF;
  34. static DAT_BUF *datb_frst; /* pointer to first data buffer */
  35. static DAT_BUF *datb_cur; /* pointer to current data buffer */
  36. static int g_sortflags; /* sort flags */
  37. /* sort compare routines */
  38. _PROTO(static int namecmpr, (GETSDIR_ENTRY *d1, GETSDIR_ENTRY *d2));
  39. _PROTO(static int timecmpr, (GETSDIR_ENTRY *d1, GETSDIR_ENTRY *d2));
  40. _PROTO(static void free_up, (void)); /* free-up used memory */
  41. /*
  42.  * name: getsdir
  43.  *
  44.  * purpose: To return a directory listing - possibly sorted
  45.  *
  46.  * synopsis: #include <dirent.h>
  47.  *
  48.  * int getsdir(dirpath, pattern, sortflags, modemask, datptr, len)
  49.  * char *dirpath;
  50.  * char *pattern;
  51.  * int sortflags;
  52.  * mode_t modemask;
  53.  * GETSDIR_ENTRY **datptr;
  54.  * int *len;
  55.  *
  56.  * input:  *dirpath - pointer to path to directory to get list of
  57.  *     files from
  58.  *  *pattern - pointer to optional wildmat pattern
  59.  * sortflags - specification flags of how to sort the
  60.  *     resulting list.  See descriptions below.
  61.  *  modemask - caller-supplied mode mask.  Bits in this will
  62.  *     be ANDed against directory entries to determine
  63.  *     whether to return them.  Ignored if 0.
  64.  *  **datptr - pointer to a destination pointer variable.
  65.  *     getsdir will allocate the required amount
  66.  *     of memory for the results and will return a
  67.  *     pointer to the returned data in this variable.
  68.  *
  69.  *     The data will be in the form:
  70.  * typedef struct dirEntry {
  71.  *     char fname[MAXNAMLEN + 1];
  72.  *     time_t time;
  73.  *     mode_t mode;
  74.  * } GETSDIR_ENTRY;
  75.  *      *len - pointer to int to contain length of longest
  76.  *     string in returned array.
  77.  *
  78.  * process: For each 0..MAX_CNT values read from specified directory,
  79.  * allocates a temporary buffer to store the entries into.
  80.  * When end of directory is detected, merges the buffers into
  81.  * a single array of data and sorts into order based on key.
  82.  *
  83.  * output: Count of number of data items pointed to by datptr or
  84.  * -1 if error.  errno may or may not be valid, based on
  85.  * type of error encountered.
  86.  *
  87.  * notes: If there is any error, -1 is returned.
  88.  *
  89.  * It is the caller's responsibility to free the memory
  90.  * block pointed to by datptr on return when done with the
  91.  * data, except in case of error return.
  92.  *
  93.  * See also: opendir(3C), readdir(3C), closedir(3C), qsort(3C)
  94.  *
  95.  * The pattern parameter is optional and may be 0-length or
  96.  * a NULL pointer.
  97.  *
  98.  * The sort flags affect the output as follows:
  99.  *
  100.  *     GETSDIR_PARNT - include parent dir (..)
  101.  *     GETSDIR_NSORT - sort by name
  102.  *     GETSDIR_TSORT - sort by time (NSORT wins if both)
  103.  *
  104.  *     The following are only meaningful if GETSDIR_NSORT or
  105.  *     GETSDIR_TSORT are specified:
  106.  *
  107.  * GETSDIR_DIRSF - dirs first
  108.  * GETSDIR_DIRSL - dirs last
  109.  * GETSDIR_RSORT - reverse sort (does not affect
  110.  * GETSDIR_DIRSF/GETSDIR_DIRSL)
  111.  *
  112.  * So-called "hidden" files (those beginning with a ".") are
  113.  * not returned unless a pattern like ".*" is specified.
  114.  *
  115.  * The present directory (".") is never returned.
  116.  */
  117. int
  118. getsdir(dirpath, pattern, sortflags, modemask, datptr, len)
  119. char *dirpath;
  120. char *pattern;
  121. int sortflags;
  122. mode_t modemask;
  123. GETSDIR_ENTRY **datptr;
  124. int *len;
  125. {
  126.     unsigned cnt; /* data count */
  127.     DIR *dirp; /* point to open dir */
  128.     struct dirent *dp; /* structure of dir as per system */
  129.     struct stat statbuf; /* structure of file stat as per system */
  130.     char fpath[BUFSIZ]; /* filename with dir path prepended */
  131.     int indx; /* g-p array indexer */
  132.     int cmprstat;
  133.     DAT_BUF *datb_sav; /* pointer to previous data buffer */
  134.     g_sortflags = sortflags; /* for sort funcs */
  135.     *len = 0; /* longest name */
  136.     datb_frst = (DAT_BUF *) NULL; /* init pointers to first data buff */
  137.     datb_cur  = (DAT_BUF *) NULL;
  138.     /* open the specified directory */
  139.     if ((dirp = opendir(dirpath)) == NULL)
  140.         return(-1);
  141.     /* discard current, and possibly parent, dir entries */
  142.     if(readdir(dirp) == NULL || 
  143. (!(sortflags & GETSDIR_PARNT) && readdir(dirp) == NULL))
  144.     {
  145. fprintf(stderr, "DBUG: initial readdir() failed (errno == %d)n",
  146.     errno);
  147. perror("readdir");
  148. fflush(stderr);
  149.     }
  150.     for(cnt = 1;; ++cnt) /* for buffer count 1 to whatever... */
  151.     {
  152. datb_sav = datb_cur; /* save pointer to previous buffer */
  153. /* get a new buffer */
  154.         if((datb_cur = (DAT_BUF*)calloc(1,sizeof(DAT_BUF))) == (DAT_BUF*)NULL)
  155. {
  156.     closedir(dirp);
  157.             return(-1);
  158. }
  159. /* init new buffer link pointer */
  160. datb_cur->nxt = (DAT_BUF *) NULL;
  161. if(datb_frst == (DAT_BUF *) NULL) /* if first buff... */
  162.             datb_frst = datb_cur; /* ...init first buff pointer */
  163. else /* else... */
  164.     datb_sav->nxt = datb_cur; /* ...link to new */
  165. /* while the current buffer is not full, get directory entries */
  166.         for(datb_cur->cnt = 0; datb_cur->cnt < MAX_CNT; )
  167.             if((dp = readdir(dirp)) != NULL) /* get next directory entry */
  168.     {
  169. if((sortflags & GETSDIR_PARNT) &&
  170.    strcmp(dp->d_name, "..") == 0)
  171. {
  172.     cmprstat = 1;
  173. }
  174. else if(pattern && strlen(pattern))
  175.     cmprstat = wildmat(dp->d_name, pattern);
  176. else
  177.     cmprstat = 1;
  178. if(cmprstat) /* matching name? */
  179. {
  180.     int l;
  181.     /* copy the filename */
  182.     strncpy(datb_cur->data[datb_cur->cnt].fname,
  183.     dp->d_name,
  184.     MAXNAMLEN);
  185.             /* get information about the directory entry */
  186.             snprintf(fpath, sizeof(fpath), "%s/%s", dirpath, dp->d_name);
  187.                     if(stat(fpath, &statbuf)) /* if error getting stat... */
  188.     {
  189. #if 0
  190. free_up(); /* free-up used memory */
  191.         closedir(dirp); /* close file pointer */
  192.         return(-1); /* nobody home */
  193. #endif
  194. continue;
  195.     }
  196.     if(modemask && !(S_IFMT & modemask & statbuf.st_mode))
  197. continue;
  198.     if((l = strlen(dp->d_name)) > *len)
  199. *len = l;
  200.     datb_cur->data[datb_cur->cnt].time = statbuf.st_mtime;
  201.     datb_cur->data[datb_cur->cnt].mode = statbuf.st_mode;
  202.     ++datb_cur->cnt; /* bump array index / data count */
  203. }
  204.     }
  205.     else
  206.         break; /* at end of directory */
  207. if(datb_cur->cnt < MAX_CNT) /* if less than full buffer... */
  208.     break; /* ...all done */
  209.     }
  210.     
  211.     closedir(dirp); /* close file pointer */
  212.     /* get memory for single array */
  213.     if((*datptr = (GETSDIR_ENTRY *) calloc(cnt, sizeof(datb_cur->data)))
  214. == NULL)
  215.     {
  216. /* couldn't get space, clear everything up */
  217. free_up(); /* free-up used memory */
  218.         return(-1); /* error */
  219.     }
  220.     /* copy/concatenate the data */
  221.     cnt = indx = 0; /* init final count and dest index */
  222.     do
  223.     {
  224. datb_cur = datb_frst;
  225. /* copy data in one swell foop */
  226. memcpy(*datptr+indx*MAX_CNT, datb_cur->data, sizeof(datb_cur->data));
  227. cnt += datb_cur->cnt; /* adjust data count */
  228. ++indx; /* bump destination index */
  229. datb_frst = datb_cur->nxt;
  230. free(datb_cur); /* free no longer needed buffer */
  231.     } while (datb_frst);  /* while more to go */
  232.     free_up(); /* free-up used memory */
  233.     /* post-process array by option */
  234.     if(cnt && sortflags) {
  235. if(sortflags & GETSDIR_NSORT)
  236.     qsort(*datptr, cnt, sizeof(GETSDIR_ENTRY),
  237.   (int (*)(const void *, const void *))namecmpr);
  238. else if(sortflags & GETSDIR_TSORT)
  239.     qsort(*datptr, cnt, sizeof(GETSDIR_ENTRY),
  240.   (int (*)(const void *, const void *))timecmpr);
  241.     }
  242.     return(cnt);
  243. } /* getsdir */
  244. /*
  245.  * name: free_up
  246.  *
  247.  * purpose: free up memory allocated for temporary buffers
  248.  *
  249.  * synopsis: static void freeup()
  250.  *
  251.  * input: none
  252.  *
  253.  * process: as under purpose
  254.  *
  255.  * output: none
  256.  *
  257.  * notes: none
  258.  */
  259. static void
  260. free_up()
  261. {
  262.     if((datb_cur = datb_frst) != (DAT_BUF *) NULL) /* start with first */
  263. do /* and free 'em all */
  264. {
  265.     datb_frst = datb_cur->nxt;
  266.     free(datb_cur);
  267. } while ((datb_cur = datb_frst));
  268. } /* free_up */
  269. /*
  270.  * name: namecmpr
  271.  *
  272.  * purpose: return stat to qsort on comparison between name fields in
  273.  * directory entry.
  274.  *
  275.  * synopsis: static in namecmpr(d1, d2)
  276.  * GETSDIR_ENTRY *d1;
  277.  * GETSDIR_ENTRY *d2;
  278.  *
  279.  * input: See explanation of qsort
  280.  *
  281.  * process: See explanation of qsort
  282.  *
  283.  * output: See explanation of qsort
  284.  *
  285.  * notes: See explanation of qsort
  286.  */
  287. static int
  288. namecmpr(d1, d2)
  289. GETSDIR_ENTRY *d1, *d2;
  290. {
  291.     if(g_sortflags & (GETSDIR_DIRSF | GETSDIR_DIRSL)) {
  292. if(S_ISDIR((d1->mode)) && ! S_ISDIR((d2->mode)))
  293.     return((g_sortflags & GETSDIR_DIRSF)? -1 : 1);
  294. else if(S_ISDIR((d2->mode)) && ! S_ISDIR((d1->mode)))
  295.     return((g_sortflags & GETSDIR_DIRSF)? 1 : -1);
  296.     }
  297.     return((g_sortflags & GETSDIR_RSORT)?
  298. strcmp(d2->fname, d1->fname) : strcmp(d1->fname, d2->fname));
  299. } /* namecmpr */
  300. /*
  301.  * name: timecmpr
  302.  *
  303.  * purpose: return stat to qsort on comparison between time fields in
  304.  * directory entry.
  305.  *
  306.  * synopsis: static in timecmpr(d1, d2)
  307.  * GETSDIR_ENTRY *d1;
  308.  * GETSDIR_ENTRY *d2;
  309.  *
  310.  * input: See explanation of qsort
  311.  *
  312.  * process: See explanation of qsort
  313.  *
  314.  * output: See explanation of qsort
  315.  *
  316.  * notes: See explanation of qsort
  317.  */
  318. static int
  319. timecmpr(d1, d2)
  320. GETSDIR_ENTRY *d1, *d2;
  321. {
  322.     if(g_sortflags & (GETSDIR_DIRSF | GETSDIR_DIRSL)) {
  323. if(S_ISDIR((d1->mode)) && ! S_ISDIR((d2->mode)))
  324.     return((g_sortflags & GETSDIR_DIRSF)? -1 : 1);
  325. else if(S_ISDIR((d2->mode)) && ! S_ISDIR((d1->mode)))
  326.     return((g_sortflags & GETSDIR_DIRSF)? 1 : -1);
  327.     }
  328.     return((g_sortflags & GETSDIR_RSORT)?
  329. (d2->time - d1->time) : (d1->time - d2->time));
  330. } /* timecmpr */
  331. #ifdef GETSDIR_STANDALONE_TEST
  332. /*
  333.  * debug for getsdir()
  334.  *
  335.  * usage: getsdir <dirpath>
  336.  *
  337.  */
  338. extern char *ctime();
  339. void
  340. main(argc, argv)
  341. int argc;
  342. char *argv[];
  343. {
  344.     GETSDIR_ENTRY *dirdat;
  345.     int cnt, index;
  346.     int sortflags = 0;
  347.     mode_t modemask = (mode_t) 0;
  348.     int len;
  349.     if(argc != 4)
  350.     {
  351.       fprintf(stderr,"usage: %s <dirpath> <pattern> <sortflags>n", argv[0]);
  352.       exit(1);
  353.     }
  354.     switch(argv[3][0]) {
  355. case 'n': sortflags = GETSDIR_NSORT;
  356.   break;
  357. case 't': sortflags = GETSDIR_TSORT;
  358.   break;
  359.     }
  360. /*    sortflags |= GETSDIR_DIRSL | GETSDIR_RSORT; */
  361.     sortflags |= GETSDIR_DIRSF;
  362. /*    sortflags |= GETSDIR_PARNT; */
  363. /*    modemask = S_IFDIR | S_IFREG; */
  364.     printf("modemask==%xn", modemask);
  365.     if((cnt = getsdir(argv[1], argv[2], sortflags, modemask, &dirdat, &len)) == -1)
  366.     {
  367. fprintf(stderr, "%s: error getting directoryn", argv[0]);
  368. exit(1);
  369.     }
  370.     printf(_("%d files:n"), cnt);
  371.     for(index = 1; index <= cnt; ++index, ++dirdat)
  372.         printf("%2d: %-20s%s",
  373.     index, dirdat->fname, ctime(&dirdat->time));
  374.     free(dirdat);
  375.     exit(0);
  376. }
  377. #endif