1 /*****************************************************************
2 * HMMER - Biological sequence analysis with profile HMMs
3 * Copyright (C) 1992-1999 Washington University School of Medicine
6 * This source code is distributed under the terms of the
7 * GNU General Public License. See the files COPYING and LICENSE
9 *****************************************************************/
11 /* RCS $Id: getopt.c,v 1.1.1.1 2005/03/22 08:34:26 cmzmasek Exp $
22 * Purpose: Portable command line option parsing with abbreviated
23 * option switches. Replaces UNIX getopt(). Using UNIX getopt()
24 * hinders portability to non-UNIX platforms, and getopt()
25 * is also limited to single letter options.
27 * Getopt() implements a superset of UNIX getopt().
28 * All of getopt()'s single-character switch behavior
29 * is emulated, and "--" by itself terminates the options.
30 * Additionally, Getopt() provides extended switches
31 * like "--youroptionhere", and Getopt() type checks
34 * Extended options must start with "--", as in "--option1".
35 * Normal options must start with "-", as in "-o".
36 * Normal options may be concatenated, as in "-a -b" == "-ab".
38 * See bottom of this .c file after #fdef GETOPT_TESTDRIVER
39 * for an example of calling Getopt().
41 * Args: argc - from main(). number of elems in argv.
42 * argv - from main(). argv[0] is the name of the command.
43 * opt - array of opt_s structures, defining option switches
44 * nopts - number of switches in opt
45 * usage - a (possibly long) string to print if usage error.
46 * ret_optind - RETURN: the index in argv[] of the next
47 * valid command-line token.
48 * ret_optname- RETURN: ptr to the name of option switch
49 * seen, or NULL if no option was seen.
50 * ret_optarg - RETURN: ptr to the optional argument, if any;
51 * NULL if option takes no argument.
53 * Return: 1 if a valid option was parsed.
54 * 0 if no option was found, and command-line parsing is complete.
55 * Die()'s here if an error is detected.
58 Getopt(int argc, char **argv, struct opt_s *opt, int nopts, char *usage,
59 int *ret_optind, char **ret_optname, char **ret_optarg)
64 static int optind = 1; /* init to 1 on first call */
65 static char *optptr = NULL; /* ptr to next valid switch */
66 int opti = 0; /* init only to silence gcc uninit warnings */
68 /* Check to see if we've run out of options.
69 * A '-' by itself is an argument (e.g. "read from stdin")
72 if (optind >= argc || argv[optind][0] != '-' || strcmp(argv[optind], "-") == 0)
80 /* Check to see if we're being told that this is the end
81 * of the options with the special "--" flag.
83 if (strcmp(argv[optind], "--") == 0)
92 /* We have a real option. Find which one it is.
93 * We handle single letter switches "-o" separately
94 * from full switches "--option", based on the "-" vs. "--"
95 * prefix -- single letter switches can be concatenated
96 * as long as they don't have arguments.
99 if (optptr == NULL && strncmp(argv[optind], "--", 2) == 0)
101 /* Use optptr to parse argument in options of form "--foo=666"
103 if ((optptr = strchr(argv[optind], '=')) != NULL)
104 { *optptr = '\0'; optptr++; }
106 arglen = strlen(argv[optind]);
108 for (i = 0; i < nopts; i++)
109 if (opt[i].single == FALSE &&
110 strncmp(opt[i].name, argv[optind], arglen) == 0)
114 if (arglen == strlen(opt[i].name)) break; /* exact match, stop now */
116 if (nmatch > 1 && arglen != strlen(opt[i].name))
117 Die("Option \"%s\" is ambiguous; please be more specific.\n%s",
118 argv[optind], usage);
120 Die("No such option \"%s\".\n%s", argv[optind], usage);
122 *ret_optname = opt[opti].name;
124 /* Set the argument, if there is one
126 if (opt[opti].argtype != sqdARG_NONE)
129 { /* --foo=666 style */
130 *ret_optarg = optptr;
134 else if (optind+1 >= argc)
135 Die("Option %s requires an argument\n%s", opt[opti].name, usage);
136 else /* "--foo 666" style */
138 *ret_optarg = argv[optind+1];
142 else /* sqdARG_NONE */
145 Die("Option %s does not take an argument\n%s", opt[opti].name, usage);
150 else /* else, a single letter option "-o" */
152 /* find the option */
154 optptr = argv[optind]+1;
155 for (opti = -1, i = 0; i < nopts; i++)
156 if (opt[i].single == TRUE && *optptr == opt[i].name[1])
159 Die("No such option \"%c\".\n%s", *optptr, usage);
160 *ret_optname = opt[opti].name;
162 /* set the argument, if there is one */
163 if (opt[opti].argtype != sqdARG_NONE)
165 if (*(optptr+1) != '\0') /* attached argument */
167 *ret_optarg = optptr+1;
170 else if (optind+1 < argc) /* unattached argument */
172 *ret_optarg = argv[optind+1];
175 else Die("Option %s requires an argument\n%s", opt[opti].name, usage);
177 optptr = NULL; /* can't concatenate after an argument */
179 else /* sqdARG_NONE */
182 if (*(optptr+1) != '\0') /* concatenation */
186 optind++; /* move to next field */
193 /* Type check the argument, if there is one
195 if (opt[opti].argtype != sqdARG_NONE)
197 if (opt[opti].argtype == sqdARG_INT && ! IsInt(*ret_optarg))
198 Die("Option %s requires an integer argument\n%s",
199 opt[opti].name, usage);
200 else if (opt[opti].argtype == sqdARG_FLOAT && ! IsReal(*ret_optarg))
201 Die("Option %s requires a numerical argument\n%s",
202 opt[opti].name, usage);
203 else if (opt[opti].argtype == sqdARG_CHAR && strlen(*ret_optarg) != 1)
204 Die("Option %s requires a single-character argument\n%s",
205 opt[opti].name, usage);
206 /* sqdARG_STRING is always ok, no type check necessary */
209 *ret_optind = optind;
215 #ifdef GETOPT_TESTDRIVER
216 /* cc -DGETOPT_TESTDRIVER -L ~/lib/squid.linux/ getopt.c -lsquid
218 struct opt_s OPTIONS[] = {
219 { "--test1", FALSE, sqdARG_INT },
220 { "--test2", FALSE, sqdARG_FLOAT },
221 { "--test3", FALSE, sqdARG_STRING },
222 { "--test4", FALSE, sqdARG_CHAR },
223 { "-a", TRUE, sqdARG_NONE },
224 { "-b", TRUE, sqdARG_INT },
226 #define NOPTIONS (sizeof(OPTIONS) / sizeof(struct opt_s))
229 main(int argc, char **argv)
235 while (Getopt(argc, argv, OPTIONS, NOPTIONS, "Usage/help here",
236 &optind, &optname, &optarg))
238 printf("Option: index: %d name: %s argument: %s\n",
239 optind, optname, optarg);
241 while (optind < argc)
243 printf("Argument: index: %d name: %s\n", optind, argv[optind]);
251 #endif /*GETOPT_TESTDRIVER*/