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.

237 lines
5.5 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. argv.h
  5. Abstract:
  6. Implementation of CommandLineToArgv() API
  7. Author:
  8. Hakki T. Bostanci (hakkib) 06-Apr-2000
  9. Revision History:
  10. --*/
  11. #ifndef __ARGV_H
  12. #define __ARGV_H
  13. #include <assert.h>
  14. #ifndef ASSERT
  15. #define ASSERT assert
  16. #endif //ASSERT
  17. PTSTR *
  18. CommandLineToArgv(
  19. PCTSTR pCmdLine,
  20. int *pNumArgs
  21. );
  22. #ifdef IMPLEMENT_ARGV
  23. //////////////////////////////////////////////////////////////////////////
  24. //
  25. // Parse_Cmdline
  26. //
  27. // Stolen directly from NT sources
  28. //
  29. void Parse_Cmdline (
  30. LPCTSTR cmdstart,
  31. LPTSTR*argv,
  32. LPTSTR lpstr,
  33. INT *numargs,
  34. INT *numbytes
  35. )
  36. {
  37. LPCTSTR p;
  38. TCHAR c;
  39. INT inquote; /* 1 = inside quotes */
  40. INT copychar; /* 1 = copy char to *args */
  41. WORD numslash; /* num of backslashes seen */
  42. *numbytes = 0;
  43. *numargs = 1; /* the program name at least */
  44. /* first scan the program name, copy it, and count the bytes */
  45. p = cmdstart;
  46. if (argv)
  47. *argv++ = lpstr;
  48. /* A quoted program name is handled here. The handling is much
  49. simpler than for other arguments. Basically, whatever lies
  50. between the leading double-quote and next one, or a terminal null
  51. character is simply accepted. Fancier handling is not required
  52. because the program name must be a legal NTFS/HPFS file name.
  53. Note that the double-quote characters are not copied, nor do they
  54. contribute to numbytes. */
  55. if (*p == TEXT('\"'))
  56. {
  57. /* scan from just past the first double-quote through the next
  58. double-quote, or up to a null, whichever comes first */
  59. while ((*(++p) != TEXT('\"')) && (*p != TEXT('\0')))
  60. {
  61. *numbytes += sizeof(TCHAR);
  62. if (lpstr)
  63. *lpstr++ = *p;
  64. }
  65. /* append the terminating null */
  66. *numbytes += sizeof(TCHAR);
  67. if (lpstr)
  68. *lpstr++ = TEXT('\0');
  69. /* if we stopped on a double-quote (usual case), skip over it */
  70. if (*p == TEXT('\"'))
  71. p++;
  72. }
  73. else
  74. {
  75. /* Not a quoted program name */
  76. do {
  77. *numbytes += sizeof(TCHAR);
  78. if (lpstr)
  79. *lpstr++ = *p;
  80. c = (TCHAR) *p++;
  81. } while (c > TEXT(' '));
  82. if (c == TEXT('\0'))
  83. {
  84. p--;
  85. }
  86. else
  87. {
  88. if (lpstr)
  89. *(lpstr - 1) = TEXT('\0');
  90. }
  91. }
  92. inquote = 0;
  93. /* loop on each argument */
  94. for ( ; ; )
  95. {
  96. if (*p)
  97. {
  98. while (*p == TEXT(' ') || *p == TEXT('\t'))
  99. ++p;
  100. }
  101. if (*p == TEXT('\0'))
  102. break; /* end of args */
  103. /* scan an argument */
  104. if (argv)
  105. *argv++ = lpstr; /* store ptr to arg */
  106. ++*numargs;
  107. /* loop through scanning one argument */
  108. for ( ; ; )
  109. {
  110. copychar = 1;
  111. /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
  112. 2N+1 backslashes + " ==> N backslashes + literal "
  113. N backslashes ==> N backslashes */
  114. numslash = 0;
  115. while (*p == TEXT('\\'))
  116. {
  117. /* count number of backslashes for use below */
  118. ++p;
  119. ++numslash;
  120. }
  121. if (*p == TEXT('\"'))
  122. {
  123. /* if 2N backslashes before, start/end quote, otherwise
  124. copy literally */
  125. if (numslash % 2 == 0)
  126. {
  127. if (inquote)
  128. if (p[1] == TEXT('\"'))
  129. p++; /* Double quote inside quoted string */
  130. else /* skip first quote char and copy second */
  131. copychar = 0;
  132. else
  133. copychar = 0; /* don't copy quote */
  134. inquote = !inquote;
  135. }
  136. numslash /= 2; /* divide numslash by two */
  137. }
  138. /* copy slashes */
  139. while (numslash--)
  140. {
  141. if (lpstr)
  142. *lpstr++ = TEXT('\\');
  143. *numbytes += sizeof(TCHAR);
  144. }
  145. /* if at end of arg, break loop */
  146. if (*p == TEXT('\0') || (!inquote && (*p == TEXT(' ') || *p == TEXT('\t'))))
  147. break;
  148. /* copy character into argument */
  149. if (copychar)
  150. {
  151. if (lpstr)
  152. *lpstr++ = *p;
  153. *numbytes += sizeof(TCHAR);
  154. }
  155. ++p;
  156. }
  157. /* null-terminate the argument */
  158. if (lpstr)
  159. *lpstr++ = TEXT('\0'); /* terminate string */
  160. *numbytes += sizeof(TCHAR);
  161. }
  162. }
  163. //////////////////////////////////////////////////////////////////////////
  164. //
  165. // CommandLineToArgv
  166. //
  167. PTSTR *
  168. CommandLineToArgv(
  169. PCTSTR pCmdLine,
  170. int *pNumArgs
  171. )
  172. {
  173. ASSERT(pNumArgs);
  174. INT numbytes = 0;
  175. Parse_Cmdline(pCmdLine, 0, 0, pNumArgs, &numbytes);
  176. PTSTR *argv = (PTSTR *) LocalAlloc(
  177. LMEM_FIXED | LMEM_ZEROINIT,
  178. *pNumArgs * sizeof(PTSTR) + numbytes
  179. );
  180. if (argv)
  181. {
  182. Parse_Cmdline(
  183. pCmdLine,
  184. argv,
  185. (PTSTR) ((PBYTE) argv + *pNumArgs * sizeof(PTSTR)),
  186. pNumArgs,
  187. &numbytes
  188. );
  189. }
  190. return argv;
  191. }
  192. #endif //IMPLEMENT_ARGV
  193. #endif //__ARGV_H