Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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