home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 February / Chip_2004-02_cd1.bin / tema / stream / download / asfrec / source / wingui / CmdLine.c < prev    next >
C/C++ Source or Header  |  2000-06-14  |  19KB  |  676 lines

  1.  
  2. /* Command line parsing with optional Wildcard expansion */
  3. /* identical in function to CRT console startup code     */
  4.  
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <ctype.h>
  8.  
  9. #define WIN32_LEAN_AND_MEAN
  10. #include <windows.h>
  11. #include "CmdLine.h"
  12.  
  13. #define _T(x) x
  14.  
  15. /* Globals */
  16.  
  17. int argc;
  18. char **argv;
  19.  
  20.  
  21. // Use Wildcard expansion on Command Line
  22.  
  23. #define WILDCARD 1
  24.  
  25.  
  26. static int mysetargv (char *lpszCmdLine);
  27.  
  28.  
  29.  
  30. // =======================================================================
  31. // ParseCommandLine()
  32. //
  33. // Returns: TRUE if successful, or FALSE if there was an error.
  34. // =======================================================================
  35. int ParseCommandLine(LPTSTR cmdline)
  36. {
  37.     if (mysetargv(cmdline))
  38.         return 0;
  39.  
  40.     // Returning TRUE means the caller should continue doing what they
  41.     // were doing: we succeeded.
  42.     return 1;
  43. }
  44.  
  45.  
  46. void FreeCommandLine(void)
  47. {
  48. }
  49.  
  50.  
  51.  
  52. /***
  53. *wild.c - wildcard expander
  54. *
  55. *       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
  56. *
  57. *Purpose:
  58. *        expands wildcards in argv
  59. *
  60. *        handles '*' (none or more of any char) and '?' (exactly one char)
  61. *
  62. *******************************************************************************/
  63.  
  64. /*
  65. ** these are the data structures
  66. **
  67. **     __argv
  68. **     -------     ------
  69. **     |     |---->|    |---->"arg0"
  70. **     -------     ------
  71. **                 |    |---->"arg1"
  72. **                 ------
  73. **                  ....
  74. **                 ------
  75. **                 |    |---->"argn"
  76. **                 ------
  77. **                 |NULL|
  78. **                 ------
  79. **                                       argend
  80. **                                       -------
  81. **     -------                           |     |
  82. **     |     | __argc                    -------
  83. **     -------                              |
  84. **                                          |
  85. **  arghead                                 V
  86. **  ------     ---------                ----------
  87. **  |    |---->|   |   |----> .... ---->|   |NULL|
  88. **  ------     ---------                ----------
  89. **               |                        |
  90. **               V                        V
  91. **            "narg0"                  "nargn"
  92. */
  93.  
  94.  
  95.  
  96. /* Prototypes */
  97.  
  98. struct argnode {
  99.     char *argptr;
  100.     struct argnode *nextnode;
  101. };
  102.  
  103. static int mycwild (void);
  104. static int mymatch(char *, char *);
  105. static int myadd(char *);
  106. static void mysort(struct argnode *);
  107. static char * myfind (char *pattern);
  108. static void myparse_cmdline(char *cmdstart, char **argv, char *args,
  109.         int *numargs, int *numchars);
  110.  
  111.         
  112. #define NULCHAR         _T('\0')
  113. #define SPACECHAR       _T(' ')
  114. #define TABCHAR         _T('\t')
  115. #define DQUOTECHAR      _T('\"')
  116. #define SLASHCHAR       _T('\\')
  117.  
  118. #define FWDSLASHCHAR    _T('/')
  119. #define COLONCHAR       _T(':')
  120. #define QUOTECHAR       _T('\"')
  121.  
  122. #define SLASH           _T("\\")
  123. #define FWDSLASH        _T("/")
  124. #define STAR            _T("*.*")
  125. #define DOT             _T(".")
  126. #define DOTDOT          _T("..")
  127.  
  128. #define WILDSTRING      _T("*?")
  129.  
  130.  
  131. static struct argnode *arghead;
  132. static struct argnode *argend;
  133.  
  134.  
  135.  
  136.  
  137. /***
  138. *stdargv.c - standard & wildcard _setargv routine
  139. *
  140. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  141. *
  142. *Purpose:
  143. *       processes program command line, with or without wildcard expansion
  144. *
  145. *******************************************************************************/
  146.  
  147.  
  148.  
  149. /***
  150. *_setargv, __setargv - set up "argc" and "argv" for C programs
  151. *
  152. *Purpose:
  153. *       Read the command line and create the argv array for C
  154. *       programs.
  155. *
  156. *Entry:
  157. *       Arguments are retrieved from the program command line,
  158. *       pointed to by _acmdln.
  159. *
  160. *Exit:
  161. *       "argv" points to a null-terminated list of pointers to ASCIZ
  162. *       strings, each of which is an argument from the command line.
  163. *       "argc" is the number of arguments.  The strings are copied from
  164. *       the environment segment into space allocated on the heap/stack.
  165. *       The list of pointers is also located on the heap or stack.
  166. *       _pgmptr points to the program name.
  167. *
  168. *Exceptions:
  169. *       Terminates with out of memory error if no memory to allocate.
  170. *
  171. *******************************************************************************/
  172.  
  173. static int mysetargv (char *lpszCmdLine)
  174. {
  175.         char *p;
  176.         char *cmdstart;                  /* start of command line to parse */
  177.         int numargs, numchars;
  178.  
  179.         /* if there's no command line at all (won't happen from cmd.exe, but
  180.            possibly another program), then we use _pgmptr as the command line
  181.            to parse, so that argv[0] is initialized to the program name */
  182.  
  183.         cmdstart = lpszCmdLine;
  184.  
  185.         /* first find out how much space is needed to store args */
  186.         myparse_cmdline(cmdstart, NULL, NULL, &numargs, &numchars);
  187.  
  188.         /* allocate space for argv[] vector and strings */
  189.         p = (char*)malloc(numargs * sizeof(char *) + numchars);
  190.         if (p == NULL)
  191.             return(-1);
  192.  
  193.         /* store args and argv ptrs in just allocated block */
  194.  
  195.         myparse_cmdline(cmdstart, (char **)p, p + numargs * sizeof(char *), &numargs, &numchars);
  196.  
  197.         /* set argv and argc */
  198.         argc = numargs - 1;
  199.         argv = (char **)p;
  200.  
  201. #ifdef WILDCARD
  202.  
  203.         /* call _[w]cwild to expand wildcards in arg vector */
  204.         if (mycwild())
  205.             return(-1);
  206.  
  207. #endif  /* WILDCARD */
  208.         return(0);
  209. }
  210.  
  211.  
  212. /***
  213. *static void parse_cmdline(cmdstart, argv, args, numargs, numchars)
  214. *
  215. *Purpose:
  216. *       Parses the command line and sets up the argv[] array.
  217. *       On entry, cmdstart should point to the command line,
  218. *       argv should point to memory for the argv array, args
  219. *       points to memory to place the text of the arguments.
  220. *       If these are NULL, then no storing (only coujting)
  221. *       is done.  On exit, *numargs has the number of
  222. *       arguments (plus one for a final NULL argument),
  223. *       and *numchars has the number of bytes used in the buffer
  224. *       pointed to by args.
  225. *
  226. *Entry:
  227. *       char *cmdstart - pointer to command line of the form
  228. *           <progname><nul><args><nul>
  229. *       char **argv - where to build argv array; NULL means don't
  230. *                       build array
  231. *       char *args - where to place argument text; NULL means don't
  232. *                       store text
  233. *
  234. *Exit:
  235. *       no return value
  236. *       int *numargs - returns number of argv entries created
  237. *       int *numchars - number of characters used in args buffer
  238. *
  239. *Exceptions:
  240. *
  241. *******************************************************************************/
  242.  
  243. static void myparse_cmdline (
  244.     char *cmdstart,
  245.     char **argv,
  246.     char *args,
  247.     int *numargs,
  248.     int *numchars
  249.     )
  250. {
  251.         char *p;
  252.         char c;
  253.         int inquote;                    /* 1 = inside quotes */
  254.         int copychar;                   /* 1 = copy char to *args */
  255.         unsigned numslash;              /* num of backslashes seen */
  256.  
  257.         *numchars = 0;
  258.         *numargs = 1;                   /* the program name at least */
  259.  
  260.         /* first scan the program name, copy it, and count the bytes */
  261.         p = cmdstart;
  262.         if (argv)
  263.             *argv++ = args;
  264.  
  265. #ifdef WILDCARD
  266.         /* To handle later wild card expansion, we prefix each entry by
  267.         it's first character before quote handling.  This is done
  268.         so _[w]cwild() knows whether to expand an entry or not. */
  269.         if (args)
  270.             *args++ = *p;
  271.         ++*numchars;
  272.  
  273. #endif  /* WILDCARD */
  274.  
  275.         /* A quoted program name is handled here. The handling is much
  276.            simpler than for other arguments. Basically, whatever lies
  277.            between the leading double-quote and next one, or a terminal null
  278.            character is simply accepted. Fancier handling is not required
  279.            because the program name must be a legal NTFS/HPFS file name.
  280.            Note that the double-quote characters are not copied, nor do they
  281.            contribute to numchars. */
  282.         if ( *p == DQUOTECHAR ) {
  283.             /* scan from just past the first double-quote through the next
  284.                double-quote, or up to a null, whichever comes first */
  285.             while ( (*(++p) != DQUOTECHAR) && (*p != NULCHAR) ) {
  286.  
  287.                 ++*numchars;
  288.                 if ( args )
  289.                     *args++ = *p;
  290.             }
  291.             /* append the terminating null */
  292.             ++*numchars;
  293.             if ( args )
  294.                 *args++ = NULCHAR;
  295.  
  296.             /* if we stopped on a double-quote (usual case), skip over it */
  297.             if ( *p == DQUOTECHAR )
  298.                 p++;
  299.         }
  300.         else {
  301.             /* Not a quoted program name */
  302.             do {
  303.                 ++*numchars;
  304.                 if (args)
  305.                     *args++ = *p;
  306.  
  307.                 c = *p++;
  308.  
  309.             } while ( c != SPACECHAR && c != NULCHAR && c != TABCHAR );
  310.  
  311.             if ( c == NULCHAR ) {
  312.                 p--;
  313.             } else {
  314.                 if (args)
  315.                     *(args-1) = NULCHAR;
  316.             }
  317.         }
  318.  
  319.         inquote = 0;
  320.  
  321.         /* loop on each argument */
  322.         for(;;) {
  323.  
  324.             if ( *p ) {
  325.                 while (*p == SPACECHAR || *p == TABCHAR)
  326.                     ++p;
  327.             }
  328.  
  329.             if (*p == NULCHAR)
  330.                 break;              /* end of args */
  331.  
  332.             /* scan an argument */
  333.             if (argv)
  334.                 *argv++ = args;     /* store ptr to arg */
  335.             ++*numargs;
  336.  
  337. #ifdef WILDCARD
  338.         /* To handle later wild card expansion, we prefix each entry by
  339.         it's first character before quote handling.  This is done
  340.         so _[w]cwild() knows whether to expand an entry or not. */
  341.         if (args)
  342.             *args++ = *p;
  343.         ++*numchars;
  344.  
  345. #endif  /* WILDCARD */
  346.  
  347.         /* loop through scanning one argument */
  348.         for (;;) {
  349.             copychar = 1;
  350.             /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
  351.                2N+1 backslashes + " ==> N backslashes + literal "
  352.                N backslashes ==> N backslashes */
  353.             numslash = 0;
  354.             while (*p == SLASHCHAR) {
  355.                 /* count number of backslashes for use below */
  356.                 ++p;
  357.                 ++numslash;
  358.             }
  359.             if (*p == DQUOTECHAR) {
  360.                 /* if 2N backslashes before, start/end quote, otherwise
  361.                     copy literally */
  362.                 if (numslash % 2 == 0) {
  363.                     if (inquote) {
  364.                         if (p[1] == DQUOTECHAR)
  365.                             p++;    /* Double quote inside quoted string */
  366.                         else        /* skip first quote char and copy second */
  367.                             copychar = 0;
  368.                     } else
  369.                         copychar = 0;       /* don't copy quote */
  370.  
  371.                     inquote = !inquote;
  372.                 }
  373.                 numslash /= 2;          /* divide numslash by two */
  374.             }
  375.  
  376.             /* copy slashes */
  377.             while (numslash--) {
  378.                 if (args)
  379.                     *args++ = SLASHCHAR;
  380.                 ++*numchars;
  381.             }
  382.  
  383.             /* if at end of arg, break loop */
  384.             if (*p == NULCHAR || (!inquote && (*p == SPACECHAR || *p == TABCHAR)))
  385.                 break;
  386.  
  387.             /* copy character into argument */
  388.             if (copychar) {
  389.                 if (args)
  390.                     *args++ = *p;
  391.                 ++*numchars;
  392.             }
  393.             ++p;
  394.             }
  395.  
  396.             /* null-terminate the argument */
  397.  
  398.             if (args)
  399.                 *args++ = NULCHAR;          /* terminate string */
  400.             ++*numchars;
  401.         }
  402.  
  403.         /* We put one last argument in -- a null ptr */
  404.         if (argv)
  405.             *argv++ = NULL;
  406.         ++*numargs;
  407. }
  408.  
  409.  
  410. /***
  411. *int _cwild() - wildcard expander
  412. *
  413. *Purpose:
  414. *    expands wildcard in file specs in argv
  415. *
  416. *    handles '*' (none or more of any char), '?' (exactly one char), and
  417. *    '[string]' (chars which match string chars or between n1 and n2
  418. *    if 'n1-n2' in string inclusive)
  419. *
  420. *Entry:
  421. *
  422. *Exit:
  423. *    returns 0 if successful, -1 if any malloc() calls fail
  424. *    if problems with malloc, the old argc and argv are not touched
  425. *
  426. *Exceptions:
  427. *
  428. *******************************************************************************/
  429.  
  430. int mycwild (void)
  431. {
  432.     char **newargv = argv;
  433.     struct argnode *nodeptr;
  434.     int newargc;
  435.     char **tmp;
  436.     char *wchar;
  437.  
  438.     arghead = argend = NULL;
  439.  
  440.     for (newargv = argv; *newargv; newargv++)  /* for each arg... */
  441.         if ( *(*newargv)++ == QUOTECHAR )
  442.             /* strip leading quote from quoted arg */
  443.         {
  444.             if (myadd(*newargv))
  445.                 return(-1);
  446.         }
  447.         else if (wchar = strpbrk( *newargv, WILDSTRING )) {
  448.             /* attempt to expand arg with wildcard */
  449.             if (mymatch( *newargv, wchar ))
  450.                 return(-1);
  451.         }
  452.         else if (myadd( *newargv )) /* normal arg, just add */
  453.             return(-1);
  454.  
  455.     /* count the args */
  456.     for (newargc = 0, nodeptr = arghead; nodeptr;
  457.             nodeptr = nodeptr->nextnode, newargc++)
  458.             ;
  459.  
  460.     /* try to get new arg vector */
  461.     if (!(tmp = (char **)malloc(sizeof(char *)*(newargc+1))))
  462.         return(-1);
  463.  
  464.     /* the new arg vector... */
  465.     argv = tmp;
  466.  
  467.     /* the new arg count... */
  468.     argc = newargc;
  469.  
  470.     /* install the new args */
  471.     for (nodeptr = arghead; nodeptr; nodeptr = nodeptr->nextnode)
  472.         *tmp++ = nodeptr->argptr;
  473.  
  474.     /* the terminal NULL */
  475.     *tmp = NULL;
  476.  
  477.     /* free up local data */
  478.     for (nodeptr = arghead; nodeptr; nodeptr = arghead) {
  479.         arghead = arghead->nextnode;
  480.         free(nodeptr);
  481.     }
  482.  
  483.     /* return success */
  484.     return(0);
  485. }
  486.  
  487.  
  488. /***
  489. *match(arg, ptr) - [STATIC]
  490. *
  491. *Purpose:
  492. *
  493. *Entry:
  494. *
  495. *Exit:
  496. *
  497. *Exceptions:
  498. *
  499. *******************************************************************************/
  500.  
  501. static int mymatch (char *arg, char *ptr)
  502. {
  503.     char *cnew;
  504.     int length = 0;
  505.     char *all;
  506.     struct argnode *first;
  507.     int gotone = 0;
  508.  
  509.     while (ptr != arg && *ptr != SLASHCHAR && *ptr != FWDSLASHCHAR
  510.         && *ptr != COLONCHAR) {
  511.         /* find first slash or ':' before wildcard */
  512.         ptr--;
  513.     }
  514.  
  515.     if (*ptr == COLONCHAR && ptr != arg+1) /* weird name, just add it as is */
  516.         return(myadd(arg));
  517.  
  518.     if (*ptr == SLASHCHAR || *ptr == FWDSLASHCHAR
  519.         || *ptr == COLONCHAR) /* pathname */
  520.         length = ptr - arg + 1; /* length of dir prefix */
  521.  
  522.     if (cnew = myfind(arg)) { /* get the first file name */
  523.         first = argend;
  524.  
  525.         do  { /* got a file name */
  526.             if (strcmp(cnew, DOT) && strcmp(cnew, DOTDOT)) {
  527.                 if (*ptr != SLASHCHAR && *ptr != COLONCHAR
  528.                     && *ptr != FWDSLASHCHAR ) {
  529.                     /* current directory; don't need path */
  530. #ifdef _DEBUG
  531.                     if (!(arg=(char*)malloc((strlen(cnew)+1)))
  532.                         || myadd(strcpy(arg,cnew)))
  533. #else  /* _DEBUG */
  534.                     if (!(arg = strdup(cnew)) || myadd(arg))
  535. #endif  /* _DEBUG */
  536.                         return(-1);
  537.                 }
  538.                 else    /* add full pathname */
  539.                     if (!(all=(char*)malloc((length+strlen(cnew)+1)))
  540.                         || myadd(strcpy(strncpy(all,arg,length)+length,cnew)
  541.                         - length))
  542.                         return(-1);
  543.  
  544.                 gotone++;
  545.             }
  546.  
  547.         }
  548.         while (cnew = myfind(NULL));  /* get following files */
  549.  
  550.         if (gotone) {
  551.             mysort(first ? first->nextnode : arghead);
  552.             return(0);
  553.         }
  554.     }
  555.  
  556.     return(myadd(arg)); /* no match */
  557. }
  558.  
  559. /***
  560. *add(arg) - [STATIC]
  561. *
  562. *Purpose:
  563. *
  564. *Entry:
  565. *
  566. *Exit:
  567. *
  568. *Exceptions:
  569. *
  570. *******************************************************************************/
  571.  
  572. static int myadd ( char *arg )
  573. {
  574.     struct argnode *nodeptr;
  575.  
  576.     if (!(nodeptr = (struct argnode *)malloc(sizeof(struct argnode))))
  577.         return(-1);
  578.  
  579.     nodeptr->argptr = arg;
  580.     nodeptr->nextnode = NULL;
  581.  
  582.     if (arghead)
  583.         argend->nextnode = nodeptr;
  584.     else
  585.         arghead = nodeptr;
  586.  
  587.     argend = nodeptr;
  588.     return(0);
  589. }
  590.  
  591.  
  592. /***
  593. *sort(first) - [STATIC]
  594. *
  595. *Purpose:
  596. *
  597. *Entry:
  598. *
  599. *Exit:
  600. *
  601. *Exceptions:
  602. *
  603. *******************************************************************************/
  604.  
  605. static void mysort (struct argnode *first)
  606. {
  607.     struct argnode *nodeptr;
  608.     char *temp;
  609.  
  610.     if (first) /* something to sort */
  611.         while (nodeptr = first->nextnode) {
  612.             do  {
  613.                 if (stricmp(nodeptr->argptr, first->argptr) < 0) {
  614.                     temp = first->argptr;
  615.                     first->argptr = nodeptr->argptr;
  616.                     nodeptr->argptr = temp;
  617.                 }
  618.             }
  619.             while (nodeptr = nodeptr->nextnode);
  620.  
  621.             first = first->nextnode;
  622.         }
  623. }
  624.  
  625.  
  626. /***
  627. *find(pattern) - find matching filename
  628. *
  629. *Purpose:
  630. *       if argument is non-null, do a DOSFINDFIRST on that pattern
  631. *       otherwise do a DOSFINDNEXT call.  Return matching filename
  632. *       or NULL if no more matches.
  633. *
  634. *Entry:
  635. *       pattern = pointer to pattern or NULL
  636. *           (NULL means find next matching filename)
  637. *
  638. *Exit:
  639. *       returns pointer to matching file name
  640. *           or NULL if no more matches.
  641. *
  642. *Exceptions:
  643. *
  644. *******************************************************************************/
  645.  
  646. static char * myfind (char *pattern)
  647. {
  648.         char *retval;
  649.  
  650.         static HANDLE _WildFindHandle;
  651.         static LPWIN32_FIND_DATA findbuf;
  652.  
  653.         if (pattern) {
  654.             if (findbuf == NULL)
  655.                 findbuf = (LPWIN32_FIND_DATA)malloc(MAX_PATH + sizeof(*findbuf));
  656.  
  657.             if (_WildFindHandle != NULL) {
  658.                 (void)FindClose( _WildFindHandle );
  659.                 _WildFindHandle = NULL;
  660.             }
  661.  
  662.             _WildFindHandle = FindFirstFile( (LPTSTR)pattern, findbuf );
  663.             if (_WildFindHandle == (HANDLE)0xffffffff)
  664.                 return NULL;
  665.         }
  666.         else if (!FindNextFile( _WildFindHandle, findbuf )) {
  667.             (void)FindClose( _WildFindHandle );
  668.             _WildFindHandle = NULL;
  669.             return NULL;
  670.         }
  671.  
  672.         retval = findbuf->cFileName;
  673.  
  674.         return retval;
  675. }
  676.