home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / libc / posix / glob / glob.c next >
Encoding:
C/C++ Source or Header  |  1996-09-11  |  9.5 KB  |  410 lines

  1. /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
  2. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  3. #include <libc/stubs.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <ctype.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <fnmatch.h>
  11. #include <dir.h>
  12. #include <glob.h>
  13. #include <crt0.h>
  14.  
  15. typedef struct Save {
  16.   struct Save *prev;
  17.   char *entry;
  18. } Save;
  19.  
  20. static Save *save_list;
  21. static int save_count;
  22. static int flags;
  23. static int (*errfunc)(const char *epath, int eerno);
  24. static char *pathbuf;
  25. static int wildcard_nesting;
  26. static char use_lfn;
  27. static char preserve_case;
  28. static char slash;
  29.  
  30. static int glob2(const char *pattern, char *epathbuf, int lower, int caseless);
  31. static int glob_dirs(const char *rest, char *epathbuf, int first, int lower, int caseless);
  32. static int add(const char *path);
  33. static int str_compare(const void *va, const void *vb);
  34.  
  35. /* `tolower' might depend on the locale.  We don't want to.  */
  36. static int
  37. msdos_tolower_fname (int c)
  38. {
  39.   return (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;
  40. }
  41.  
  42. static int
  43. add(const char *path)
  44. {
  45.   Save *sp;
  46.   for (sp=save_list; sp; sp=sp->prev)
  47.     if (stricmp(sp->entry, path) == 0)
  48.       return 0;
  49.   sp = (Save *)malloc(sizeof(Save));
  50.   if (sp == 0)
  51.     return 1;
  52.   sp->entry = (char *)malloc(strlen(path)+1);
  53.   if (sp->entry == 0)
  54.   {
  55.     free(sp);
  56.     return 1;
  57.   }
  58. /*  printf("add: `%s'\n", path); */
  59.   strcpy(sp->entry, path);
  60.   sp->prev = save_list;
  61.   save_list = sp;
  62.   save_count++;
  63.   return 0;
  64. }
  65.  
  66. static int
  67. glob_dirs(const char *rest, char *epathbuf, int first, /* rest is ptr to null or ptr after slash, bp after slash */
  68.       int lower, int caseless)
  69. {
  70.   struct ffblk ff;
  71.   int done;
  72.  
  73. /*  printf("glob_dirs[%d]: rest=`%s' %c epathbuf=`%s' %c pathbuf=`%s'\n",
  74.      wildcard_nesting, rest, *rest, epathbuf, *epathbuf, pathbuf); */
  75.  
  76.   if (first)
  77.   {
  78.     if (*rest)
  79.     {
  80.       if (glob2(rest, epathbuf, lower, caseless) == GLOB_NOSPACE)
  81.     return GLOB_NOSPACE;
  82.     }
  83.     else
  84.     {
  85.       char sl = epathbuf[-1];
  86.       *epathbuf = 0;
  87. /*      printf("end, checking `%s'\n", pathbuf); */
  88.       if (epathbuf == pathbuf)
  89.       {
  90.     epathbuf[0] = '.';
  91.     epathbuf[1] = 0;
  92.       }
  93.       else
  94.     epathbuf[-1] = 0;
  95.       if (__file_exists(pathbuf))
  96.     if (add(pathbuf))
  97.       return GLOB_NOSPACE;
  98.       epathbuf[-1] = sl;
  99.     }
  100.   }
  101.  
  102.   strcpy(epathbuf, "*.*");
  103.   done = findfirst(pathbuf, &ff, FA_DIREC);
  104.   while (!done)
  105.   {
  106.     char short_name[13];
  107.  
  108.     if ((ff.ff_name[0] != '.') && (ff.ff_attrib & FA_DIREC))
  109.     {
  110.       int i;
  111.       char *tp;
  112.       /* Long directory names are never lower-cased!  */
  113.       if (lower
  114.       && !strcmp(ff.ff_name, _lfn_gen_short_fname(ff.ff_name, short_name)))
  115.     for (i=0; ff.ff_name[i] && i<13; i++)
  116.       ff.ff_name[i] = msdos_tolower_fname(ff.ff_name[i]);
  117.  
  118. /*    printf("found `%s' `%s'\n", pathbuf, ff.ff_name); */
  119.  
  120.       strcpy(epathbuf, ff.ff_name);
  121.       tp = epathbuf + strlen(epathbuf);
  122.       *tp++ = slash;
  123.       *tp = 0;
  124.  
  125.       wildcard_nesting++;
  126.       if (*rest)
  127.       {
  128.     if (glob2(rest, tp, lower, caseless) == GLOB_NOSPACE)
  129.       return GLOB_NOSPACE;
  130.       }
  131.       else
  132.       {
  133.     if (!(flags & GLOB_MARK))
  134.       tp[-1] = 0;
  135.     if (add(pathbuf))
  136.       return GLOB_NOSPACE;
  137.     tp[-1] = slash;
  138.       }
  139.       *tp = 0;
  140.       if (glob_dirs(rest, tp, 0, lower, caseless) == GLOB_NOSPACE)
  141.     return GLOB_NOSPACE;
  142.       wildcard_nesting--;
  143.     }
  144.     done = findnext(&ff);
  145.   }
  146.   return 0;
  147. }
  148.  
  149. static int
  150. glob2(const char *pattern, char *epathbuf,  /* both point *after* the slash */
  151.       int lower, int caseless)
  152. {
  153.   const char *pp, *pslash;
  154.   char *bp;
  155.   struct ffblk ff;
  156.   char *my_pattern;
  157.   int done;
  158.  
  159.   if (strcmp(pattern, "...") == 0)
  160.   {
  161.     return glob_dirs(pattern+3, epathbuf, 1, lower, caseless);
  162.   }
  163.   if (strncmp(pattern, "...", 3) == 0 && (pattern[3] == '\\' || pattern[3] == '/'))
  164.   {
  165.     slash = pattern[3];
  166.     return glob_dirs(pattern+4, epathbuf, 1, lower, caseless);
  167.   }
  168.  
  169.   *epathbuf = 0;
  170.   /* copy as many non-wildcard segments as possible */
  171.   pp = pattern;
  172.   bp = epathbuf;
  173.   pslash = bp-1;
  174.   while (1)
  175.   {
  176.     if (*pp == ':' || *pp == '\\' || *pp == '/')
  177.     {
  178.       pslash = bp;
  179.       if (strcmp(pp+1, "...") == 0
  180.       || (strncmp(pp+1, "...", 3) == 0 && (pp[4] == '/' || pp[4] == '\\')))
  181.       {
  182.     if (*pp != ':')
  183.       slash = *pp;
  184. /*    printf("glob2: dots at `%s'\n", pp); */
  185.     *bp++ = *pp++;
  186.     break;
  187.       }
  188.     }
  189.  
  190.     else if (*pp == '*' || *pp == '?' || *pp == '[')
  191.     {
  192.       if (pslash > pathbuf)
  193.     strncpy(epathbuf, pattern, pslash - pathbuf);
  194.       pp = pattern + (pslash - epathbuf) + 1;
  195.       bp = epathbuf + (pslash - epathbuf) + 1;
  196.       break;
  197.     }
  198.  
  199.     else if (*pp == 0)
  200.     {
  201.       break;
  202.     }
  203.  
  204.     /* Upper-case or mixed-case patterns force case-sensitive
  205.        matches in `fnmatch' for LFN filesystems.  They also
  206.        suppress downcasing 8+3 filenames (on all filesystems).  */
  207.     else if (!preserve_case)
  208.     {
  209.       if (*pp >= 'A' && *pp <= 'Z')
  210.       {
  211.     if (use_lfn)
  212.       caseless = 0;
  213.     lower = 0;
  214.       }
  215.       else if (*pp >= 'a' && *pp <= 'z')
  216.     lower = 1;
  217.     }
  218.  
  219.     *bp++ = *pp++;
  220.   }
  221.   *bp = 0;
  222.  
  223.   if (*pp == 0) /* end of pattern? */
  224.   {
  225.     if (__file_exists(pathbuf))
  226.     {
  227.       if (flags & GLOB_MARK)
  228.       {
  229.         struct ffblk _ff;
  230.         findfirst(pathbuf, &_ff, FA_RDONLY|FA_SYSTEM|FA_DIREC|FA_ARCH);
  231.         if (_ff.ff_attrib & FA_DIREC)
  232.         {
  233.           char *_pathbuf = pathbuf + strlen(pathbuf);
  234.           *_pathbuf++ = '/';
  235.           *_pathbuf = 0;
  236.         }
  237.       }
  238.       if (add(pathbuf))
  239.     return GLOB_NOSPACE;
  240.     }
  241.     return 0;
  242.   }
  243. /*  printf("glob2: initial segment is `%s'\n", pathbuf); */
  244.   if (wildcard_nesting)
  245.   {
  246.     char s = bp[-1];
  247.     bp[-1] = 0;
  248.     if (!__file_exists(pathbuf))
  249.       return 0;
  250.     bp[-1] = s;
  251.   }
  252.  
  253.   for (pslash = pp; *pslash && *pslash != '\\' && *pslash != '/';  pslash++)
  254.     if (!preserve_case)
  255.     {
  256.       if (*pslash >= 'A' && *pslash <= 'Z')
  257.       {
  258.     if (use_lfn)
  259.       caseless = 0;
  260.     lower = 0;
  261.       }
  262.       else if (*pslash >= 'a' && *pslash <= 'z')
  263.     lower = 1;
  264.     }
  265.  
  266.   if (*pslash)
  267.     slash = *pslash;
  268.   my_pattern = (char *)alloca(pslash - pp + 1);
  269.   if (my_pattern == 0)
  270.     return GLOB_NOSPACE;
  271.   strncpy(my_pattern, pp, pslash - pp);
  272.   my_pattern[pslash-pp] = 0;
  273.  
  274. /*  printf("glob2: `%s' `%s'\n", pathbuf, my_pattern); */
  275.  
  276.   if (strcmp(my_pattern, "...") == 0)
  277.   {
  278.     if (glob_dirs(*pslash ? pslash+1 : pslash, bp, 1, lower, caseless) == GLOB_NOSPACE)
  279.       return GLOB_NOSPACE;
  280.     return 0;
  281.   }
  282.  
  283.   strcpy(bp, "*.*");
  284.  
  285.   done = findfirst(pathbuf, &ff, FA_RDONLY|FA_SYSTEM|FA_DIREC|FA_ARCH);
  286.   while (!done)
  287.   {
  288.     int i;
  289.     char fshort[13];
  290.     if (ff.ff_name[0] != '.')
  291.     {
  292.       /* Long filenames are never lower-cased!  */
  293.       if (lower
  294.       && !strcmp(ff.ff_name, _lfn_gen_short_fname(ff.ff_name, fshort)))
  295.     for (i=0; ff.ff_name[i] && i<13; i++)
  296.       ff.ff_name[i] = msdos_tolower_fname(ff.ff_name[i]);
  297.  
  298.       if (fnmatch(my_pattern, ff.ff_name,
  299.           FNM_NOESCAPE|FNM_PATHNAME|(caseless ? FNM_NOCASE : 0)) == 0)
  300.       {
  301.     strcpy(bp, ff.ff_name);
  302.     if (*pslash)
  303.     {
  304.       char *tp = bp + strlen(bp);
  305.       *tp++ = *pslash;
  306.       *tp = 0;
  307. /*      printf("nest: `%s' `%s'\n", pslash+1, pathbuf); */
  308.       wildcard_nesting++;
  309.       if (glob2(pslash+1, tp, lower, caseless) == GLOB_NOSPACE)
  310.         return GLOB_NOSPACE;
  311.       wildcard_nesting--;
  312.     }
  313.     else
  314.     {
  315. /*      printf("ffmatch: `%s' matching `%s', add `%s'\n",
  316.          ff.ff_name, my_pattern, pathbuf); */
  317.       if (ff.ff_attrib & FA_DIREC && (flags & GLOB_MARK))
  318.       {
  319.         bp[strlen(bp)+1] = 0;
  320.         bp[strlen(bp)] = slash;
  321.       }
  322.       if (add(pathbuf))
  323.         return GLOB_NOSPACE;
  324.     }
  325.       }
  326.     }
  327.     done = findnext(&ff);
  328.   } 
  329.  
  330.   return 0;
  331. }
  332.  
  333. static int
  334. str_compare(const void *va, const void *vb)
  335. {
  336.   return strcmp(*(char * const *)va, *(char * const *)vb);
  337. }
  338.  
  339. int
  340. glob(const char *_pattern, int _flags, int (*_errfunc)(const char *_epath, int _eerrno), glob_t *_pglob)
  341. {
  342.   char path_buffer[2000];
  343.   int l_ofs, l_ptr;
  344.  
  345.   pathbuf = path_buffer+1;
  346.   flags = _flags;
  347.   errfunc = _errfunc;
  348.   wildcard_nesting = 0;
  349.   save_count = 0;
  350.   save_list = 0;
  351.   use_lfn = _USE_LFN;
  352.   preserve_case = _preserve_fncase();
  353.   slash = '/';
  354.  
  355.   if (glob2(_pattern, pathbuf, preserve_case ? 0 : 1, preserve_case ? 0 : 1) == GLOB_NOSPACE)
  356.     {
  357.       return GLOB_NOSPACE;
  358.     }
  359.  
  360.   if (save_count == 0)
  361.   {
  362.     if (flags & GLOB_NOCHECK)
  363.     {
  364.       if (add(_pattern))
  365.     return GLOB_NOSPACE;
  366.     }
  367.     else
  368.       return GLOB_NOMATCH;
  369.   }
  370.  
  371.   if (flags & GLOB_DOOFFS)
  372.     l_ofs = _pglob->gl_offs;
  373.   else
  374.     l_ofs = 0;
  375.  
  376.   if (flags & GLOB_APPEND)
  377.   {
  378.     _pglob->gl_pathv = (char **)realloc(_pglob->gl_pathv, (l_ofs + _pglob->gl_pathc + save_count + 1) * sizeof(char *));
  379.     if (_pglob->gl_pathv == 0)
  380.       return GLOB_NOSPACE;
  381.     l_ptr = l_ofs + _pglob->gl_pathc;
  382.   }
  383.   else
  384.   {
  385.     _pglob->gl_pathv = (char* *)malloc((l_ofs + save_count + 1) * sizeof(char *));
  386.     if (_pglob->gl_pathv == 0)
  387.       return GLOB_NOSPACE;
  388.     l_ptr = l_ofs;
  389.     if (l_ofs)
  390.       memset(_pglob->gl_pathv, 0, l_ofs * sizeof(char *));
  391.   }
  392.  
  393.   l_ptr += save_count;
  394.   _pglob->gl_pathv[l_ptr] = 0;
  395.   while (save_list)
  396.   {
  397.     Save *s = save_list;
  398.     l_ptr --;
  399.     _pglob->gl_pathv[l_ptr] = save_list->entry;
  400.     save_list = save_list->prev;
  401.     free(s);
  402.   }
  403.   if (!(flags & GLOB_NOSORT))
  404.     qsort(_pglob->gl_pathv + l_ptr, save_count, sizeof(char *), str_compare);
  405.  
  406.   _pglob->gl_pathc = l_ptr + save_count;
  407.  
  408.   return 0;
  409. }
  410.