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.

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