home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / c / glob.arc / GLOB.C
C/C++ Source or Header  |  1988-02-10  |  9KB  |  210 lines

  1. /* ------------------------------------------------------------ *
  2.  *  This is 'glob ()' version 1.04 (11/27/87) by Bob Kamins.    *
  3.  * ------------------------------------------------------------ *
  4.  *  int glob (argc, argv, attr)                                 *
  5.  *  int *argc;        <- pointer to argument count              *
  6.  *  char **argv [];   <- pointer to argument array pointer      *
  7.  *  char attribute;   <- file search attribute                  *
  8.  *  ----------------------------------------------------------- *
  9.  *  'glob ()' will expand ambiguous file name arguments (using  *
  10.  *  wildcards) into unambiguous file names that can be used by  *
  11.  *  an application program.  The expanded arguments and count   *
  12.  *  replace the old 'argc' and 'argv', so that an existing      *
  13.  *  application program will require minimal changes.           *
  14.  *                                                              *
  15.  *  'glob ()' uses ms-dos functions 0x4e and 0x4f ('findfirst'  *
  16.  *  and 'findnext') to find each expanded name, which is then   *
  17.  *  installed in a newly allocated memory space.  When all of   *
  18.  *  the names have been found, a new 'argv' array is allocated  *
  19.  *  and the old 'argv' and 'argc' are overwritten.  The memory  *
  20.  *  used by the old 'argv' array and its associated elements    *
  21.  *  is lost (except for 'argv [0]'.)                            *
  22.  *                                                              *
  23.  *  I decided to sort all of the names except 'argv [0]' (with  *
  24.  *  'qsort ()') after the new 'argv' array is made.  This is    *
  25.  *  not entirely compatible with most Unix shells: they will    *
  26.  *  return the new arguments sorted within the original ufn's.  *
  27.  *  We can easily do that, but I'm not sure that there is any   *
  28.  *  tremendous advantage to it.                                 *
  29.  * ------------------------------------------------------------ *
  30.  *  Usage:                                                      *
  31.  *                                                              *
  32.  *    main (int argc, char *argv [])  /* usual invocation       *
  33.  *    {                                                         *
  34.  *      int i;                                                  *
  35.  *      glob (&argc, &argv, attr);    /* pass the addresses     *
  36.  *      for (i = 0; i < argc; i++)    /* just like before       *
  37.  *      {                                                       *
  38.  *        ...blah - blah - blah                                 *
  39.  * ------------------------------------------------------------ *
  40.  *  'glob ()' returns a negative value if any error occurs and  *
  41.  *  zero otherwise.                                             *
  42.  * ============================================================ *
  43.  *  11/28/87 (1.06): If an argument is enclosed in single       *
  44.  *                   quotes, it is considered not to be         *
  45.  *                   globbable.  The quotes should be           *
  46.  *                   removed and the argument should not        *
  47.  *                   be expanded (see 'expand ()'.)             *
  48.  * ------------------------------------------------------------ *
  49.  */
  50.  
  51. #include <stdio.h>
  52. #include <dir.h>
  53.  
  54. static char *first;  /* first element of expanded argument list */
  55. static int newc;     /* new argc */
  56.  
  57. /* ------------------------------------------------------------- *
  58.  *  'insert ()' puts a (possibly) expanded file name in the next *
  59.  *  position in the list and updates the count in 'newc'.        *
  60.  * ------------------------------------------------------------- *
  61.  *  The function will return zero if no error occurred or -1 if  *
  62.  *  the 'sbrk ()' fails.                                         *
  63.  * ------------------------------------------------------------- */
  64.  
  65. static int insert (char *newname)
  66. {
  67.   char *p;
  68.  
  69.   if (((int) (p = (char *) sbrk (strlen (newname) + 1))) == -1)
  70.     return (-2);      /* 'sbrk ()' failed  */
  71.   if (first == NULL)
  72.     first = p;
  73.   while ((*p++ = *newname++) != 0)  /* copy newname */
  74.     ;
  75.   newc++;             /* bump the argument counter */
  76.   return (0);         /* normal return */
  77. }
  78.  
  79. /* ------------------------------------------------------------- *
  80.  *  'fullname ()' returns a pointer to the drive/path/file name  *
  81.  *  if one was used in the original argument.  Note that the     *
  82.  *  abbreviation '..' is not translated to a to a full drive/-   *
  83.  *  path/name specification (although this could be done) but    *
  84.  *  returned as '..', which is sufficient to perform most types  *
  85.  *  of operations (open/read/write/close) on the file.           *
  86.  * ------------------------------------------------------------- */
  87.  
  88. static char *fullname (char *argv, char *name)
  89. {
  90.   int res;
  91.   char path [MAXDIR];              /* holds the path temporarily */
  92.   static char fullpath [MAXPATH];  /* holds the drive at first */
  93.  
  94.   res = fnsplit (argv, &fullpath, &path, NULL, NULL);
  95.   if ((res & DIRECTORY) > 0)       /* add path name */
  96.     strcat (fullpath, path);
  97.   strcat (fullpath, name);         /* add file name */
  98.   strupr (fullpath);               /* everything in upper case */
  99.   return (fullpath);
  100. }
  101.  
  102. /* ------------------------------------------------------------- *
  103.  *  'expand ()' checks an argument for wildcards, expands it if  *
  104.  *  neccessary, and saves the expansion (or original, if no      *
  105.  *  wildcards were found) in a list.                             *
  106.  * ------------------------------------------------------------- *
  107.  *  If errors are detected (during 'insert ()'), 'expand ()' is  *
  108.  *  terminated and the error is returned to the caller.          *
  109.  * ------------------------------------------------------------- */
  110.  
  111. static int expand (char *argv, unsigned char attr)
  112. {
  113.   int ret,              /* stores 'insert ()' return code */
  114.       done;             /* controls 'findnext ()' loop */
  115.   struct ffblk ffblk;   /* used by 'findfirst ()' & 'findnext ()' */
  116.  
  117.   if ((strpbrk (argv, "*?")) == NULL)
  118.   {                             /* no wildcards in this argument */
  119.     if ((ret = insert (argv)) < 0)
  120.       return (ret);             /* 'insert ()' returned error */
  121.   }
  122.  
  123.   else            /* this argument has wildcards -- expand it... */
  124.   {
  125.     done = findfirst (argv, &ffblk, attr);
  126.     while (!done)
  127.     {
  128.       if ((ret = insert (fullname (argv, ffblk.ff_name))) < 0)
  129.         return (ret);           /* function returned error */
  130.       done = findnext (&ffblk);
  131.     }
  132.   }
  133.   return (0);                   /* normal return */
  134. }
  135.  
  136. /* ------------------------------------------------------------- *
  137.  *  'makearray ()' traverses the argument list and creates the   *
  138.  *  new 'argv' pointer array.  Zero is returned if no error or   *
  139.  *  -2 if a memory allocation error occurs.                      *
  140.  * ------------------------------------------------------------- */
  141.  
  142. static int makearray ()
  143. {
  144.   int i;       /* loop index counter */
  145.   char **p;    /* pointer to array element */
  146.  
  147.   p = (char **) sbrk (newc * sizeof (char *));
  148.   if ((int) p == -1)  /* 'sbrk ()' failed */
  149.     return (-3);
  150.  
  151.   for (i = 0; i < newc; i++) /* for each new argument */
  152.   {
  153.     *p++ = first++;  /* set array element to address of string */
  154.     while (*first++ != 0)  /* look for end of string */
  155.       ;
  156.   }
  157.   return (0);
  158. }
  159.  
  160. /* ---------------------------------------------------------- *
  161.  *  'fcmp ()' is the comparison function for 'qsort' below.   *
  162.  * ---------------------------------------------------------- */
  163.  
  164. static int fcmp (char **a, char **b)
  165. {
  166.   return (strcmp (*a, *b));
  167. }
  168.  
  169. /* ---------------------------------------------------------- *
  170.  *  The main 'glob ()' function expands wildcarded arguments  *
  171.  *  passed in 'argv' and plugs new values into 'argv' and     *
  172.  *  'argc'.  Zero is returned if no errors occur, or else a   *
  173.  *  negative number indicating the type of error is returned: *
  174.  *         -1: 'sbrk ()' in 'glob ()' failed.                 *
  175.  *         -2: 'sbrk ()' in 'insert ()' failed.               *
  176.  *         -3: 'sbrk ()' in 'makearray ()' failed.            *
  177.  * ---------------------------------------------------------- */
  178.  
  179. int glob (int *argc, char **argv [], unsigned char attr)
  180. {
  181.   int i,
  182.       ret;   /* holds function return values */
  183.   char **p;  /* pointer to 'argv [0]' */
  184.  
  185.   /*
  186.    *  save each argument or expansion in a list:
  187.    */
  188.   newc = 0;
  189.   first = NULL;
  190.   for (i = 1; i < *argc; i++)
  191.   {
  192.     if ((ret = expand ((*argv) [i], attr)) < 0)
  193.       return (ret);   /* 'expand ()' returned error */
  194.   }
  195.  
  196.   /*
  197.    *  save old 'argv [0]' (program name) in new 'argv' array:
  198.    */
  199.   p = (char **) sbrk (sizeof (char *));
  200.   if ((int) p == -1)
  201.     return (-1);     /* 'sbrk ()' failed */
  202.   *p = *argv [0];    /* save address of old 'argv [0]' */
  203.   *argv = p;         /* point to second element in new array */
  204.   *argc = newc + 1;
  205.   if ((ret = makearray ()) < 0)
  206.     return (ret);
  207.   qsort (&((*argv) [1]), newc, sizeof (char **), fcmp);
  208.   return (0);
  209. }
  210.