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.

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