Source code of Windows XP (NT5)
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.

239 lines
6.8 KiB

  1. /***
  2. *argvw.c - create Unicode version of argv arguments
  3. *
  4. * Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * processes program command line
  8. *
  9. *Revision History:
  10. *
  11. *******************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. /***
  15. *void Parse_Cmdline(cmdstart, argv, lpstr, numargs, numbytes)
  16. *
  17. *Purpose:
  18. * Parses the command line and sets up the Unicode argv[] array.
  19. * On entry, cmdstart should point to the command line,
  20. * argv should point to memory for the argv array, lpstr
  21. * points to memory to place the text of the arguments.
  22. * If these are NULL, then no storing (only counting)
  23. * is done. On exit, *numargs has the number of
  24. * arguments (plus one for a final NULL argument),
  25. * and *numbytes has the number of bytes used in the buffer
  26. * pointed to by args.
  27. *
  28. *Entry:
  29. * LPWSTR cmdstart - pointer to command line of the form
  30. * <progname><nul><args><nul>
  31. * TCHAR **argv - where to build argv array; NULL means don't
  32. * build array
  33. * LPWSTR lpstr - where to place argument text; NULL means don't
  34. * store text
  35. *
  36. *Exit:
  37. * no return value
  38. * INT *numargs - returns number of argv entries created
  39. * INT *numbytes - number of bytes used in args buffer
  40. *
  41. *Exceptions:
  42. *
  43. *******************************************************************************/
  44. void Parse_Cmdline (
  45. LPTSTR cmdstart,
  46. LPTSTR*argv,
  47. LPTSTR lpstr,
  48. INT *numargs,
  49. INT *numbytes
  50. )
  51. {
  52. LPTSTR p;
  53. TCHAR c;
  54. INT inquote; /* 1 = inside quotes */
  55. INT copychar; /* 1 = copy char to *args */
  56. WORD numslash; /* num of backslashes seen */
  57. *numbytes = 0;
  58. *numargs = 1; /* the program name at least */
  59. /* first scan the program name, copy it, and count the bytes */
  60. p = cmdstart;
  61. if (argv)
  62. *argv++ = lpstr;
  63. /* A quoted program name is handled here. The handling is much
  64. simpler than for other arguments. Basically, whatever lies
  65. between the leading double-quote and next one, or a terminal null
  66. character is simply accepted. Fancier handling is not required
  67. because the program name must be a legal NTFS/HPFS file name.
  68. Note that the double-quote characters are not copied, nor do they
  69. contribute to numbytes. */
  70. if (*p == TEXT('\"'))
  71. {
  72. /* scan from just past the first double-quote through the next
  73. double-quote, or up to a null, whichever comes first */
  74. while ((*(++p) != TEXT('\"')) && (*p != TEXT('\0')))
  75. {
  76. *numbytes += sizeof(WCHAR);
  77. if (lpstr)
  78. *lpstr++ = *p;
  79. }
  80. /* append the terminating null */
  81. *numbytes += sizeof(WCHAR);
  82. if (lpstr)
  83. *lpstr++ = TEXT('\0');
  84. /* if we stopped on a double-quote (usual case), skip over it */
  85. if (*p == TEXT('\"'))
  86. p++;
  87. }
  88. else
  89. {
  90. /* Not a quoted program name */
  91. do {
  92. *numbytes += sizeof(WCHAR);
  93. if (lpstr)
  94. *lpstr++ = *p;
  95. c = *p++;
  96. } while (c > TEXT(' '));
  97. if (c == TEXT('\0'))
  98. {
  99. p--;
  100. }
  101. else
  102. {
  103. if (lpstr)
  104. *(lpstr - 1) = TEXT('\0');
  105. }
  106. }
  107. inquote = 0;
  108. /* loop on each argument */
  109. for ( ; ; )
  110. {
  111. if (*p)
  112. {
  113. while (*p == TEXT(' ') || *p == TEXT('\t'))
  114. ++p;
  115. }
  116. if (*p == TEXT('\0'))
  117. break; /* end of args */
  118. /* scan an argument */
  119. if (argv)
  120. *argv++ = lpstr; /* store ptr to arg */
  121. ++*numargs;
  122. /* loop through scanning one argument */
  123. for ( ; ; )
  124. {
  125. copychar = 1;
  126. /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
  127. 2N+1 backslashes + " ==> N backslashes + literal "
  128. N backslashes ==> N backslashes */
  129. numslash = 0;
  130. while (*p == TEXT('\\'))
  131. {
  132. /* count number of backslashes for use below */
  133. ++p;
  134. ++numslash;
  135. }
  136. if (*p == TEXT('\"'))
  137. {
  138. /* if 2N backslashes before, start/end quote, otherwise
  139. copy literally */
  140. if (numslash % 2 == 0)
  141. {
  142. if (inquote)
  143. if (p[1] == TEXT('\"'))
  144. p++; /* Double quote inside quoted string */
  145. else /* skip first quote char and copy second */
  146. copychar = 0;
  147. else
  148. copychar = 0; /* don't copy quote */
  149. inquote = !inquote;
  150. }
  151. numslash /= 2; /* divide numslash by two */
  152. }
  153. /* copy slashes */
  154. while (numslash--)
  155. {
  156. if (lpstr)
  157. *lpstr++ = TEXT('\\');
  158. *numbytes += sizeof(WCHAR);
  159. }
  160. /* if at end of arg, break loop */
  161. if (*p == TEXT('\0') || (!inquote && (*p == TEXT(' ') || *p == TEXT('\t'))))
  162. break;
  163. /* copy character into argument */
  164. if (copychar)
  165. {
  166. if (lpstr)
  167. *lpstr++ = *p;
  168. *numbytes += sizeof(WCHAR);
  169. }
  170. ++p;
  171. }
  172. /* null-terminate the argument */
  173. if (lpstr)
  174. *lpstr++ = TEXT('\0'); /* terminate string */
  175. *numbytes += sizeof(WCHAR);
  176. }
  177. }
  178. LPTSTR *
  179. CommandLineToArgv(
  180. OUT int *NumArgs
  181. )
  182. {
  183. LPTSTR CommandLine;
  184. TCHAR ModuleName[MAX_PATH];
  185. LPTSTR Start;
  186. INT Size;
  187. LPTSTR *Args;
  188. CommandLine = GetCommandLine();
  189. GetModuleFileName(NULL,ModuleName,MAX_PATH);
  190. //
  191. // If there's no command line at all (won't happen from cmd.exe, but
  192. // possibly another program), then we use pgmname as the command line
  193. // to parse, so that argv[0] is initialized to the program name
  194. //
  195. Start = *CommandLine ? CommandLine : ModuleName;
  196. //
  197. // Find out how much space is needed to store args,
  198. // allocate space for argv[] vector and strings,
  199. // and store args and argv ptrs in block we allocate
  200. //
  201. Parse_Cmdline(Start,NULL,NULL,NumArgs,&Size);
  202. Args = (LPTSTR *)LocalAlloc(LMEM_ZEROINIT,((*NumArgs+1) * sizeof(LPTSTR)) + Size);
  203. if(!Args) {
  204. return(NULL);
  205. }
  206. Parse_Cmdline(Start,Args,(LPTSTR)(Args + *NumArgs),NumArgs,&Size);
  207. return(Args);
  208. }