Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /** \file globbing.c */
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <ctype.h>
  7. #include <assert.h>
  8.  
  9. #include "globbing.h"
  10.  
  11. /**
  12.  * Please see globbing.h for details.
  13.  *
  14.  * License: this code is public domain. I make no warranty that it is useful,
  15.  *  correct, harmless, or environmentally safe.
  16.  *
  17.  * This particular file may be used however you like, including copying it
  18.  *  verbatim into a closed-source project, exploiting it commercially, and
  19.  *  removing any trace of my name from the source (although I hope you won't
  20.  *  do that). I welcome enhancements and corrections to this file, but I do
  21.  *  not require you to send me patches if you make changes. This code has
  22.  *  NO WARRANTY.
  23.  *
  24.  * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
  25.  *  Please see the file LICENSE.txt in the source's root directory.
  26.  *
  27.  *  \author Ryan C. Gordon.
  28.  */
  29.  
  30.  
  31. static int matchesPattern(const char *fname, const char *wildcard,
  32.                           int caseSensitive)
  33. {
  34.     char x, y;
  35.     const char *fnameptr = fname;
  36.     const char *wildptr = wildcard;
  37.  
  38.     while ((*wildptr) && (*fnameptr))
  39.     {
  40.         y = *wildptr;
  41.         if (y == '*')
  42.         {
  43.             do
  44.             {
  45.                 wildptr++;  /* skip multiple '*' in a row... */
  46.             } while (*wildptr == '*');
  47.  
  48.             y = (caseSensitive) ? *wildptr : (char) tolower(*wildptr);
  49.  
  50.             while (1)
  51.             {
  52.                 x = (caseSensitive) ? *fnameptr : (char) tolower(*fnameptr);
  53.                 if ((!x) || (x == y))
  54.                     break;
  55.                 else
  56.                     fnameptr++;
  57.             } /* while */
  58.         } /* if */
  59.  
  60.         else if (y == '?')
  61.         {
  62.             wildptr++;
  63.             fnameptr++;
  64.         } /* else if */
  65.  
  66.         else
  67.         {
  68.             if (caseSensitive)
  69.                 x = *fnameptr;
  70.             else
  71.             {
  72.                 x = tolower(*fnameptr);
  73.                 y = tolower(y);
  74.             } /* if */
  75.  
  76.             wildptr++;
  77.             fnameptr++;
  78.  
  79.             if (x != y)
  80.                 return 0;
  81.         } /* else */
  82.     } /* while */
  83.  
  84.     while (*wildptr == '*')
  85.         wildptr++;
  86.  
  87.     return (*fnameptr == *wildptr);
  88. } /* matchesPattern */
  89.  
  90. typedef struct
  91. {
  92.     const PHYSFS_Allocator *allocator;
  93.     const char *wildcard;
  94.     int caseSensitive;
  95.     PHYSFS_EnumFilesCallback callback;
  96.     void *origData;
  97. } WildcardCallbackData;
  98.  
  99.  
  100. /*
  101.  * This callback sits between the enumerator and the enduser callback,
  102.  *  filtering out files that don't match the wildcard pattern.
  103.  */
  104. static void wildcardCallback(void *_d, const char *origdir, const char *fname)
  105. {
  106.     const WildcardCallbackData *data = (const WildcardCallbackData *) _d;
  107.     if (matchesPattern(fname, data->wildcard, data->caseSensitive))
  108.         data->callback(data->origData, origdir, fname);
  109. } /* wildcardCallback */
  110.  
  111.  
  112. void PHYSFSEXT_enumerateFilesCallbackWildcard(const char *dir,
  113.                                               const char *wildcard,
  114.                                               int caseSensitive,
  115.                                               PHYSFS_EnumFilesCallback c,
  116.                                               void *d)
  117. {
  118.     WildcardCallbackData data;
  119.     data.allocator = PHYSFS_getAllocator();
  120.     data.wildcard = wildcard;
  121.     data.caseSensitive = caseSensitive;
  122.     data.callback = c;
  123.     data.origData = d;
  124.     PHYSFS_enumerateFilesCallback(dir, wildcardCallback, &data);
  125. } /* PHYSFSEXT_enumerateFilesCallbackWildcard */
  126.  
  127.  
  128. void PHYSFSEXT_freeEnumeration(char **list)
  129. {
  130.     const PHYSFS_Allocator *allocator = PHYSFS_getAllocator();
  131.     int i;
  132.     if (list != NULL)
  133.     {
  134.         for (i = 0; list[i] != NULL; i++)
  135.             allocator->Free(list[i]);
  136.         allocator->Free(list);
  137.     } /* if */
  138. } /* PHYSFSEXT_freeEnumeration */
  139.  
  140.  
  141. char **PHYSFSEXT_enumerateFilesWildcard(const char *dir, const char *wildcard,
  142.                                         int caseSensitive)
  143. {
  144.     const PHYSFS_Allocator *allocator = PHYSFS_getAllocator();
  145.     char **list = PHYSFS_enumerateFiles(dir);
  146.     char **retval = NULL;
  147.     int totalmatches = 0;
  148.     int matches = 0;
  149.     char **i;
  150.  
  151.     for (i = list; *i != NULL; i++)
  152.     {
  153.         #if 0
  154.         printf("matchesPattern: '%s' vs '%s' (%s) ... %s\n", *i, wildcard,
  155.                caseSensitive ? "case" : "nocase",
  156.                matchesPattern(*i, wildcard, caseSensitive) ? "true" : "false");
  157.         #endif
  158.         if (matchesPattern(*i, wildcard, caseSensitive))
  159.             totalmatches++;
  160.     } /* for */
  161.  
  162.     retval = (char **) allocator->Malloc(sizeof (char *) * (totalmatches+1));
  163.     if (retval != NULL)
  164.     {
  165.         for (i = list; ((matches < totalmatches) && (*i != NULL)); i++)
  166.         {
  167.             if (matchesPattern(*i, wildcard, caseSensitive))
  168.             {
  169.                 retval[matches] = (char *) allocator->Malloc(strlen(*i) + 1);
  170.                 if (retval[matches] == NULL)
  171.                 {
  172.                     while (matches--)
  173.                         allocator->Free(retval[matches]);
  174.                     allocator->Free(retval);
  175.                     retval = NULL;
  176.                     break;
  177.                 } /* if */
  178.                 strcpy(retval[matches], *i);
  179.                 matches++;
  180.             } /* if */
  181.         } /* for */
  182.  
  183.         if (retval != NULL)
  184.         {
  185.             assert(totalmatches == matches);
  186.             retval[matches] = NULL;
  187.         } /* if */
  188.     } /* if */
  189.  
  190.     PHYSFS_freeList(list);
  191.     return retval;
  192. } /* PHYSFSEXT_enumerateFilesWildcard */
  193.  
  194.  
  195. #ifdef TEST_PHYSFSEXT_ENUMERATEFILESWILDCARD
  196. int main(int argc, char **argv)
  197. {
  198.     int rc;
  199.     char **flist;
  200.     char **i;
  201.  
  202.     if (argc != 3)
  203.     {
  204.         printf("USAGE: %s <pattern> <caseSen>\n"
  205.                "   where <caseSen> is 1 or 0.\n", argv[0]);
  206.         return 1;
  207.     } /* if */
  208.  
  209.     if (!PHYSFS_init(argv[0]))
  210.     {
  211.         fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getLastError());
  212.         return 1;
  213.     } /* if */
  214.  
  215.     if (!PHYSFS_addToSearchPath(".", 1))
  216.     {
  217.         fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getLastError());
  218.         PHYSFS_deinit();
  219.         return 1;
  220.     } /* if */
  221.  
  222.     flist = PHYSFSEXT_enumerateFilesWildcard("/", argv[1], atoi(argv[2]));
  223.     rc = 0;
  224.     for (i = flist; *i; i++)
  225.     {
  226.         printf("%s\n", *i);
  227.         rc++;
  228.     } /* for */
  229.     printf("\n  total %d files.\n\n", rc);
  230.  
  231.     PHYSFSEXT_freeEnumeration(flist);
  232.     PHYSFS_deinit();
  233.  
  234.     return 0;
  235. } /* main */
  236. #endif
  237.  
  238. /* end of globbing.c ... */
  239.  
  240.