1 /****************************************************************************
3 getopt.c - Read command line options
5 AUTHOR: Gregory Pietsch
6 CREATED Fri Jan 10 21:13:05 1997
10 The getopt() function parses the command line arguments. Its arguments argc
11 and argv are the argument count and array as passed to the main() function
12 on program invocation. The argument optstring is a list of available option
13 characters. If such a character is followed by a colon (`:'), the option
14 takes an argument, which is placed in optarg. If such a character is
15 followed by two colons, the option takes an optional argument, which is
16 placed in optarg. If the option does not take an argument, optarg is NULL.
18 The external variable optind is the index of the next array element of argv
19 to be processed; it communicates from one call to the next which element to
22 The getopt_long() function works like getopt() except that it also accepts
23 long options started by two dashes `--'. If these take values, it is either
32 It takes the additional arguments longopts which is a pointer to the first
33 element of an array of type GETOPT_LONG_OPTION_T. The last element of the
34 array has to be filled with NULL for the name field.
36 The longind pointer points to the index of the current long option relative
37 to longopts if it is non-NULL.
39 The getopt() function returns the option character if the option was found
40 successfully, `:' if there was a missing parameter for one of the options,
41 `?' for an unknown option character, and EOF for the end of the option list.
43 The getopt_long() function's return value is described in the header file.
45 The function getopt_long_only() is identical to getopt_long(), except that a
46 plus sign `+' can introduce long options as well as `--'.
48 The following describes how to deal with options that follow non-option
51 If the caller did not specify anything, the default is REQUIRE_ORDER if the
52 environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise.
54 REQUIRE_ORDER means don't recognize them as options; stop option processing
55 when the first non-option is seen. This is what Unix does. This mode of
56 operation is selected by either setting the environment variable
57 POSIXLY_CORRECT, or using `+' as the first character of the optstring
60 PERMUTE is the default. We permute the contents of ARGV as we scan, so that
61 eventually all the non-options are at the end. This allows options to be
62 given in any order, even with programs that were not written to expect this.
64 RETURN_IN_ORDER is an option available to programs that were written to
65 expect options and other argv-elements in any order and that care about the
66 ordering of the two. We describe each non-option argv-element as if it were
67 the argument of an option with character code 1. Using `-' as the first
68 character of the optstring parameter selects this mode of operation.
70 The special argument `--' forces an end of option-scanning regardless of the
71 value of ordering. In the case of RETURN_IN_ORDER, only `--' can cause
72 getopt() and friends to return EOF with optind != argc.
74 COPYRIGHT NOTICE AND DISCLAIMER:
76 Copyright (C) 1997 Gregory Pietsch
78 This file and the accompanying getopt.h header file are hereby placed in the
79 public domain without restrictions. Just give the author credit, don't
80 claim you wrote it or prevent anyone else from using it.
82 Gregory Pietsch's current e-mail address:
84 ****************************************************************************/
97 typedef enum GETOPT_ORDERING_T
104 /* globally-defined variables */
112 /* reverse_argv_elements: reverses num elements starting at argv */
114 reverse_argv_elements (char **argv, int num)
119 for (i = 0; i < (num >> 1); i++)
122 argv[i] = argv[num - i - 1];
123 argv[num - i - 1] = tmp;
127 /* permute: swap two blocks of argv-elements given their lengths */
129 permute (char **argv, int len1, int len2)
131 reverse_argv_elements (argv, len1);
132 reverse_argv_elements (argv, len1 + len2);
133 reverse_argv_elements (argv, len2);
136 /* is_option: is this argv-element an option or the end of the option list? */
138 is_option (char *argv_element, int only)
140 return ((argv_element == NULL)
141 || (argv_element[0] == '-') || (only && argv_element[0] == '+'));
144 /* getopt_internal: the function that does all the dirty work */
146 getopt_internal (int argc, char **argv, char *shortopts,
147 GETOPT_LONG_OPTION_T * longopts, int *longind, int only)
149 GETOPT_ORDERING_T ordering = PERMUTE;
150 static size_t optwhere = 0;
151 size_t permute_from = 0;
154 size_t match_chars = 0;
155 char *possible_arg = NULL;
156 int longopt_match = -1;
161 /* first, deal with silly parameters and easy stuff */
162 if (argc == 0 || argv == NULL || (shortopts == NULL && longopts == NULL))
163 return (optopt = '?');
164 if (optind >= argc || argv[optind] == NULL)
166 if (strcmp (argv[optind], "--") == 0)
171 /* if this is our first time through */
173 optind = optwhere = 1;
175 /* define ordering */
176 if (shortopts != NULL && (*shortopts == '-' || *shortopts == '+'))
178 ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER;
182 ordering = (getenv ("POSIXLY_CORRECT") != NULL) ? REQUIRE_ORDER : PERMUTE;
185 * based on ordering, find our next option, if we're at the beginning of
193 permute_from = optind;
195 while (!is_option (argv[optind], only))
200 if (argv[optind] == NULL)
202 /* no more options */
203 optind = permute_from;
206 else if (strcmp (argv[optind], "--") == 0)
208 /* no more options, but have to get `--' out of the way */
209 permute (argv + permute_from, num_nonopts, 1);
210 optind = permute_from + 1;
214 case RETURN_IN_ORDER:
215 if (!is_option (argv[optind], only))
217 optarg = argv[optind++];
222 if (!is_option (argv[optind], only))
227 /* we've got an option, so parse it */
229 /* first, is it a long option? */
231 && (memcmp (argv[optind], "--", 2) == 0
232 || (only && argv[optind][0] == '+')) && optwhere == 1)
234 /* handle long options */
235 if (memcmp (argv[optind], "--", 2) == 0)
238 possible_arg = strchr (argv[optind] + optwhere, '=');
239 if (possible_arg == NULL)
241 /* no =, so next argv might be arg */
242 match_chars = strlen (argv[optind]);
243 possible_arg = argv[optind] + match_chars;
244 match_chars = match_chars - optwhere;
247 match_chars = (possible_arg - argv[optind]) - optwhere;
248 for (optindex = 0; longopts[optindex].name != NULL; optindex++)
250 if (memcmp (argv[optind] + optwhere,
251 longopts[optindex].name, match_chars) == 0)
253 /* do we have an exact match? */
254 if (match_chars == strlen (longopts[optindex].name))
256 longopt_match = optindex;
259 /* do any characters match? */
262 if (longopt_match < 0)
263 longopt_match = optindex;
266 /* we have ambiguous options */
268 fprintf (stderr, "%s: option `%s' is ambiguous "
269 "(could be `--%s' or `--%s')\n",
272 longopts[longopt_match].name,
273 longopts[optindex].name);
274 return (optopt = '?');
279 if (longopt_match >= 0)
280 has_arg = longopts[longopt_match].has_arg;
282 /* if we didn't find a long option, is it a short option? */
283 if (longopt_match < 0 && shortopts != NULL)
285 cp = strchr (shortopts, argv[optind][optwhere]);
288 /* couldn't find option in shortopts */
291 "%s: invalid option -- `-%c'\n",
292 argv[0], argv[optind][optwhere]);
294 if (argv[optind][optwhere] == '\0')
299 return (optopt = '?');
301 has_arg = ((cp[1] == ':')
302 ? ((cp[2] == ':') ? OPTIONAL_ARG : required_argument) : no_argument);
303 possible_arg = argv[optind] + optwhere + 1;
306 /* get argument and reset optwhere */
311 if (*possible_arg == '=')
313 if (*possible_arg != '\0')
315 optarg = possible_arg;
321 case required_argument:
322 if (*possible_arg == '=')
324 if (*possible_arg != '\0')
326 optarg = possible_arg;
329 else if (optind + 1 >= argc)
333 fprintf (stderr, "%s: argument required for option `", argv[0]);
334 if (longopt_match >= 0)
335 fprintf (stderr, "--%s'\n", longopts[longopt_match].name);
337 fprintf (stderr, "-%c'\n", *cp);
340 return (optopt = ':');
344 optarg = argv[optind + 1];
350 if (longopt_match < 0)
353 if (argv[optind][optwhere] == '\0')
362 /* do we have to permute or otherwise modify optind? */
363 if (ordering == PERMUTE && optwhere == 1 && num_nonopts != 0)
365 permute (argv + permute_from, num_nonopts, 1 + arg_next);
366 optind = permute_from + 1 + arg_next;
368 else if (optwhere == 1)
369 optind = optind + 1 + arg_next;
372 if (longopt_match >= 0)
375 *longind = longopt_match;
376 if (longopts[longopt_match].flag != NULL)
378 *(longopts[longopt_match].flag) = longopts[longopt_match].val;
382 return longopts[longopt_match].val;
390 getopt (int argc, char **argv, char *optstring)
392 return getopt_internal (argc, argv, optstring, NULL, NULL, 0);
397 getopt_long (int argc, char **argv, const char *shortopts,
398 const GETOPT_LONG_OPTION_T * longopts, int *longind)
400 return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)longopts, longind, 0);
404 getopt_long_only (int argc, char **argv, const char *shortopts,
405 const GETOPT_LONG_OPTION_T * longopts, int *longind)
407 return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)longopts, longind, 1);
410 /* end of file GETOPT.C */