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.

430 lines
14 KiB

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