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.

265 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. 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. #include "StrSafe.h"
  17. namespace ShimLib
  18. {
  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. * LPSTR 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. * LPSTR 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_CmdlineA (
  50. LPCSTR cmdstart,
  51. LPSTR* argv,
  52. LPSTR lpstr,
  53. INT * numargs,
  54. INT * numbytes
  55. )
  56. {
  57. LPCSTR p;
  58. char 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(char);
  82. if (lpstr)
  83. *lpstr++ = *p;
  84. }
  85. /* append the terminating null */
  86. *numbytes += sizeof(char);
  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(char);
  98. if (lpstr)
  99. *lpstr++ = *p;
  100. c = (char) *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(char);
  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(char);
  174. }
  175. ++p;
  176. }
  177. /* null-terminate the argument */
  178. if (lpstr)
  179. *lpstr++ = TEXT('\0'); /* terminate string */
  180. *numbytes += sizeof(char);
  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. LPSTR * _CommandLineToArgvA (LPCSTR lpCmdLine, int*pNumArgs)
  203. {
  204. LPSTR*argv_U;
  205. LPCSTR cmdstart; /* start of command line to parse */
  206. INT numbytes;
  207. if (pNumArgs == NULL) {
  208. SetLastError(ERROR_INVALID_PARAMETER);
  209. return NULL;
  210. }
  211. cmdstart = lpCmdLine;
  212. /* first find out how much space is needed to store args */
  213. Parse_CmdlineA(cmdstart, NULL, NULL, pNumArgs, &numbytes);
  214. /* allocate space for argv[] vector and strings */
  215. argv_U = (LPSTR*)LocalAlloc(LMEM_ZEROINIT,
  216. (*pNumArgs + 1) * sizeof(LPSTR) + numbytes);
  217. if (!argv_U) {
  218. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  219. return (NULL);
  220. }
  221. /* store args and argv ptrs in just allocated block */
  222. Parse_CmdlineA(cmdstart,
  223. argv_U,
  224. (LPSTR)(((LPBYTE)argv_U) + *pNumArgs * sizeof(LPSTR)),
  225. pNumArgs,
  226. &numbytes);
  227. return argv_U;
  228. }
  229. }; // end of namespace ShimLib