Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

469 lines
13 KiB

  1. /***
  2. *wild.c - wildcard expander
  3. *
  4. * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * expands wildcards in argv
  8. *
  9. * handles '*' (none or more of any char) and '?' (exactly one char)
  10. *
  11. *Revision History:
  12. * 05-21-84 RN initial version
  13. * 06-07-85 TDC since dos accepts forward slash, added
  14. * code to accept forward slash in a manner consistent
  15. * with reverse slash.
  16. * 09-20-86 SKS Modified for OS/2
  17. * All argument strings to this function have a
  18. * leading flag character. If the flag is a quote,
  19. * that argument string was quoted on the command
  20. * line and should have not wildcard expansion. In all
  21. * cases the leading flag character is removed from
  22. * the string.
  23. * 11-11-86 JMB Added Kanji support under KANJI switch.
  24. * 09-21-88 WAJ initial 386 version
  25. * 04-09-90 GJF Added #include <cruntime.h> and removed #include
  26. * <register.h>. Made calling types explicit (_CALLTYPE1
  27. * or _CALLTYPE4). Also, fixed the copyright.
  28. * 04-10-90 GJF Added #include <internal.h> and fixed compiler warnings
  29. * (-W3).
  30. * 07-03-90 SBM Compiles cleanly with -W3 under KANJI, removed
  31. * redundant includes, removed #include <internal.h>
  32. * to keep wild.c free of private stuff, should we
  33. * decide to release it
  34. * 09-07-90 SBM put #include <internal.h> back in, reason for
  35. * removing it discovered to be horribly bogus
  36. * 10-08-90 GJF New-style function declarators.
  37. * 01-18-91 GJF ANSI naming.
  38. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  39. * Remove explicit declarations of __argc & __argv.
  40. * They are declared in <stdlib.h>
  41. * 05-05-93 SKS Filename sorting should be case-insensitive
  42. * 06-09-93 KRS Update _MBCS support.
  43. * 10-20-93 GJF Merged in NT version.
  44. * 11-23-93 CFW Wide char enable, grab _find from stdargv.c.
  45. * 12-07-93 CFW Change _TCHAR to _TSCHAR.
  46. * 04-22-94 GJF Made defintions of arghead, argend, _WildFindHandle
  47. * and findbuf conditional on DLL_FOR_WIN32S.
  48. * 01-10-95 CFW Debug CRT allocs.
  49. * 01-18-95 GJF Must replace _tcsdup with _malloc_crt/_tcscpy for
  50. * _DEBUG build.
  51. * 02-04-98 GJF Changes for Win64: use intptr_t and ptrdiff_t casts
  52. * where appropriate.
  53. * 02-19-01 GB added check for return value of malloc in find.
  54. *
  55. *******************************************************************************/
  56. #include <cruntime.h>
  57. #include <oscalls.h>
  58. #include <stddef.h>
  59. #include <stdlib.h>
  60. #include <string.h>
  61. #include <ctype.h>
  62. #include <msdos.h>
  63. #include <internal.h>
  64. #include <tchar.h>
  65. #ifdef _MBCS
  66. #include <mbdata.h>
  67. #include <mbstring.h>
  68. #endif
  69. #include <dbgint.h>
  70. /*
  71. ** these are the data structures
  72. **
  73. ** __argv
  74. ** ------- ------
  75. ** | |---->| |---->"arg0"
  76. ** ------- ------
  77. ** | |---->"arg1"
  78. ** ------
  79. ** ....
  80. ** ------
  81. ** | |---->"argn"
  82. ** ------
  83. ** |NULL|
  84. ** ------
  85. ** argend
  86. ** -------
  87. ** ------- | |
  88. ** | | __argc -------
  89. ** ------- |
  90. ** |
  91. ** arghead V
  92. ** ------ --------- ----------
  93. ** | |---->| | |----> .... ---->| |NULL|
  94. ** ------ --------- ----------
  95. ** | |
  96. ** V V
  97. ** "narg0" "nargn"
  98. */
  99. #define ERRORHANDLE ((HANDLE)(intptr_t)(-1))
  100. /* local function tchars */
  101. #ifdef WPRFLAG
  102. #define tmatch wmatch
  103. #define tadd wadd
  104. #define tsort wsort
  105. #define tfind wfind
  106. #else
  107. #define tmatch match
  108. #define tadd add
  109. #define tsort sort
  110. #define tfind find
  111. #endif
  112. #define SLASHCHAR _T('\\')
  113. #define FWDSLASHCHAR _T('/')
  114. #define COLONCHAR _T(':')
  115. #define QUOTECHAR _T('"')
  116. #define SLASH _T("\\")
  117. #define FWDSLASH _T("/")
  118. #define STAR _T("*.*")
  119. #define DOT _T(".")
  120. #define DOTDOT _T("..")
  121. #define WILDSTRING _T("*?")
  122. struct argnode {
  123. _TSCHAR *argptr;
  124. struct argnode *nextnode;
  125. };
  126. static struct argnode *arghead;
  127. static struct argnode *argend;
  128. #ifdef WPRFLAG
  129. static int __cdecl wmatch(wchar_t *, wchar_t *);
  130. static int __cdecl wadd(wchar_t *);
  131. static void __cdecl wsort(struct argnode *);
  132. static wchar_t * __cdecl wfind (wchar_t *pattern);
  133. #else
  134. static int __cdecl match(char *, char *);
  135. static int __cdecl add(char *);
  136. static void __cdecl sort(struct argnode *);
  137. static char * __cdecl find (char *pattern);
  138. #endif
  139. /***
  140. *int _cwild() - wildcard expander
  141. *
  142. *Purpose:
  143. * expands wildcard in file specs in argv
  144. *
  145. * handles '*' (none or more of any char), '?' (exactly one char), and
  146. * '[string]' (chars which match string chars or between n1 and n2
  147. * if 'n1-n2' in string inclusive)
  148. *
  149. *Entry:
  150. *
  151. *Exit:
  152. * returns 0 if successful, -1 if any malloc() calls fail
  153. * if problems with malloc, the old argc and argv are not touched
  154. *
  155. *Exceptions:
  156. *
  157. *******************************************************************************/
  158. #ifdef WPRFLAG
  159. int __cdecl _wcwild (
  160. #else
  161. int __cdecl _cwild (
  162. #endif
  163. void
  164. )
  165. {
  166. #ifdef WPRFLAG
  167. REG1 wchar_t **argv = __wargv;
  168. #else
  169. REG1 char **argv = __argv;
  170. #endif
  171. REG2 struct argnode *nodeptr;
  172. REG3 int argc;
  173. REG4 _TSCHAR **tmp;
  174. _TSCHAR *wchar;
  175. arghead = argend = NULL;
  176. #ifdef WPRFLAG
  177. for (argv = __wargv; *argv; argv++) /* for each arg... */
  178. #else
  179. for (argv = __argv; *argv; argv++) /* for each arg... */
  180. #endif
  181. if ( *(*argv)++ == QUOTECHAR )
  182. /* strip leading quote from quoted arg */
  183. {
  184. if (tadd(*argv))
  185. return(-1);
  186. }
  187. else if (wchar = _tcspbrk( *argv, WILDSTRING )) {
  188. /* attempt to expand arg with wildcard */
  189. if (tmatch( *argv, wchar ))
  190. return(-1);
  191. }
  192. else if (tadd( *argv )) /* normal arg, just add */
  193. return(-1);
  194. /* count the args */
  195. for (argc = 0, nodeptr = arghead; nodeptr;
  196. nodeptr = nodeptr->nextnode, argc++)
  197. ;
  198. /* try to get new arg vector */
  199. if (!(tmp = (_TSCHAR **)_malloc_crt(sizeof(_TSCHAR *)*(argc+1))))
  200. return(-1);
  201. /* the new arg vector... */
  202. #ifdef WPRFLAG
  203. __wargv = tmp;
  204. #else
  205. __argv = tmp;
  206. #endif
  207. /* the new arg count... */
  208. __argc = argc;
  209. /* install the new args */
  210. for (nodeptr = arghead; nodeptr; nodeptr = nodeptr->nextnode)
  211. *tmp++ = nodeptr->argptr;
  212. /* the terminal NULL */
  213. *tmp = NULL;
  214. /* free up local data */
  215. for (nodeptr = arghead; nodeptr; nodeptr = arghead) {
  216. arghead = arghead->nextnode;
  217. _free_crt(nodeptr);
  218. }
  219. /* return success */
  220. return(0);
  221. }
  222. /***
  223. *match(arg, ptr) - [STATIC]
  224. *
  225. *Purpose:
  226. *
  227. *Entry:
  228. *
  229. *Exit:
  230. *
  231. *Exceptions:
  232. *
  233. *******************************************************************************/
  234. #ifdef WPRFLAG
  235. static int __cdecl wmatch (
  236. #else
  237. static int __cdecl match (
  238. #endif
  239. REG4 _TSCHAR *arg,
  240. REG1 _TSCHAR *ptr
  241. )
  242. {
  243. REG2 _TSCHAR *new;
  244. REG3 int length = 0;
  245. _TSCHAR *all;
  246. REG5 struct argnode *first;
  247. REG6 int gotone = 0;
  248. while (ptr != arg && *ptr != SLASHCHAR && *ptr != FWDSLASHCHAR
  249. && *ptr != COLONCHAR) {
  250. /* find first slash or ':' before wildcard */
  251. #ifdef _MBCS
  252. if (--ptr > arg)
  253. ptr = _mbsdec(arg,ptr+1);
  254. #else
  255. ptr--;
  256. #endif
  257. }
  258. if (*ptr == COLONCHAR && ptr != arg+1) /* weird name, just add it as is */
  259. return(tadd(arg));
  260. if (*ptr == SLASHCHAR || *ptr == FWDSLASHCHAR
  261. || *ptr == COLONCHAR) /* pathname */
  262. length = (int)(ptrdiff_t)(ptr - arg + 1); /* length of dir prefix */
  263. if (new = tfind(arg)) { /* get the first file name */
  264. first = argend;
  265. do { /* got a file name */
  266. if (_tcscmp(new, DOT) && _tcscmp(new, DOTDOT)) {
  267. if (*ptr != SLASHCHAR && *ptr != COLONCHAR
  268. && *ptr != FWDSLASHCHAR ) {
  269. /* current directory; don't need path */
  270. #ifdef _DEBUG
  271. if (!(arg=_malloc_crt((_tcslen(new)+1)*sizeof(_TSCHAR)))
  272. || tadd(_tcscpy(arg,new)))
  273. #else /* ndef _DEBUG */
  274. if (!(arg = _tcsdup(new)) || tadd(arg))
  275. #endif /* _DEBUG */
  276. return(-1);
  277. }
  278. else /* add full pathname */
  279. if (!(all=_malloc_crt((length+_tcslen(new)+1)*sizeof(_TSCHAR)))
  280. || tadd(_tcscpy(_tcsncpy(all,arg,length)+length,new)
  281. - length))
  282. return(-1);
  283. gotone++;
  284. }
  285. }
  286. while (new = tfind(NULL)); /* get following files */
  287. if (gotone) {
  288. tsort(first ? first->nextnode : arghead);
  289. return(0);
  290. }
  291. }
  292. return(tadd(arg)); /* no match */
  293. }
  294. /***
  295. *add(arg) - [STATIC]
  296. *
  297. *Purpose:
  298. *
  299. *Entry:
  300. *
  301. *Exit:
  302. *
  303. *Exceptions:
  304. *
  305. *******************************************************************************/
  306. #ifdef WPRFLAG
  307. static int __cdecl wadd (
  308. #else
  309. static int __cdecl add (
  310. #endif
  311. _TSCHAR *arg
  312. )
  313. {
  314. REG1 struct argnode *nodeptr;
  315. if (!(nodeptr = (struct argnode *)_malloc_crt(sizeof(struct argnode))))
  316. return(-1);
  317. nodeptr->argptr = arg;
  318. nodeptr->nextnode = NULL;
  319. if (arghead)
  320. argend->nextnode = nodeptr;
  321. else
  322. arghead = nodeptr;
  323. argend = nodeptr;
  324. return(0);
  325. }
  326. /***
  327. *sort(first) - [STATIC]
  328. *
  329. *Purpose:
  330. *
  331. *Entry:
  332. *
  333. *Exit:
  334. *
  335. *Exceptions:
  336. *
  337. *******************************************************************************/
  338. #ifdef WPRFLAG
  339. static void __cdecl wsort (
  340. #else
  341. static void __cdecl sort (
  342. #endif
  343. REG2 struct argnode *first
  344. )
  345. {
  346. REG1 struct argnode *nodeptr;
  347. REG3 _TSCHAR *temp;
  348. if (first) /* something to sort */
  349. while (nodeptr = first->nextnode) {
  350. do {
  351. #ifdef _POSIX_
  352. if (_tcscmp(nodeptr->argptr, first->argptr) < 0) {
  353. #else
  354. if (_tcsicmp(nodeptr->argptr, first->argptr) < 0) {
  355. #endif /* _POSIX_ */
  356. temp = first->argptr;
  357. first->argptr = nodeptr->argptr;
  358. nodeptr->argptr = temp;
  359. }
  360. }
  361. while (nodeptr = nodeptr->nextnode);
  362. first = first->nextnode;
  363. }
  364. }
  365. /***
  366. *find(pattern) - find matching filename
  367. *
  368. *Purpose:
  369. * if argument is non-null, do a DOSFINDFIRST on that pattern
  370. * otherwise do a DOSFINDNEXT call. Return matching filename
  371. * or NULL if no more matches.
  372. *
  373. *Entry:
  374. * pattern = pointer to pattern or NULL
  375. * (NULL means find next matching filename)
  376. *
  377. *Exit:
  378. * returns pointer to matching file name
  379. * or NULL if no more matches.
  380. *
  381. *Exceptions:
  382. *
  383. *******************************************************************************/
  384. #ifdef WPRFLAG
  385. static wchar_t * __cdecl wfind (
  386. #else
  387. static char * __cdecl find (
  388. #endif /* WPRFLAG */
  389. _TSCHAR *pattern
  390. )
  391. {
  392. _TSCHAR *retval;
  393. static HANDLE _WildFindHandle;
  394. static LPWIN32_FIND_DATA findbuf;
  395. if (pattern) {
  396. if (findbuf == NULL)
  397. if ((findbuf = (LPWIN32_FIND_DATA)_malloc_crt(MAX_PATH + sizeof(*findbuf))) == NULL)
  398. return NULL;
  399. if (_WildFindHandle != NULL) {
  400. (void)FindClose( _WildFindHandle );
  401. _WildFindHandle = NULL;
  402. }
  403. _WildFindHandle = FindFirstFile( (LPTSTR)pattern, findbuf );
  404. if (_WildFindHandle == ERRORHANDLE)
  405. return NULL;
  406. }
  407. else if (!FindNextFile( _WildFindHandle, findbuf )) {
  408. (void)FindClose( _WildFindHandle );
  409. _WildFindHandle = NULL;
  410. return NULL;
  411. }
  412. retval = findbuf->cFileName;
  413. return retval;
  414. }