home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / C / GLOB.ZIP / GLOB.C < prev    next >
Encoding:
C/C++ Source or Header  |  1987-07-20  |  8.6 KB  |  334 lines

  1.  
  2. /*
  3.  *    Copyright 1985, 1986  by John Plocher  Non-commercial use approved
  4.  *
  5.  *    glob    expand a given pathname with wildcards into
  6.  *        an argv[] type array of 'strings' which are
  7.  *        the files (directories) which result from the
  8.  *        expansion of the pathname.  (All characters in
  9.  *        the returned list of filenames are in lower case)
  10.  *
  11.  *    usage:    char **glob(pathname) char *pathname;
  12.  *
  13.  *        pathname is an absolute or relative pathname which may
  14.  *        contain DOS type wildcards wherever desired:
  15.  *
  16.  *            names = glob("\\usr\\pl*\\*.c");
  17.  *
  18.  *    It requires an externally declared int in the main function
  19.  *    named globerror:
  20.  *
  21.  *        extern int globerror;
  22.  *
  23.  *    to be used to return an error indication if glob() fails.
  24.  *    If glob() fails, it returns NULL with
  25.  *
  26.  *    globerror set to GE_BADPATH    invalid path - directory not found
  27.  *    globerror set to GE_AMBIGUOUS    ambiguous directory spec
  28.  *    globerror set to GE_MAXFILES    too many files found (MAXFILES)
  29.  *    globerror set to GE_NOMEM    out of memory
  30.  *
  31.  *    else it returns a pointer to a NULL terminated array of pointers
  32.  *    to 'strings':
  33.  *
  34.  *    +-[ MAIN.C ]----------------------------------------------------+
  35.  *    |                                |
  36.  *    | #include "glob.h"                            |
  37.  *    | main() {                            |
  38.  *    |     char **glob();                        |
  39.  *    |     char **names;                        |
  40.  *    |     names = glob("/u??/p*");                |
  41.  *    |     if (names)                        |
  42.  *    |         printf("the first name returned is %s\n",names[0]);    |
  43.  *    |     else                            |
  44.  *    |         printf("glob() error number %d\n",globerror);    |
  45.  *    |    recover(names);                        |
  46.  *    | }                                |
  47.  *    |                                |
  48.  *    +---------------------------------------------------------------+
  49.  *
  50.  *    ALL strings and the array *names[] are made with calls to
  51.  *    malloc().  Thus, be sure to free() *names[x] AND names when done!
  52.  *
  53.  *    +-[sample routines]---------------------------------------------+
  54.  *    |                                |
  55.  *    |    (* free() all the space used up by **names; *)        |
  56.  *    | recover(names)                        |
  57.  *    | char **names;                            |
  58.  *    | {                                |
  59.  *    |     int i = 0;                        |
  60.  *    |                                |
  61.  *    |     while (names[i] != (char *)0) {                |
  62.  *    |     free(names[i]);                        |
  63.  *    |     i++;                            |
  64.  *    |     }                                |
  65.  *    |     free(names);                        |
  66.  *    | }                                |
  67.  *    |                                 |
  68.  *    |                                 |
  69.  *    |    (* print out all the filenames returned by glob() *)    |
  70.  *    | print(names)                            |
  71.  *    | char **names;                            |
  72.  *    | {                                |
  73.  *    |     int i;                            |
  74.  *    |     i = 0;                            |
  75.  *    |     while (names[i] != (char *)0) {                |
  76.  *    |     printf("%s\n",names[i]);                |
  77.  *    |     i++;                            |
  78.  *    |     }                                |
  79.  *    | }                                |
  80.  *    +---------------------------------------------------------------+
  81.  *
  82.  *    Compile as follows:    (Structures MUST be packed in order for 
  83.  *                 the program to interface correctly with DOS)
  84.  *        cl -c -Zp glob.c    ** Microsoft C v3 or 4 **
  85.  *
  86.  *    Using the example given above, compile and link main program:
  87.  *        cl main.c glob
  88.  *
  89.  *    Written December, 1985 by John Plocher with MicroSoft C 3.0
  90.  *    Change log:
  91.  *
  92.  *    version    date        who    comments
  93.  *    ------- ----        ---    --------
  94.  *    1.0    10-Dec-85    jmp    Orig. coding
  95.  *    1.1    16-Jan-86    jmp    added globerror
  96.  *    1.2    05-Feb-86    jmp    added comments and doccumentation
  97.  *
  98.  */
  99.  
  100. static char *scssid = "5-Feb-86 (Plocher) @(#)glob.c    1.2";
  101. static char *copyright =
  102.     "Copyright 1985, 1986 John Plocher.  Non-commercial use approved";
  103.  
  104. #include    <stdio.h>
  105. #include    <dos.h>
  106. #include    <memory.h>
  107. #include    <direct.h>
  108. #include    <string.h>
  109. #include    "glob.h"
  110.  
  111.  
  112. /* Change the following if you might have more than this many    */
  113. /* files returned by glob()                                      */
  114.  
  115. #define MAXFILES    256    /* max files returned by glob() */
  116.  
  117.  
  118. static char *list[MAXFILES];    /* MAXFILES entries per sub-dir */
  119.  
  120.  
  121. extern char *strlwr();
  122. extern int getdir();
  123. extern char *pos();
  124.  
  125. int globerror;            /* PUBLIC - global error number */
  126.  
  127. /*
  128.  *    glob()
  129.  */
  130. char **
  131. glob(proposed)
  132. char *proposed;
  133. {
  134.     int i,j,k,needdir,n;
  135.     char *end, filename[128], newpath[127], tmppath[127];
  136.     char *f, *p1, *p2;
  137.     char **names;
  138.     
  139.     strcpy(filename, proposed);
  140.     
  141.     /* add on current directory if first char is not '/' or '\' */
  142.     if (*filename != '/' && *filename != '\\') {
  143.     getcwd(tmppath,128);
  144.     p2 = strchr(tmppath,'\0');
  145.     p2--;
  146.     if (*p2 != '/' && *p2 != '\\')
  147.         strcat(tmppath,"/");
  148.     strcat(tmppath,filename);
  149.     strcpy(filename, tmppath);
  150.     }
  151.     for (i=strlen(filename); i; i--)
  152.     if (filename[i] == '\\')
  153.         filename[i] = '/';
  154.     i = 0; j = 0;
  155.     p2 = strchr(filename,'\0');
  156.     p2--;
  157.     if (*p2 == '.')
  158.     strcat(filename,"/");
  159.     while ((p1 = pos("/./",filename)) != NULL) {
  160.     memccpy(p1+1, p1+3, '\0',strlen(p1));
  161.     }
  162.     while ((p1 = pos("../",filename)) != NULL) {
  163.     char tmp;
  164.     tmp = *(p1 - 1);
  165.     *(p1 - 1) = '\0';
  166.     p2 = strrchr(filename,'/');
  167.     if (p2 == NULL) {
  168.         globerror = GE_BADFILE;
  169.         return(NULL);
  170.     }
  171.     *(p1 - 1) = tmp;
  172.     memccpy(p2+1, p1+3, '\0',strlen(p1));
  173.     }
  174.     p2 = strchr(filename,'\0');
  175.     p2--;
  176.     if (*p2 == '/')
  177.     *p2 = '\0';
  178. loop:
  179.     while (filename[i]  != 0 &&        /* copy till hit a wildcard */
  180.        filename[i]  != '*' &&
  181.        filename[i]  != '?') {
  182.     tmppath[j++] = filename[i++];
  183.     }
  184.     if (filename[i] != 0)    /* wildcard found */
  185.     while (filename[i]  != 0 &&
  186.            filename[i]  != '/')
  187.         tmppath[j++] = filename[i++];
  188.     if (filename[i] != 0)    /* need directory here */
  189.     needdir = 1;
  190.     else            /* any file will do */
  191.     needdir = 0;
  192.     tmppath[j] = 0;
  193.     strcpy(newpath,tmppath);
  194.     end = strrchr(newpath,'/');
  195.     if  (end != NULL)
  196.       *end = '\0';
  197.       
  198.     n = getdir(tmppath,needdir);
  199.  
  200.     if (n == -2) {    /* out of dynamic memory */
  201.     globerror = GE_NOMEM;
  202.     return(NULL);
  203.     }
  204.     if (n == -1) {    /* exceeded filecount */
  205.     globerror = GE_MAXFILES;
  206.     return(NULL);
  207.     }
  208.     if (n == 0) { /* file not found */
  209.     globerror = GE_BADFILE;
  210.     return(NULL);
  211.     }
  212.     if (needdir && n != 1) { /* ambiguous directory reference */
  213.     for (i = 0; i < n; i++)        /* This is an arbitrary limit */
  214.         free(list[i]);        /* one could follow all paths */
  215.     globerror = GE_AMBIGUOUS;    /* and not just the first...  */
  216.     return(NULL);
  217.     }
  218.     if (needdir) {
  219.     strcpy(tmppath,newpath);
  220.     strcat(tmppath,"/");
  221.     strcat(tmppath,list[0]);
  222.     free(list[0]);
  223.     j = strlen(tmppath);
  224.     goto loop;
  225.     }
  226.  
  227.     names = (char **)malloc((n+1) * sizeof(char *));
  228.     for (i = 0; i < n; i++) {
  229.     sprintf(tmppath,"%s/%s", newpath, list[i]);
  230.     names[i] = strdup(tmppath);
  231.     free(list[i]);
  232.     }
  233.     names[n] = (char *)0;
  234.  
  235.     return(names);
  236. }
  237.  
  238.  
  239. /*
  240.  *    pos(target, src)
  241.  *            find target string within src
  242.  */
  243. static char *pos(s1,s2)
  244. char *s1, *s2;
  245. {
  246.     int temploc, dist;
  247.     char *tp;
  248.  
  249.     if (*s1) {
  250.     for (;;) {
  251.         tp = strchr(s2, *s1);
  252.         if (tp == NULL) {        /* couldn't even find first char */
  253.         return(NULL);
  254.         }
  255.         if (!strncmp(s1,tp,strlen(s1)))    /* match */ {
  256.         return(tp);
  257.         }
  258.         s2 = tp + 1;
  259.     }
  260.     }
  261. }
  262.  
  263.  
  264. /*
  265.  *    File attributes
  266.  */
  267.  
  268. #define AT_RO        0x01    /* Read Only */
  269. #define AT_HIDDEN    0x02    /* hidden file */
  270. #define    AT_SYSTEM    0x04    /* System file */
  271. #define AT_LABEL    0x08    /* volume label */
  272. #define AT_DIR        0x10    /* sub directory */
  273. #define AT_ARCH        0x20    /* archive bit */
  274.  
  275. static struct REGS rregs;
  276. static struct SREGS sregs;
  277.  
  278.  
  279. static struct DMA {            /* For reading directory entry    */
  280.     char res[21];
  281.     char attr;
  282.     unsigned sec : 5, min : 6, hour : 5;
  283.     unsigned day : 5, mon : 4, year : 7;
  284.     long size;
  285.     char name[13];
  286. } dma;
  287.  
  288. /*
  289.  *    getdir        gather all the files found in this directory
  290.  */
  291. static int 
  292. getdir(path, needdir)    /* return number of 'files' found in this path */
  293. char  *path;        /* this is where to look */
  294. int needdir;        /* 1 = we want ONLY AT_DIR type entries */
  295.             /* 0 = we will take EVERYTHING */
  296. {
  297.     int i, j, n;
  298.     char *entry;
  299.  
  300.     bdos(0x1a, &dma,0);
  301.  
  302.     n = 0;
  303.     rregs.h.ah = 0x4e;
  304.     rregs.x.cx = AT_RO | AT_HIDDEN | AT_SYSTEM | AT_DIR;
  305.     rregs.x.dx = (unsigned int) path;
  306.     j = intdos(&rregs, &rregs);        /* Search for first    */
  307.     while(j == 0) {
  308.     strlwr(dma.name);
  309.     if (needdir && (dma.attr & AT_DIR != AT_DIR)){ /* skip this entry */
  310.         rregs.h.ah = 0x4f;        /* wes needs dirs, and this ain't one */
  311.         j = intdos(&rregs, &rregs);/* Search for next    */
  312.         continue;
  313.     }
  314.     entry = strdup(dma.name);
  315.     if (entry == NULL) {        /* out of memory */
  316.         for (i = 0; i < n; i++)
  317.         free(list[i]);
  318.         return (-2);
  319.     }
  320.     if (n >= MAXFILES)        /* too many files found */
  321.         return(-1);
  322.     for (i = n++; i > 0; --i) {    /* alphabetize */
  323.         if (strcmp(entry, list[i - 1]) >= 0)
  324.         break;
  325.         list[i] = list[i - 1];
  326.     }
  327.     list[i] = entry;
  328.     rregs.h.ah = 0x4f;
  329.     j = intdos(&rregs, &rregs);        /* Search for next    */
  330.     }
  331.     return(n);
  332. }
  333.  
  334.