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 struct option. The last element of the array
34 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 2012-08-26: Tried to make the error handling more sus4-like. The functions
75 return a colon if getopt() and friends detect a missing argument and the
76 first character of shortopts/optstring starts with a colon (`:'). If getopt()
77 and friends detect a missing argument and shortopts/optstring does not start
78 with a colon, the function returns a question mark (`?'). If it was a missing
79 argument to a short option, optopt is set to the character in question. The
80 colon goes after the ordering character (`+' or `-').
82 COPYRIGHT NOTICE AND DISCLAIMER:
84 Copyright (C) 1997 Gregory Pietsch
86 This file and the accompanying getopt.h header file are hereby placed in the
87 public domain without restrictions. Just give the author credit, don't
88 claim you wrote it or prevent anyone else from using it.
90 Gregory Pietsch's current e-mail address:
92 ****************************************************************************/
100 #define __need_getopt_newlib
106 typedef enum GETOPT_ORDERING_T
113 /* globally-defined variables */
119 /* static variables */
120 static int optwhere
= 0;
121 static int permute_from
= 0;
122 static int num_nonopts
= 0;
126 /* reverse_argv_elements: reverses num elements starting at argv */
128 reverse_argv_elements (char **argv
, int num
)
133 for (i
= 0; i
< (num
>> 1); i
++)
136 argv
[i
] = argv
[num
- i
- 1];
137 argv
[num
- i
- 1] = tmp
;
141 /* permute: swap two blocks of argv-elements given their lengths */
143 permute (char *const argv
[], int len1
, int len2
)
145 reverse_argv_elements ((char **) argv
, len1
);
146 reverse_argv_elements ((char **) argv
, len1
+ len2
);
147 reverse_argv_elements ((char **) argv
, len2
);
150 /* is_option: is this argv-element an option or the end of the option list? */
152 is_option (char *argv_element
, int only
)
154 return ((argv_element
== 0)
155 || (argv_element
[0] == '-') || (only
&& argv_element
[0] == '+'));
158 /* read_globals: read the values from the globals into a getopt_data
161 read_globals (struct getopt_data
*data
)
163 data
->optarg
= optarg
;
164 data
->optind
= optind
;
165 data
->opterr
= opterr
;
166 data
->optopt
= optopt
;
167 data
->optwhere
= optwhere
;
168 data
->permute_from
= permute_from
;
169 data
->num_nonopts
= num_nonopts
;
172 /* write_globals: write the values into the globals from a getopt_data
175 write_globals (struct getopt_data
*data
)
177 optarg
= data
->optarg
;
178 optind
= data
->optind
;
179 opterr
= data
->opterr
;
180 optopt
= data
->optopt
;
181 optwhere
= data
->optwhere
;
182 permute_from
= data
->permute_from
;
183 num_nonopts
= data
->num_nonopts
;
186 /* getopt_internal: the function that does all the dirty work
187 NOTE: to reduce the code and RAM footprint this function uses
188 fputs()/fputc() to do output to stderr instead of fprintf(). */
190 getopt_internal (int argc
, char *const argv
[], const char *shortopts
,
191 const struct option
*longopts
, int *longind
, int only
,
192 struct getopt_data
*data
)
194 GETOPT_ORDERING_T ordering
= PERMUTE
;
196 size_t match_chars
= 0;
197 char *possible_arg
= 0;
198 int longopt_match
= -1;
202 int initial_colon
= 0;
204 /* first, deal with silly parameters and easy stuff */
205 if (argc
== 0 || argv
== 0 || (shortopts
== 0 && longopts
== 0)
206 || data
->optind
>= argc
|| argv
[data
->optind
] == 0)
208 if (strcmp (argv
[data
->optind
], "--") == 0)
214 /* if this is our first time through */
215 if (data
->optind
== 0)
219 data
->permute_from
= 0;
220 data
->num_nonopts
= 0;
223 /* define ordering */
224 if (shortopts
!= 0 && (*shortopts
== '-' || *shortopts
== '+'))
226 ordering
= (*shortopts
== '-') ? RETURN_IN_ORDER
: REQUIRE_ORDER
;
230 ordering
= (getenv ("POSIXLY_CORRECT") != 0) ? REQUIRE_ORDER
: PERMUTE
;
232 /* check for initial colon in shortopts */
233 if (shortopts
!= 0 && *shortopts
== ':')
240 * based on ordering, find our next option, if we're at the beginning of
243 if (data
->optwhere
== 1)
247 default: /* shouldn't happen */
249 data
->permute_from
= data
->optind
;
250 data
->num_nonopts
= 0;
251 while (!is_option (argv
[data
->optind
], only
))
256 if (argv
[data
->optind
] == 0)
258 /* no more options */
259 data
->optind
= data
->permute_from
;
262 else if (strcmp (argv
[data
->optind
], "--") == 0)
264 /* no more options, but have to get `--' out of the way */
265 permute (argv
+ data
->permute_from
, data
->num_nonopts
, 1);
266 data
->optind
= data
->permute_from
+ 1;
270 case RETURN_IN_ORDER
:
271 if (!is_option (argv
[data
->optind
], only
))
273 data
->optarg
= argv
[data
->optind
++];
274 return (data
->optopt
= 1);
278 if (!is_option (argv
[data
->optind
], only
))
283 /* End of option list? */
284 if (argv
[data
->optind
] == 0)
287 /* we've got an option, so parse it */
289 /* first, is it a long option? */
291 && (memcmp (argv
[data
->optind
], "--", 2) == 0
292 || (only
&& argv
[data
->optind
][0] == '+')) && data
->optwhere
== 1)
294 /* handle long options */
295 if (memcmp (argv
[data
->optind
], "--", 2) == 0)
298 possible_arg
= strchr (argv
[data
->optind
] + data
->optwhere
, '=');
299 if (possible_arg
== 0)
301 /* no =, so next argv might be arg */
302 match_chars
= strlen (argv
[data
->optind
]);
303 possible_arg
= argv
[data
->optind
] + match_chars
;
304 match_chars
= match_chars
- data
->optwhere
;
307 match_chars
= (possible_arg
- argv
[data
->optind
]) - data
->optwhere
;
308 for (optindex
= 0; longopts
[optindex
].name
!= 0; ++optindex
)
311 (argv
[data
->optind
] + data
->optwhere
, longopts
[optindex
].name
,
314 /* do we have an exact match? */
315 if (match_chars
== strlen (longopts
[optindex
].name
))
317 longopt_match
= optindex
;
320 /* do any characters match? */
323 if (longopt_match
< 0)
324 longopt_match
= optindex
;
327 /* we have ambiguous options */
330 fputs (argv
[0], stderr
);
331 fputs (": option `", stderr
);
332 fputs (argv
[data
->optind
], stderr
);
333 fputs ("' is ambiguous (could be `--", stderr
);
334 fputs (longopts
[longopt_match
].name
, stderr
);
335 fputs ("' or `--", stderr
);
336 fputs (longopts
[optindex
].name
, stderr
);
337 fputs ("')\n", stderr
);
339 return (data
->optopt
= '?');
344 if (longopt_match
>= 0)
345 has_arg
= longopts
[longopt_match
].has_arg
;
348 /* if we didn't find a long option, is it a short option? */
349 if (longopt_match
< 0 && shortopts
!= 0)
351 cp
= strchr (shortopts
, argv
[data
->optind
][data
->optwhere
]);
354 /* couldn't find option in shortopts */
357 fputs (argv
[0], stderr
);
358 fputs (": invalid option -- `-", stderr
);
359 fputc (argv
[data
->optind
][data
->optwhere
], stderr
);
360 fputs ("'\n", stderr
);
363 if (argv
[data
->optind
][data
->optwhere
] == '\0')
368 return (data
->optopt
= '?');
370 has_arg
= ((cp
[1] == ':')
371 ? ((cp
[2] == ':') ? OPTIONAL_ARG
: REQUIRED_ARG
) : NO_ARG
);
372 possible_arg
= argv
[data
->optind
] + data
->optwhere
+ 1;
376 /* get argument and reset data->optwhere */
381 if (*possible_arg
== '=')
383 data
->optarg
= (*possible_arg
!= '\0') ? possible_arg
: 0;
387 if (*possible_arg
== '=')
389 if (*possible_arg
!= '\0')
391 data
->optarg
= possible_arg
;
394 else if (data
->optind
+ 1 >= argc
)
398 fputs (argv
[0], stderr
);
399 fputs (": argument required for option `-", stderr
);
400 if (longopt_match
>= 0)
403 fputs (longopts
[longopt_match
].name
, stderr
);
404 data
->optopt
= initial_colon
? ':' : '\?';
411 fputs ("'\n", stderr
);
414 return initial_colon
? ':' : '\?';
418 data
->optarg
= argv
[data
->optind
+ 1];
423 default: /* shouldn't happen */
425 if (longopt_match
< 0)
428 if (argv
[data
->optind
][data
->optwhere
] == '\0')
437 /* do we have to permute or otherwise modify data->optind? */
438 if (ordering
== PERMUTE
&& data
->optwhere
== 1 && data
->num_nonopts
!= 0)
440 permute (argv
+ data
->permute_from
, data
->num_nonopts
, 1 + arg_next
);
441 data
->optind
= data
->permute_from
+ 1 + arg_next
;
443 else if (data
->optwhere
== 1)
444 data
->optind
= data
->optind
+ 1 + arg_next
;
447 if (longopt_match
>= 0)
450 *longind
= longopt_match
;
451 if (longopts
[longopt_match
].flag
!= 0)
453 *(longopts
[longopt_match
].flag
) = longopts
[longopt_match
].val
;
457 return longopts
[longopt_match
].val
;
464 getopt (int argc
, char *const argv
[], const char *optstring
)
466 struct getopt_data data
;
469 read_globals (&data
);
470 r
= getopt_internal (argc
, argv
, optstring
, 0, 0, 0, &data
);
471 write_globals (&data
);
476 getopt_long (int argc
, char *const argv
[], const char *shortopts
,
477 const struct option
*longopts
, int *longind
)
479 struct getopt_data data
;
482 read_globals (&data
);
483 r
= getopt_internal (argc
, argv
, shortopts
, longopts
, longind
, 0, &data
);
484 write_globals (&data
);
489 getopt_long_only (int argc
, char *const argv
[], const char *shortopts
,
490 const struct option
*longopts
, int *longind
)
492 struct getopt_data data
;
495 read_globals (&data
);
496 r
= getopt_internal (argc
, argv
, shortopts
, longopts
, longind
, 1, &data
);
497 write_globals (&data
);
502 __getopt_r (int argc
, char *const argv
[], const char *optstring
,
503 struct getopt_data
*data
)
505 return getopt_internal (argc
, argv
, optstring
, 0, 0, 0, data
);
509 __getopt_long_r (int argc
, char *const argv
[], const char *shortopts
,
510 const struct option
*longopts
, int *longind
,
511 struct getopt_data
*data
)
513 return getopt_internal (argc
, argv
, shortopts
, longopts
, longind
, 0, data
);
517 __getopt_long_only_r (int argc
, char *const argv
[], const char *shortopts
,
518 const struct option
*longopts
, int *longind
,
519 struct getopt_data
*data
)
521 return getopt_internal (argc
, argv
, shortopts
, longopts
, longind
, 1, data
);
524 #endif /* !HAVE_GETOPT */
526 /* end of file GETOPT.C */