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.

365 lines
8.6 KiB

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