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.

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