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.

248 lines
7.4 KiB

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