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.

367 lines
9.1 KiB

  1. /*******************************************************************************
  2. * SETARGVW.C (UNICODE argc, argv routines)
  3. *
  4. * argc / argv routines
  5. *
  6. * Copyright Citrix Systems Inc. 1995
  7. * Copyright (C) 1997-1999 Microsoft Corp.
  8. *
  9. * $Author: butchd $
  10. ******************************************************************************/
  11. /*
  12. * Include files
  13. */
  14. #include <windows.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <stdlib.h>
  18. /*
  19. * UNICODE ARGS structure and other stuff (private).
  20. */
  21. #include "setargvw.h"
  22. /*
  23. * Local function prototypes.
  24. */
  25. void args_init( ARGS * );
  26. int add_arg_to_list( WCHAR *, ARGS * );
  27. int args_trunc( ARGS * );
  28. /*
  29. * setargvW()
  30. *
  31. * Forms a standard C-runtime argc, argv parsed command line.
  32. *
  33. * ENTRY:
  34. * szModuleName (input)
  35. * Optional Windows module name. If not NULL, will be added as first
  36. * parsed argument (argv[0], argc=1).
  37. * szCmdLine (input)
  38. * Points to command line to parse into argc, argv
  39. * argc (output)
  40. * Points to int to save argument count into on exit.
  41. * argv (output)
  42. * Points to (WCHAR **) to save argv array into on exit.
  43. *
  44. * RETURNS:
  45. * ERROR_SUCCESS if ok; ERROR_xxx code if not ok.
  46. *
  47. * A typical use of this routine is by a Windows UI application to
  48. * convert a command line into the C argc & argv variables prior to calling
  49. * the utilsub.lib ParseCommandLine() function. Therefore, a companion
  50. * routine, freeargv(), allows for alloc'd memory to be freed by the caller
  51. * after use, if desired.
  52. *
  53. */
  54. int WINAPI
  55. setargvW( LPWSTR szModuleName,
  56. LPWSTR szCmdLine,
  57. int *argc,
  58. WCHAR ***argv )
  59. {
  60. int rc;
  61. WCHAR *cp;
  62. WCHAR FAR *cfp = szCmdLine;
  63. WCHAR ch, fname[_MAX_PATH];
  64. ARGS arg_data;
  65. /*
  66. * Initialize arg_data
  67. */
  68. args_init( &arg_data );
  69. /*
  70. * If present, add module name as argv[0].
  71. */
  72. if ( szModuleName ) {
  73. if ( (rc = add_arg_to_list( szModuleName, &arg_data )) != ERROR_SUCCESS )
  74. goto setargv_error;
  75. }
  76. /*
  77. * Skip leading blanks/tabs of remaining args
  78. */
  79. cp = fname;
  80. /* skip consecutive blanks and/or tabs */
  81. while ( (ch = *cfp) == L' ' || ch == L'\t' )
  82. cfp++;
  83. /*
  84. * Process remainder of command line
  85. */
  86. while ( ch = *cfp++ ) {
  87. /*
  88. * Process quoted strings.
  89. */
  90. if ( ch == '"' ) {
  91. while ( (ch = *cfp++) && ch != '"' )
  92. *cp++ = ch;
  93. if ( ch == '\0' )
  94. cfp--;
  95. /*
  96. * If we find a delimeter, process the pathname we just scanned.
  97. */
  98. } else if ( ch == ' ' || ch == '\t') {
  99. *cp = '\0';
  100. if ( (rc = add_arg_to_list( fname, &arg_data )) != ERROR_SUCCESS )
  101. goto setargv_error;
  102. cp = fname;
  103. /* skip consecutive blanks and/or tabs */
  104. while ( (ch = *cfp) == ' ' || ch == '\t')
  105. cfp++;
  106. /*
  107. * All other chars, just copy to internal buffer.
  108. */
  109. } else {
  110. *cp++ = ch;
  111. }
  112. }
  113. if ( cp != fname ) {
  114. *cp = '\0';
  115. if ( (rc = add_arg_to_list( fname, &arg_data )) != ERROR_SUCCESS )
  116. goto setargv_error;
  117. }
  118. if ( (rc = args_trunc( &arg_data )) != ERROR_SUCCESS )
  119. goto setargv_error;
  120. /*
  121. * Initialize global variables __argc and __argv
  122. */
  123. *argc = arg_data.argc;
  124. *argv = arg_data.argv;
  125. return(ERROR_SUCCESS);
  126. //--------------
  127. // Error return
  128. //--------------
  129. setargv_error:
  130. return(rc);
  131. }
  132. /*
  133. * freeargvW()
  134. *
  135. * Frees up the memory alloc'd for argv strings and argv
  136. * array itself.
  137. *
  138. * ENTER:
  139. * argv = argv array as created by this setargv() routine.
  140. *
  141. */
  142. void WINAPI
  143. freeargvW( WCHAR **argv )
  144. {
  145. free(*argv);
  146. free(argv);
  147. }
  148. /*
  149. * args_init()
  150. *
  151. * Initialize the ARGS struct passed as an argument.
  152. *
  153. * ENTER:
  154. * argp = pointer to ARGS struct
  155. *
  156. */
  157. static void
  158. args_init( ARGS *argp )
  159. {
  160. argp->argc = 0;
  161. argp->argv = NULL;
  162. argp->argvlen = 0;
  163. argp->argvp = NULL;
  164. argp->buflen = 0;
  165. argp->buf = argp->bufptr = argp->bufend = NULL;
  166. }
  167. /*
  168. * add_arg_to_list()
  169. *
  170. * This routine adds the specified argument string to the argv array,
  171. * and increments the argv pointer and argc counter.
  172. * If necessary, memory for the argument string is allocated.
  173. *
  174. * RETURNS:
  175. * ERROR_SUCCESS if ok; ERROR_NOT_ENOUGH_MEMORY if not.
  176. *
  177. */
  178. static int
  179. add_arg_to_list( WCHAR *arg_string,
  180. ARGS *argp )
  181. {
  182. int len;
  183. #ifdef notdef
  184. wprintf( L"add_arg_to_list: arg_string=%s:, argc=%d, argvp=%x",
  185. arg_string, argp->argc, argp->argvp );
  186. #endif
  187. /*
  188. * Verify we have an argv array buffer.
  189. * If we have one but it is full, expand the array.
  190. * If we can't alloc/realloc the array, return an error.
  191. */
  192. if ( !argp->argv ) {
  193. argp->argvlen = MIN_ARG_ALLOC;
  194. argp->argc = 0;
  195. argp->argv = malloc( argp->argvlen * sizeof( WCHAR *) );
  196. argp->argvp = argp->argv;
  197. } else if ( argp->argc + 1 >= argp->argvlen ) {
  198. argp->argvlen += MIN_ARG_ALLOC;
  199. argp->argv = realloc( argp->argv, argp->argvlen * sizeof(WCHAR *) );
  200. argp->argvp = argp->argv + argp->argc;
  201. }
  202. if ( !argp->argv ) {
  203. #ifdef notdef
  204. wprintf( L"add_arg_to_list: failed to (re)alloc argv buf\n" );
  205. #endif
  206. goto add_arg_to_list_error;
  207. }
  208. /*
  209. * Verify we have a string buffer to store the argument string.
  210. * If we have one but there is not room for the new arg, expand the
  211. * buffer. If we can't alloc/realloc the buffer, return an error.
  212. */
  213. len = wcslen( arg_string ) + 1;
  214. if ( !argp->buf ) {
  215. argp->buflen = MIN_BUF_ALLOC;
  216. while ( argp->buflen < len )
  217. argp->buflen += MIN_BUF_ALLOC;
  218. argp->buf = malloc( argp->buflen );
  219. argp->bufptr = argp->buf;
  220. argp->bufend = argp->buf + argp->buflen - 1;
  221. } else if ( argp->bufptr + len > argp->bufend ) {
  222. WCHAR *old_buf;
  223. int buf_offset = (int)(argp->bufptr - argp->buf);
  224. while ( argp->buflen < buf_offset + len )
  225. argp->buflen += MIN_BUF_ALLOC;
  226. old_buf = argp->buf;
  227. argp->buf = realloc( argp->buf, argp->buflen );
  228. argp->bufend = argp->buf + argp->buflen - 1;
  229. argp->bufptr = argp->buf + buf_offset;
  230. /*
  231. * If the argument string buffer moved, then we need to relocate the
  232. * argv pointers in the argv array to point to the new string locations.
  233. */
  234. if ( argp->buf != old_buf ) {
  235. WCHAR *buf_ptr, **argv_ptr;
  236. argv_ptr = argp->argv;
  237. buf_ptr = argp->buf;
  238. while ( buf_ptr != argp->bufptr ) {
  239. *argv_ptr++ = buf_ptr;
  240. buf_ptr += wcslen( buf_ptr ) + 1;
  241. }
  242. }
  243. }
  244. if ( !argp->buf ) {
  245. #ifdef notdef
  246. wprintf( L"add_arg_to_list: failed to (re)alloc string buf\n" );
  247. #endif
  248. goto add_arg_to_list_error;
  249. }
  250. /*
  251. * Add the new argument to the buffer and the argv array.
  252. * Increment the arg count, the argv pointer, and the buffer pointer.
  253. */
  254. wcscpy( argp->bufptr, arg_string );
  255. *(argp->argvp) = argp->bufptr;
  256. argp->bufptr += len;
  257. ++argp->argc;
  258. ++argp->argvp;
  259. *(argp->argvp) = NULL;
  260. return(ERROR_SUCCESS);
  261. //--------------
  262. // Error return
  263. //--------------
  264. add_arg_to_list_error:
  265. return(ERROR_NOT_ENOUGH_MEMORY);
  266. }
  267. /*
  268. * args_trunc()
  269. *
  270. * Truncate the memory used by the ARGS struct
  271. * so that unused memory is freed.
  272. *
  273. * ENTER:
  274. * argp = pointer to ARGS struct
  275. *
  276. * RETURNS:
  277. * ERROR_SUCCESS if ok; ERROR_NOT_ENOUGH_MEMORY code if not ok.
  278. *
  279. */
  280. static int
  281. args_trunc( ARGS *argp )
  282. {
  283. WCHAR *old_buf;
  284. /*
  285. * call realloc to shrink size of argv array, set argvlen = argc
  286. * to indicate no more room in argv array.
  287. */
  288. argp->argvlen = argp->argc + 1;
  289. argp->argv = realloc( argp->argv, argp->argvlen * sizeof(WCHAR *) );
  290. if ( !argp->argv )
  291. goto args_trunc_error;
  292. argp->argvp = argp->argv + argp->argc;
  293. /*
  294. * call realloc to shrink size of argument string buffer, set bufend
  295. * pointer to end of buffer to indicate buf is full.
  296. */
  297. old_buf = argp->buf;
  298. argp->buflen = (int)(argp->bufptr - argp->buf);
  299. argp->buf = realloc( argp->buf, argp->buflen );
  300. if ( !argp->buf )
  301. goto args_trunc_error;
  302. argp->bufptr = argp->buf + argp->buflen;
  303. argp->bufend = argp->buf + argp->buflen - 1;
  304. /*
  305. * If the argument string buffer moved, then we need to relocate the
  306. * argv pointers in the argv array to point to the new string locations.
  307. */
  308. if ( old_buf != argp->buf ) {
  309. WCHAR *buf_ptr, **argv_ptr;
  310. argv_ptr = argp->argv;
  311. buf_ptr = argp->buf;
  312. while ( buf_ptr != argp->bufptr ) {
  313. *argv_ptr++ = buf_ptr;
  314. buf_ptr += wcslen( buf_ptr ) + 1;
  315. }
  316. }
  317. return(ERROR_SUCCESS);
  318. //--------------
  319. // Error return
  320. //--------------
  321. args_trunc_error:
  322. return(ERROR_NOT_ENOUGH_MEMORY);
  323. }