globbing.c 6.4 KB

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