/src/unixem/flx_glob.cpp

http://github.com/felix-lang/felix · C++ · 373 lines · 302 code · 58 blank · 13 comment · 83 complexity · 7a0e76ca130fe81eb6e8ae78a5c34d6b MD5 · raw file

  1. #include "flx_glob.hpp"
  2. #include "unixem_util.hpp"
  3. #include <errno.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <windows.h>
  7. static char const *strrpbrk(char const *string, char const *strCharSet)
  8. {
  9. char const *part = NULL;
  10. char const *pch;
  11. for(pch = strCharSet; *pch; ++pch)
  12. {
  13. char const *p = strrchr(string, *pch);
  14. if(NULL != p)
  15. {
  16. if(NULL == part)
  17. {
  18. part = p;
  19. }
  20. else
  21. {
  22. if(part < p)
  23. {
  24. part = p;
  25. }
  26. }
  27. }
  28. }
  29. return part;
  30. }
  31. int glob( char const *pattern
  32. , int flags
  33. , int (*errfunc)(char const *, int)
  34. , glob_t *pglob)
  35. {
  36. int result;
  37. char szRelative[1 + _MAX_PATH];
  38. char const *file_part;
  39. WIN32_FIND_DATAA find_data;
  40. HANDLE hFind;
  41. char *buffer;
  42. char szPattern2[1 + _MAX_PATH];
  43. char szPattern3[1 + _MAX_PATH];
  44. char const *effectivePattern = pattern;
  45. char const *leafMost;
  46. const int bMagic = (NULL != strpbrk(pattern, "?*"));
  47. int bNoMagic = 0;
  48. int bMagic0;
  49. size_t maxMatches = ~(size_t)(0);
  50. if(flags & GLOB_NOMAGIC)
  51. {
  52. bNoMagic = !bMagic;
  53. }
  54. if(flags & GLOB_LIMIT)
  55. {
  56. maxMatches = (size_t)pglob->gl_matchc;
  57. }
  58. if(flags & GLOB_TILDE)
  59. {
  60. if( '~' == pattern[0] &&
  61. ( '\0' == pattern[1] ||
  62. '/' == pattern[1] ||
  63. '\\' == pattern[1]))
  64. {
  65. DWORD dw;
  66. (void)lstrcpyA(&szPattern2[0], "%HOMEDRIVE%%HOMEPATH%");
  67. dw = ExpandEnvironmentStringsA(&szPattern2[0], &szPattern3[0], UNIXEM_NUM_ELEMENTS(szPattern3) - 1);
  68. if(0 != dw)
  69. {
  70. (void)lstrcpynA(&szPattern3[0] + dw - 1, &pattern[1], (int)(UNIXEM_NUM_ELEMENTS(szPattern3) - dw));
  71. szPattern3[UNIXEM_NUM_ELEMENTS(szPattern3) - 1] = '\0';
  72. effectivePattern = szPattern3;
  73. }
  74. }
  75. }
  76. file_part = strrpbrk(effectivePattern, "\\/");
  77. if(NULL != file_part)
  78. {
  79. leafMost = ++file_part;
  80. (void)lstrcpyA(szRelative, effectivePattern);
  81. szRelative[file_part - effectivePattern] = '\0';
  82. }
  83. else
  84. {
  85. szRelative[0] = '\0';
  86. leafMost = effectivePattern;
  87. }
  88. bMagic0 = (leafMost == strpbrk(leafMost, "?*"));
  89. hFind = FindFirstFileA(effectivePattern, &find_data);
  90. buffer = NULL;
  91. pglob->gl_pathc = 0;
  92. pglob->gl_pathv = NULL;
  93. if(0 == (flags & GLOB_DOOFFS))
  94. {
  95. pglob->gl_offs = 0;
  96. }
  97. if(hFind == INVALID_HANDLE_VALUE)
  98. {
  99. if(NULL != errfunc)
  100. {
  101. (void)errfunc(effectivePattern, (int)GetLastError());
  102. }
  103. result = GLOB_NOMATCH;
  104. }
  105. else
  106. {
  107. int cbCurr = 0;
  108. size_t cbAlloc = 0;
  109. size_t cMatches = 0;
  110. result = 0;
  111. do
  112. {
  113. int cch;
  114. size_t new_cbAlloc;
  115. if( bMagic0 &&
  116. 0 == (flags & GLOB_PERIOD))
  117. {
  118. if('.' == find_data.cFileName[0])
  119. {
  120. continue;
  121. }
  122. }
  123. if(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  124. {
  125. #ifdef GLOB_ONLYFILE
  126. if(flags & GLOB_ONLYFILE)
  127. {
  128. continue;
  129. }
  130. #endif /* GLOB_ONLYFILE */
  131. if( bMagic0 &&
  132. GLOB_NODOTSDIRS == (flags & GLOB_NODOTSDIRS))
  133. {
  134. /* Pattern must begin with '.' to match either dots directory */
  135. if( 0 == lstrcmpA(".", find_data.cFileName) ||
  136. 0 == lstrcmpA("..", find_data.cFileName))
  137. {
  138. continue;
  139. }
  140. }
  141. if(flags & GLOB_MARK)
  142. {
  143. #if 0
  144. if(find_data.cFileName[0] >= 'A' && find_data.cFileName[0] <= 'M')
  145. #endif /* 0 */
  146. (void)lstrcatA(find_data.cFileName, "/");
  147. }
  148. }
  149. else
  150. {
  151. if(flags & GLOB_ONLYDIR)
  152. {
  153. /* Skip all further actions, and get the next entry */
  154. #if 0
  155. if(find_data.cFileName[0] >= 'A' && find_data.cFileName[0] <= 'M')
  156. #endif /* 0 */
  157. continue;
  158. }
  159. }
  160. cch = lstrlenA(find_data.cFileName);
  161. if(NULL != file_part)
  162. {
  163. cch += file_part - effectivePattern;
  164. }
  165. new_cbAlloc = (size_t)cbCurr + cch + 1;
  166. if(new_cbAlloc > cbAlloc)
  167. {
  168. char *new_buffer;
  169. new_cbAlloc *= 2;
  170. new_cbAlloc = (new_cbAlloc + 31) & ~(31);
  171. new_buffer = (char*)realloc(buffer, new_cbAlloc);
  172. if(new_buffer == NULL)
  173. {
  174. result = GLOB_NOSPACE;
  175. free(buffer);
  176. buffer = NULL;
  177. break;
  178. }
  179. buffer = new_buffer;
  180. cbAlloc = new_cbAlloc;
  181. }
  182. (void)lstrcpynA(buffer + cbCurr, szRelative, 1 + (file_part - effectivePattern));
  183. (void)lstrcatA(buffer + cbCurr, find_data.cFileName);
  184. cbCurr += cch + 1;
  185. ++cMatches;
  186. }
  187. while(FindNextFile(hFind, &find_data) && cMatches != maxMatches);
  188. (void)FindClose(hFind);
  189. if(result == 0)
  190. {
  191. /* Now expand the buffer, to fit in all the pointers. */
  192. size_t cbPointers = (1 + cMatches + pglob->gl_offs) * sizeof(char*);
  193. char *new_buffer = (char*)realloc(buffer, cbAlloc + cbPointers);
  194. if(new_buffer == NULL)
  195. {
  196. result = GLOB_NOSPACE;
  197. free(buffer);
  198. }
  199. else
  200. {
  201. char **pp;
  202. char **begin;
  203. char **end;
  204. char *next_str;
  205. buffer = new_buffer;
  206. (void)memmove(new_buffer + cbPointers, new_buffer, cbAlloc);
  207. /* Handle the offsets. */
  208. begin = (char**)new_buffer;
  209. end = begin + pglob->gl_offs;
  210. for(; begin != end; ++begin)
  211. {
  212. *begin = NULL;
  213. }
  214. /* Sort, or no sort. */
  215. pp = (char**)new_buffer + pglob->gl_offs;
  216. begin = pp;
  217. end = begin + cMatches;
  218. if(flags & GLOB_NOSORT)
  219. {
  220. /* The way we need in order to test the removal of dots in the findfile_sequence. */
  221. *end = NULL;
  222. for(begin = pp, next_str = buffer + cbPointers; begin != end; --end)
  223. {
  224. *(end - 1) = next_str;
  225. /* Find the next string. */
  226. next_str += 1 + lstrlenA(next_str);
  227. }
  228. }
  229. else
  230. {
  231. /* The normal way. */
  232. for(begin = pp, next_str = buffer + cbPointers; begin != end; ++begin)
  233. {
  234. *begin = next_str;
  235. /* Find the next string. */
  236. next_str += 1 + lstrlenA(next_str);
  237. }
  238. *begin = NULL;
  239. }
  240. /* Return results to caller. */
  241. pglob->gl_pathc = (int)cMatches;
  242. pglob->gl_matchc= (int)cMatches;
  243. pglob->gl_flags = 0;
  244. if(bMagic)
  245. {
  246. pglob->gl_flags |= GLOB_MAGCHAR;
  247. }
  248. pglob->gl_pathv = (char**)new_buffer;
  249. }
  250. }
  251. if(0 == cMatches)
  252. {
  253. result = GLOB_NOMATCH;
  254. }
  255. }
  256. if(GLOB_NOMATCH == result)
  257. {
  258. if( (flags & GLOB_TILDE_CHECK) &&
  259. effectivePattern == szPattern3)
  260. {
  261. result = GLOB_NOMATCH;
  262. }
  263. else if(bNoMagic ||
  264. (flags & GLOB_NOCHECK))
  265. {
  266. size_t cbNeeded = ((2 + pglob->gl_offs) * sizeof(char*)) + (1 + strlen(effectivePattern));
  267. char **pp = (char**)realloc(buffer, cbNeeded);
  268. if(NULL == pp)
  269. {
  270. result = GLOB_NOSPACE;
  271. free(buffer);
  272. }
  273. else
  274. {
  275. /* Handle the offsets. */
  276. char **begin = pp;
  277. char **end = pp + pglob->gl_offs;
  278. for(; begin != end; ++begin)
  279. {
  280. *begin = NULL;
  281. }
  282. /* Synthesis the pattern result. */
  283. pp[0 + pglob->gl_offs] = strcpy((char*)(pp + 2 + pglob->gl_offs), effectivePattern);
  284. pp[1 + pglob->gl_offs] = NULL;
  285. /* Return results to caller. */
  286. pglob->gl_pathc = 1;
  287. pglob->gl_matchc= 1;
  288. pglob->gl_flags = 0;
  289. if(bMagic)
  290. {
  291. pglob->gl_flags |= GLOB_MAGCHAR;
  292. }
  293. pglob->gl_pathv = pp;
  294. result = 0;
  295. }
  296. }
  297. }
  298. else if(0 == result)
  299. {
  300. if((size_t)pglob->gl_matchc == maxMatches)
  301. {
  302. result = GLOB_NOSPACE;
  303. }
  304. }
  305. return result;
  306. }
  307. void globfree(glob_t *pglob)
  308. {
  309. if(pglob != NULL)
  310. {
  311. free(pglob->gl_pathv);
  312. pglob->gl_pathc = 0;
  313. pglob->gl_pathv = NULL;
  314. }
  315. }