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

  1. /***
  2. *stdargv.c - standard & wildcard _setargv routine
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       processes program command line, with or without wildcard expansion
  8. *
  9. *******************************************************************************/
  10.  
  11.  
  12. #include <cruntime.h>
  13. #include <internal.h>
  14. #include <rterr.h>
  15. #include <stdlib.h>
  16. #if defined (WILDCARD) || defined (_WIN32)
  17. #include <dos.h>
  18. #include <oscalls.h>
  19. #endif  /* defined (WILDCARD) || defined (_WIN32) */
  20. #ifdef _MBCS
  21. #include <mbctype.h>
  22. #endif  /* _MBCS */
  23. #include <tchar.h>
  24. #include <dbgint.h>
  25.  
  26. #define NULCHAR    _T('\0')
  27. #define SPACECHAR  _T(' ')
  28. #define TABCHAR    _T('\t')
  29. #define DQUOTECHAR _T('\"')
  30. #define SLASHCHAR  _T('\\')
  31.  
  32. /*
  33.  * Flag to ensure multibyte ctype table is only initialized once
  34.  */
  35. extern int __mbctype_initialized;
  36.  
  37. #ifdef WPRFLAG
  38. static void __cdecl wparse_cmdline(wchar_t *cmdstart, wchar_t **argv, wchar_t *args,
  39.         int *numargs, int *numchars);
  40. #else  /* WPRFLAG */
  41. static void __cdecl parse_cmdline(char *cmdstart, char **argv, char *args,
  42.         int *numargs, int *numchars);
  43. #endif  /* WPRFLAG */
  44.  
  45. /***
  46. *_setargv, __setargv - set up "argc" and "argv" for C programs
  47. *
  48. *Purpose:
  49. *       Read the command line and create the argv array for C
  50. *       programs.
  51. *
  52. *Entry:
  53. *       Arguments are retrieved from the program command line,
  54. *       pointed to by _acmdln.
  55. *
  56. *Exit:
  57. *       "argv" points to a null-terminated list of pointers to ASCIZ
  58. *       strings, each of which is an argument from the command line.
  59. *       "argc" is the number of arguments.  The strings are copied from
  60. *       the environment segment into space allocated on the heap/stack.
  61. *       The list of pointers is also located on the heap or stack.
  62. *       _pgmptr points to the program name.
  63. *
  64. *Exceptions:
  65. *       Terminates with out of memory error if no memory to allocate.
  66. *
  67. *******************************************************************************/
  68.  
  69. #ifdef WILDCARD
  70.  
  71. #ifdef WPRFLAG
  72. void __cdecl __wsetargv (
  73. #else  /* WPRFLAG */
  74. void __cdecl __setargv (
  75. #endif  /* WPRFLAG */
  76.  
  77. #else  /* WILDCARD */
  78.  
  79. #ifdef WPRFLAG
  80. void __cdecl _wsetargv (
  81. #else  /* WPRFLAG */
  82. void __cdecl _setargv (
  83. #endif  /* WPRFLAG */
  84.  
  85. #endif  /* WILDCARD */
  86.     void
  87.     )
  88. {
  89.         _TSCHAR *p;
  90.         _TSCHAR *cmdstart;                  /* start of command line to parse */
  91.         int numargs, numchars;
  92.  
  93.         static _TSCHAR _pgmname[ MAX_PATH ];
  94.  
  95. #if !defined (CRTDLL) && defined (_MBCS)
  96.         /* If necessary, initialize the multibyte ctype table. */
  97.         if ( __mbctype_initialized == 0 )
  98.             __initmbctable();
  99. #endif  /* !defined (CRTDLL) && defined (_MBCS) */
  100.  
  101.         /* Get the program name pointer from Win32 Base */
  102.  
  103.         GetModuleFileName( NULL, _pgmname, sizeof( _pgmname ) / sizeof(_TSCHAR));
  104. #ifdef WPRFLAG
  105.         _wpgmptr = _pgmname;
  106. #else  /* WPRFLAG */
  107.         _pgmptr = _pgmname;
  108. #endif  /* WPRFLAG */
  109.  
  110.         /* if there's no command line at all (won't happen from cmd.exe, but
  111.            possibly another program), then we use _pgmptr as the command line
  112.            to parse, so that argv[0] is initialized to the program name */
  113.  
  114. #ifdef WPRFLAG
  115.         cmdstart = (*_wcmdln == NULCHAR) ? _wpgmptr : _wcmdln;
  116. #else  /* WPRFLAG */
  117.         cmdstart = (*_acmdln == NULCHAR) ? _pgmptr : _acmdln;
  118. #endif  /* WPRFLAG */
  119.  
  120.         /* first find out how much space is needed to store args */
  121. #ifdef WPRFLAG
  122.         wparse_cmdline(cmdstart, NULL, NULL, &numargs, &numchars);
  123. #else  /* WPRFLAG */
  124.         parse_cmdline(cmdstart, NULL, NULL, &numargs, &numchars);
  125. #endif  /* WPRFLAG */
  126.  
  127.         /* allocate space for argv[] vector and strings */
  128.         p = _malloc_crt(numargs * sizeof(_TSCHAR *) + numchars * sizeof(_TSCHAR));
  129.         if (p == NULL)
  130.             _amsg_exit(_RT_SPACEARG);
  131.  
  132.         /* store args and argv ptrs in just allocated block */
  133.  
  134. #ifdef WPRFLAG
  135.         wparse_cmdline(cmdstart, (wchar_t **)p, (wchar_t *)(((char *)p) + numargs * sizeof(wchar_t *)), &numargs, &numchars);
  136. #else  /* WPRFLAG */
  137.         parse_cmdline(cmdstart, (char **)p, p + numargs * sizeof(char *), &numargs, &numchars);
  138. #endif  /* WPRFLAG */
  139.  
  140.         /* set argv and argc */
  141.         __argc = numargs - 1;
  142. #ifdef WPRFLAG
  143.         __wargv = (wchar_t **)p;
  144. #else  /* WPRFLAG */
  145.         __argv = (char **)p;
  146. #endif  /* WPRFLAG */
  147.  
  148. #ifdef WILDCARD
  149.  
  150.         /* call _[w]cwild to expand wildcards in arg vector */
  151. #ifdef WPRFLAG
  152.         if (_wcwild())
  153. #else  /* WPRFLAG */
  154.         if (_cwild())
  155. #endif  /* WPRFLAG */
  156.             _amsg_exit(_RT_SPACEARG);   /* out of space */
  157.  
  158. #endif  /* WILDCARD */
  159. }
  160.  
  161.  
  162. /***
  163. *static void parse_cmdline(cmdstart, argv, args, numargs, numchars)
  164. *
  165. *Purpose:
  166. *       Parses the command line and sets up the argv[] array.
  167. *       On entry, cmdstart should point to the command line,
  168. *       argv should point to memory for the argv array, args
  169. *       points to memory to place the text of the arguments.
  170. *       If these are NULL, then no storing (only coujting)
  171. *       is done.  On exit, *numargs has the number of
  172. *       arguments (plus one for a final NULL argument),
  173. *       and *numchars has the number of bytes used in the buffer
  174. *       pointed to by args.
  175. *
  176. *Entry:
  177. *       _TSCHAR *cmdstart - pointer to command line of the form
  178. *           <progname><nul><args><nul>
  179. *       _TSCHAR **argv - where to build argv array; NULL means don't
  180. *                       build array
  181. *       _TSCHAR *args - where to place argument text; NULL means don't
  182. *                       store text
  183. *
  184. *Exit:
  185. *       no return value
  186. *       int *numargs - returns number of argv entries created
  187. *       int *numchars - number of characters used in args buffer
  188. *
  189. *Exceptions:
  190. *
  191. *******************************************************************************/
  192.  
  193. #ifdef WPRFLAG
  194. static void __cdecl wparse_cmdline (
  195. #else  /* WPRFLAG */
  196. static void __cdecl parse_cmdline (
  197. #endif  /* WPRFLAG */
  198.     _TSCHAR *cmdstart,
  199.     _TSCHAR **argv,
  200.     _TSCHAR *args,
  201.     int *numargs,
  202.     int *numchars
  203.     )
  204. {
  205.         _TSCHAR *p;
  206.         _TUCHAR c;
  207.         int inquote;                    /* 1 = inside quotes */
  208.         int copychar;                   /* 1 = copy char to *args */
  209.         unsigned numslash;              /* num of backslashes seen */
  210.  
  211.         *numchars = 0;
  212.         *numargs = 1;                   /* the program name at least */
  213.  
  214.         /* first scan the program name, copy it, and count the bytes */
  215.         p = cmdstart;
  216.         if (argv)
  217.             *argv++ = args;
  218.  
  219. #ifdef WILDCARD
  220.         /* To handle later wild card expansion, we prefix each entry by
  221.         it's first character before quote handling.  This is done
  222.         so _[w]cwild() knows whether to expand an entry or not. */
  223.         if (args)
  224.             *args++ = *p;
  225.         ++*numchars;
  226.  
  227. #endif  /* WILDCARD */
  228.  
  229.         /* A quoted program name is handled here. The handling is much
  230.            simpler than for other arguments. Basically, whatever lies
  231.            between the leading double-quote and next one, or a terminal null
  232.            character is simply accepted. Fancier handling is not required
  233.            because the program name must be a legal NTFS/HPFS file name.
  234.            Note that the double-quote characters are not copied, nor do they
  235.            contribute to numchars. */
  236.         if ( *p == DQUOTECHAR ) {
  237.             /* scan from just past the first double-quote through the next
  238.                double-quote, or up to a null, whichever comes first */
  239.             while ( (*(++p) != DQUOTECHAR) && (*p != NULCHAR) ) {
  240.  
  241. #ifdef _MBCS
  242.                 if (_ismbblead(*p)) {
  243.                     ++*numchars;
  244.                     if ( args )
  245.                         *args++ = *p++;
  246.                 }
  247. #endif  /* _MBCS */
  248.                 ++*numchars;
  249.                 if ( args )
  250.                     *args++ = *p;
  251.             }
  252.             /* append the terminating null */
  253.             ++*numchars;
  254.             if ( args )
  255.                 *args++ = NULCHAR;
  256.  
  257.             /* if we stopped on a double-quote (usual case), skip over it */
  258.             if ( *p == DQUOTECHAR )
  259.                 p++;
  260.         }
  261.         else {
  262.             /* Not a quoted program name */
  263.             do {
  264.                 ++*numchars;
  265.                 if (args)
  266.                     *args++ = *p;
  267.  
  268.                 c = (_TUCHAR) *p++;
  269. #ifdef _MBCS
  270.                 if (_ismbblead(c)) {
  271.                     ++*numchars;
  272.                     if (args)
  273.                         *args++ = *p;   /* copy 2nd byte too */
  274.                     p++;  /* skip over trail byte */
  275.                 }
  276. #endif  /* _MBCS */
  277.  
  278.             } while ( c != SPACECHAR && c != NULCHAR && c != TABCHAR );
  279.  
  280.             if ( c == NULCHAR ) {
  281.                 p--;
  282.             } else {
  283.                 if (args)
  284.                     *(args-1) = NULCHAR;
  285.             }
  286.         }
  287.  
  288.         inquote = 0;
  289.  
  290.         /* loop on each argument */
  291.         for(;;) {
  292.  
  293.             if ( *p ) {
  294.                 while (*p == SPACECHAR || *p == TABCHAR)
  295.                     ++p;
  296.             }
  297.  
  298.             if (*p == NULCHAR)
  299.                 break;              /* end of args */
  300.  
  301.             /* scan an argument */
  302.             if (argv)
  303.                 *argv++ = args;     /* store ptr to arg */
  304.             ++*numargs;
  305.  
  306. #ifdef WILDCARD
  307.         /* To handle later wild card expansion, we prefix each entry by
  308.         it's first character before quote handling.  This is done
  309.         so _[w]cwild() knows whether to expand an entry or not. */
  310.         if (args)
  311.             *args++ = *p;
  312.         ++*numchars;
  313.  
  314. #endif  /* WILDCARD */
  315.  
  316.         /* loop through scanning one argument */
  317.         for (;;) {
  318.             copychar = 1;
  319.             /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
  320.                2N+1 backslashes + " ==> N backslashes + literal "
  321.                N backslashes ==> N backslashes */
  322.             numslash = 0;
  323.             while (*p == SLASHCHAR) {
  324.                 /* count number of backslashes for use below */
  325.                 ++p;
  326.                 ++numslash;
  327.             }
  328.             if (*p == DQUOTECHAR) {
  329.                 /* if 2N backslashes before, start/end quote, otherwise
  330.                     copy literally */
  331.                 if (numslash % 2 == 0) {
  332.                     if (inquote) {
  333.                         if (p[1] == DQUOTECHAR)
  334.                             p++;    /* Double quote inside quoted string */
  335.                         else        /* skip first quote char and copy second */
  336.                             copychar = 0;
  337.                     } else
  338.                         copychar = 0;       /* don't copy quote */
  339.  
  340.                     inquote = !inquote;
  341.                 }
  342.                 numslash /= 2;          /* divide numslash by two */
  343.             }
  344.  
  345.             /* copy slashes */
  346.             while (numslash--) {
  347.                 if (args)
  348.                     *args++ = SLASHCHAR;
  349.                 ++*numchars;
  350.             }
  351.  
  352.             /* if at end of arg, break loop */
  353.             if (*p == NULCHAR || (!inquote && (*p == SPACECHAR || *p == TABCHAR)))
  354.                 break;
  355.  
  356.             /* copy character into argument */
  357. #ifdef _MBCS
  358.             if (copychar) {
  359.                 if (args) {
  360.                     if (_ismbblead(*p)) {
  361.                         *args++ = *p++;
  362.                         ++*numchars;
  363.                     }
  364.                     *args++ = *p;
  365.                 } else {
  366.                     if (_ismbblead(*p)) {
  367.                         ++p;
  368.                         ++*numchars;
  369.                     }
  370.                 }
  371.                 ++*numchars;
  372.             }
  373.             ++p;
  374. #else  /* _MBCS */
  375.             if (copychar) {
  376.                 if (args)
  377.                     *args++ = *p;
  378.                 ++*numchars;
  379.             }
  380.             ++p;
  381. #endif  /* _MBCS */
  382.             }
  383.  
  384.             /* null-terminate the argument */
  385.  
  386.             if (args)
  387.                 *args++ = NULCHAR;          /* terminate string */
  388.             ++*numchars;
  389.         }
  390.  
  391.         /* We put one last argument in -- a null ptr */
  392.         if (argv)
  393.             *argv++ = NULL;
  394.         ++*numargs;
  395. }
  396.  
  397.  
  398.