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.

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