cmdline.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /****************************************************************************
  2. *
  3. * ========================================================================
  4. *
  5. * The contents of this file are subject to the SciTech MGL Public
  6. * License Version 1.0 (the "License"); you may not use this file
  7. * except in compliance with the License. You may obtain a copy of
  8. * the License at http://www.scitechsoft.com/mgl-license.txt
  9. *
  10. * Software distributed under the License is distributed on an
  11. * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  12. * implied. See the License for the specific language governing
  13. * rights and limitations under the License.
  14. *
  15. * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
  16. *
  17. * The Initial Developer of the Original Code is SciTech Software, Inc.
  18. * All Rights Reserved.
  19. *
  20. * ========================================================================
  21. *
  22. * Language: ANSI C
  23. * Environment: any
  24. *
  25. * Description: This module contains code to parse the command line,
  26. * extracting options and parameters in standard System V
  27. * style.
  28. *
  29. ****************************************************************************/
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <ctype.h>
  33. #include "cmdline.h"
  34. /*------------------------- Global variables ------------------------------*/
  35. int nextargv = 1; /* Index into argv array */
  36. char *nextchar = NULL; /* Pointer to next character */
  37. /*-------------------------- Implementation -------------------------------*/
  38. #define IS_SWITCH_CHAR(c) ((c) == '-')
  39. #define IS_NOT_SWITCH_CHAR(c) ((c) != '-')
  40. /****************************************************************************
  41. DESCRIPTION:
  42. Parse the command line for specific options
  43. HEADER:
  44. cmdline.h
  45. PARAMETERS:
  46. argc - Value passed to program through argc variable
  47. argv - Pointer to the argv array passed to the program
  48. format - A string representing the expected format of the command line
  49. argument - Pointer to optional argument on command line
  50. RETURNS:
  51. Character code representing the next option parsed from the command line by
  52. getcmdopt. Returns ALLDONE (-1) when there are no more parameters to be parsed
  53. on the command line, PARAMETER (-2) when the argument being parsed is a
  54. parameter and not an option switch and lastly INVALID (-3) if an error
  55. occured while parsing the command line.
  56. REMARKS:
  57. Function to parse the command line option switches in UNIX System V style.
  58. When getcmdopt is called, it returns the character code of the next valid
  59. option that is parsed from the command line as specified by the Format
  60. string. The format string should be in the following form:
  61. "abcd:e:f:"
  62. where a,b and c represent single switch style options and the character
  63. code returned by getcmdopt is the only value returned. Also d, e and f
  64. represent options that expect arguments immediately after them on the
  65. command line. The argument that follows the option on the command line is
  66. returned via a reference in the pointer argument. Thus a valid command line
  67. for this format string might be:
  68. myprogram -adlines -b -f format infile outfile
  69. where a and b will be returned as single character options with no argument,
  70. while d is returned with the argument lines and f is returned with the
  71. argument format.
  72. When getcmdopt returns with PARAMETER (we attempted to parse a paramter, not
  73. an option), the global variable NextArgv will hold an index in the argv
  74. array to the argument on the command line AFTER the options, ie in the
  75. above example the string 'infile'. If the parameter is successfully used,
  76. NextArgv should be incremented and getcmdopt can be called again to parse any
  77. more options. Thus you can also have options interspersed throught the
  78. command line. eg:
  79. myprogram -adlines infile -b outfile -f format
  80. can be made to be a valid form of the above command line.
  81. ****************************************************************************/
  82. int getcmdopt(
  83. int argc,
  84. char **argv,
  85. char *format,
  86. char **argument)
  87. {
  88. char ch;
  89. char *formatchar;
  90. if (argc > nextargv) {
  91. if (nextchar == NULL) {
  92. nextchar = argv[nextargv]; /* Index next argument */
  93. if (nextchar == NULL) {
  94. nextargv++;
  95. return ALLDONE; /* No more options */
  96. }
  97. if (IS_NOT_SWITCH_CHAR(*nextchar)) {
  98. nextchar = NULL;
  99. return PARAMETER; /* We have a parameter */
  100. }
  101. nextchar++; /* Move past switch operator */
  102. if (IS_SWITCH_CHAR(*nextchar)) {
  103. nextchar = NULL;
  104. return INVALID; /* Ignore rest of line */
  105. }
  106. }
  107. if ((ch = *(nextchar++)) == 0) {
  108. nextchar = NULL;
  109. return INVALID; /* No options on line */
  110. }
  111. if (ch == ':' || (formatchar = strchr(format, ch)) == NULL)
  112. return INVALID;
  113. if (*(++formatchar) == ':') { /* Expect an argument after option */
  114. nextargv++;
  115. if (*nextchar == 0) {
  116. if (argc <= nextargv)
  117. return INVALID;
  118. nextchar = argv[nextargv++];
  119. }
  120. *argument = nextchar;
  121. nextchar = NULL;
  122. }
  123. else { /* We have a switch style option */
  124. if (*nextchar == 0) {
  125. nextargv++;
  126. nextchar = NULL;
  127. }
  128. *argument = NULL;
  129. }
  130. return ch; /* return the option specifier */
  131. }
  132. nextchar = NULL;
  133. nextargv++;
  134. return ALLDONE; /* no arguments on command line */
  135. }
  136. /****************************************************************************
  137. PARAMETERS:
  138. optarr - Description for the option we are parsing
  139. argument - String to parse
  140. RETURNS:
  141. INVALID on error, ALLDONE on success.
  142. REMARKS:
  143. Parses the argument string depending on the type of argument that is
  144. expected, filling in the argument for that option. Note that to parse a
  145. string, we simply return a pointer to argument.
  146. ****************************************************************************/
  147. static int parse_option(
  148. Option *optarr,
  149. char *argument)
  150. {
  151. int num_read;
  152. switch ((int)(optarr->type)) {
  153. case OPT_INTEGER:
  154. num_read = sscanf(argument,"%d",(int*)optarr->arg);
  155. break;
  156. case OPT_HEX:
  157. num_read = sscanf(argument,"%x",(int*)optarr->arg);
  158. break;
  159. case OPT_OCTAL:
  160. num_read = sscanf(argument,"%o",(int*)optarr->arg);
  161. break;
  162. case OPT_UNSIGNED:
  163. num_read = sscanf(argument,"%u",(uint*)optarr->arg);
  164. break;
  165. case OPT_LINTEGER:
  166. num_read = sscanf(argument,"%ld",(long*)optarr->arg);
  167. break;
  168. case OPT_LHEX:
  169. num_read = sscanf(argument,"%lx",(long*)optarr->arg);
  170. break;
  171. case OPT_LOCTAL:
  172. num_read = sscanf(argument,"%lo",(long*)optarr->arg);
  173. break;
  174. case OPT_LUNSIGNED:
  175. num_read = sscanf(argument,"%lu",(ulong*)optarr->arg);
  176. break;
  177. case OPT_FLOAT:
  178. num_read = sscanf(argument,"%f",(float*)optarr->arg);
  179. break;
  180. case OPT_DOUBLE:
  181. num_read = sscanf(argument,"%lf",(double*)optarr->arg);
  182. break;
  183. case OPT_LDOUBLE:
  184. num_read = sscanf(argument,"%Lf",(long double*)optarr->arg);
  185. break;
  186. case OPT_STRING:
  187. num_read = 1; /* This always works */
  188. *((char**)optarr->arg) = argument;
  189. break;
  190. default:
  191. return INVALID;
  192. }
  193. if (num_read == 0)
  194. return INVALID;
  195. else
  196. return ALLDONE;
  197. }
  198. /****************************************************************************
  199. HEADER:
  200. cmdline.h
  201. PARAMETERS:
  202. argc - Number of arguments on command line
  203. argv - Array of command line arguments
  204. num_opt - Number of options in option array
  205. optarr - Array to specify how to parse the command line
  206. do_param - Routine to handle a command line parameter
  207. RETURNS:
  208. ALLDONE, INVALID or HELP
  209. REMARKS:
  210. Function to parse the command line according to a table of options. This
  211. routine calls getcmdopt above to parse each individual option and attempts
  212. to parse each option into a variable of the specified type. The routine
  213. can parse integers and long integers in either decimal, octal, hexadecimal
  214. notation, unsigned integers and unsigned longs, strings and option switches.
  215. Option switches are simply boolean variables that get turned on if the
  216. switch was parsed.
  217. Parameters are extracted from the command line by calling a user supplied
  218. routine do_param() to handle each parameter as it is encountered. The
  219. routine do_param() should accept a pointer to the parameter on the command
  220. line and an integer representing how many parameters have been encountered
  221. (ie: 1 if this is the first parameter, 10 if it is the 10th etc), and return
  222. ALLDONE upon successfully parsing it or INVALID if the parameter was invalid.
  223. We return either ALLDONE if all the options were successfully parsed,
  224. INVALID if an invalid option was encountered or HELP if any of -h, -H or
  225. -? were present on the command line.
  226. ****************************************************************************/
  227. int getargs(
  228. int argc,
  229. char *argv[],
  230. int num_opt,
  231. Option optarr[],
  232. int (*do_param)(
  233. char *param,
  234. int num))
  235. {
  236. int i,opt;
  237. char *argument;
  238. int param_num = 1;
  239. char cmdstr[MAXARG*2 + 4];
  240. /* Build the command string from the array of options */
  241. strcpy(cmdstr,"hH?");
  242. for (i = 0,opt = 3; i < num_opt; i++,opt++) {
  243. cmdstr[opt] = optarr[i].opt;
  244. if (optarr[i].type != OPT_SWITCH) {
  245. cmdstr[++opt] = ':';
  246. }
  247. }
  248. cmdstr[opt] = '\0';
  249. for (;;) {
  250. opt = getcmdopt(argc,argv,cmdstr,&argument);
  251. switch (opt) {
  252. case 'H':
  253. case 'h':
  254. case '?':
  255. return HELP;
  256. case ALLDONE:
  257. return ALLDONE;
  258. case INVALID:
  259. return INVALID;
  260. case PARAMETER:
  261. if (do_param == NULL)
  262. return INVALID;
  263. if (do_param(argv[nextargv],param_num) == INVALID)
  264. return INVALID;
  265. nextargv++;
  266. param_num++;
  267. break;
  268. default:
  269. /* Search for the option in the option array. We are
  270. * guaranteed to find it.
  271. */
  272. for (i = 0; i < num_opt; i++) {
  273. if (optarr[i].opt == opt)
  274. break;
  275. }
  276. if (optarr[i].type == OPT_SWITCH)
  277. *((ibool*)optarr[i].arg) = true;
  278. else {
  279. if (parse_option(&optarr[i],argument) == INVALID)
  280. return INVALID;
  281. }
  282. break;
  283. }
  284. }
  285. }
  286. /****************************************************************************
  287. HEADER:
  288. cmdline.h
  289. PARAMETERS:
  290. num_opt - Number of options in the table
  291. optarr - Table of option descriptions
  292. REMARKS:
  293. Prints the description of each option in a standard format to the standard
  294. output device. The description for each option is obtained from the table
  295. of options.
  296. ****************************************************************************/
  297. void print_desc(
  298. int num_opt,
  299. Option optarr[])
  300. {
  301. int i;
  302. for (i = 0; i < num_opt; i++) {
  303. if (optarr[i].type == OPT_SWITCH)
  304. printf(" -%c %s\n",optarr[i].opt,optarr[i].desc);
  305. else
  306. printf(" -%c<arg> %s\n",optarr[i].opt,optarr[i].desc);
  307. }
  308. }
  309. /****************************************************************************
  310. HEADER:
  311. cmdline.h
  312. PARAMETERS:
  313. moduleName - Module name for program
  314. cmdLine - Command line to parse
  315. pargc - Pointer to 'argc' parameter
  316. pargv - Pointer to 'argv' parameter
  317. maxArgc - Maximum argv array index
  318. REMARKS:
  319. Parses a command line from a single string into the C style 'argc' and
  320. 'argv' format. Most useful for Windows programs where the command line
  321. is passed in verbatim.
  322. ****************************************************************************/
  323. int parse_commandline(
  324. char *moduleName,
  325. char *cmdLine,
  326. int *pargc,
  327. char *argv[],
  328. int maxArgv)
  329. {
  330. static char str[512];
  331. static char filename[260];
  332. char *prevWord = NULL;
  333. ibool inQuote = FALSE;
  334. ibool noStrip = FALSE;
  335. int argc;
  336. argc = 0;
  337. strcpy(filename,moduleName);
  338. argv[argc++] = filename;
  339. cmdLine = strncpy(str, cmdLine, sizeof(str)-1);
  340. while (*cmdLine) {
  341. switch (*cmdLine) {
  342. case '"' :
  343. if (prevWord != NULL) {
  344. if (inQuote) {
  345. if (!noStrip)
  346. *cmdLine = '\0';
  347. argv [argc++] = prevWord;
  348. prevWord = NULL;
  349. }
  350. else
  351. noStrip = TRUE;
  352. }
  353. inQuote = !inQuote;
  354. break;
  355. case ' ' :
  356. case '\t' :
  357. if (!inQuote) {
  358. if (prevWord != NULL) {
  359. *cmdLine = '\0';
  360. argv [argc++] = prevWord;
  361. prevWord = NULL;
  362. noStrip = FALSE;
  363. }
  364. }
  365. break;
  366. default :
  367. if (prevWord == NULL)
  368. prevWord = cmdLine;
  369. break;
  370. }
  371. if (argc >= maxArgv - 1)
  372. break;
  373. cmdLine++;
  374. }
  375. if ((prevWord != NULL || (inQuote && prevWord != NULL)) && argc < maxArgv - 1) {
  376. *cmdLine = '\0';
  377. argv [argc++] = prevWord;
  378. }
  379. argv[argc] = NULL;
  380. /* Return updated parameters */
  381. return (*pargc = argc);
  382. }