home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / wild.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  11KB  |  420 lines

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