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 ****************************************************************************/
92 #include "cli-option-parser.h"
104 /* Initialize CLI option parser state by default values. */
106 cli_option_parser_state_initialize (struct cli_option_parser_state
*state
)
108 state
->argument
= NULL
;
115 /* Reverses num elements starting at argv. */
117 reverse_argv_elements (char **argv
, int num
)
122 for (i
= 0; i
< (num
>> 1); i
++)
125 argv
[i
] = argv
[num
- i
- 1];
126 argv
[num
- i
- 1] = tmp
;
130 /* Swap two blocks of argv-elements given their lengths. */
132 permute (char **argv
, int len1
, int len2
)
134 reverse_argv_elements (argv
, len1
);
135 reverse_argv_elements (argv
, len1
+ len2
);
136 reverse_argv_elements (argv
, len2
);
139 /* Is this argv-element an option or the end of the option list? */
141 is_option (char *argv_element
)
143 return ((argv_element
== NULL
) || (argv_element
[0] == '-'));
147 cli_option_parse (struct cli_option_parser_state
*state
,
148 int argc
, char **argv
,
149 const char *shortopts
,
151 struct cli_option
*longopts
,
154 enum ordering ordering
= PERMUTE
;
155 int permute_from
= 0;
158 char *possible_arg
= NULL
;
159 int longopt_match
= -1;
160 int has_argument
= -1;
164 if (state
->index
>= argc
|| argv
[state
->index
] == NULL
)
167 if (strcmp (argv
[state
->index
], "--") == 0)
173 /* If this is our first time through. */
174 if (state
->index
== 0)
175 state
->index
= state
->where
= 1;
177 /* Define ordering. */
181 ordering
= RETURN_IN_ORDER
;
185 ordering
= REQUIRE_ORDER
;
189 ordering
= (getenv ("POSIXLY_CORRECT") != NULL
) ? REQUIRE_ORDER
: PERMUTE
;
193 /* Based on ordering, find our next option, if we're at the beginning of one. */
194 if (state
->where
== 1)
199 permute_from
= state
->index
;
202 while (!is_option (argv
[state
->index
]))
208 if (argv
[state
->index
] == NULL
)
210 /* No more options. */
211 state
->index
= permute_from
;
214 else if (strcmp (argv
[state
->index
], "--") == 0)
216 /* No more options, but have to get `--' out of the way. */
217 permute (argv
+ permute_from
, num_nonopts
, 1);
218 state
->index
= permute_from
+ 1;
223 case RETURN_IN_ORDER
:
224 if (!is_option (argv
[state
->index
]))
226 state
->argument
= argv
[state
->index
++];
228 return state
->option
;
233 if (!is_option (argv
[state
->index
]))
240 /* We have got an option, so parse it. */
242 /* First, is it a long option? */
243 if (memcmp (argv
[state
->index
], "--", 2) == 0 && state
->where
== 1)
245 /* Handle long options. */
247 possible_arg
= strchr (argv
[state
->index
] + state
->where
, '=');
249 if (possible_arg
== NULL
)
251 /* No =, so next argv might be argument. */
252 size_t len
= strlen (argv
[state
->index
]);
256 /* We have option which name is too long. */
258 error (_("option `%s' is too long"), argv
[state
->index
]);
260 return (state
->option
= '?');
263 match_chars
= (int) len
;
264 possible_arg
= argv
[state
->index
] + match_chars
;
265 match_chars
-= state
->where
;
268 match_chars
= (int) (possible_arg
- argv
[state
->index
]) - state
->where
;
270 for (int optindex
= 0; optindex
< optcount
; optindex
++)
272 if (memcmp (argv
[state
->index
] + state
->where
,
273 longopts
[optindex
].name
,
274 (size_t) match_chars
) == 0)
276 size_t len
= strlen (longopts
[optindex
].name
);
280 /* We have option which name is too long. */
282 error (_("option `%s' is too long"), longopts
[optindex
].name
);
284 return (state
->option
= '?');
287 /* Do we have an exact match? */
288 if (match_chars
== (int) len
)
290 longopt_match
= optindex
;
293 /* Do any characters match? */
296 if (longopt_match
< 0)
297 longopt_match
= optindex
;
300 /* We have ambiguous options. */
302 error (_("option `%s' is ambiguous (could be `--%s' or `--%s')"),
304 longopts
[longopt_match
].name
,
305 longopts
[optindex
].name
);
307 return (state
->option
= '?');
313 if (longopt_match
>= 0)
314 has_argument
= longopts
[longopt_match
].has_argument
;
317 /* If we did not find a long option, is it a short option? */
318 if (longopt_match
< 0 && shortopts
!= NULL
)
320 cp
= strchr (shortopts
, argv
[state
->index
][state
->where
]);
324 /* Could not find option in shortopts. */
326 error (_("invalid option -- `-%c'"),
327 argv
[state
->index
][state
->where
]);
331 if (argv
[state
->index
][state
->where
] == '\0')
337 return (state
->option
= '?');
340 has_argument
= ((cp
[1] == ':') ? ((cp
[2] == ':') ? optional_argument
: required_argument
) : no_argument
);
341 possible_arg
= argv
[state
->index
] + state
->where
+ 1;
345 /* Get argument and reset state->where. */
348 switch (has_argument
)
350 case optional_argument
:
351 if (*possible_arg
== '=')
354 if (*possible_arg
!= '\0')
356 state
->argument
= possible_arg
;
360 state
->argument
= NULL
;
363 case required_argument
:
364 if (*possible_arg
== '=')
367 if (*possible_arg
!= '\0')
369 state
->argument
= possible_arg
;
372 else if (state
->index
+ 1 >= argc
)
376 if (longopt_match
>= 0)
377 error (_("argument required for option `--%s'"), longopts
[longopt_match
].name
);
379 error (_("argument required for option `-%c'"), *cp
);
383 return (state
->option
= ':');
387 state
->argument
= argv
[state
->index
+ 1];
394 if (longopt_match
< 0)
398 if (argv
[state
->index
][state
->where
] == '\0')
404 state
->argument
= NULL
;
408 /* Do we have to permute or otherwise modify state->index? */
409 if (ordering
== PERMUTE
&& state
->where
== 1 && num_nonopts
!= 0)
411 permute (argv
+ permute_from
, num_nonopts
, 1 + arg_next
);
412 state
->index
= permute_from
+ 1 + arg_next
;
414 else if (state
->where
== 1)
415 state
->index
= state
->index
+ 1 + arg_next
;
417 /* Finally return. */
418 if (longopt_match
>= 0)
421 *longind
= longopt_match
;
423 if (longopts
[longopt_match
].flag
!= NULL
)
425 *(longopts
[longopt_match
].flag
) = longopts
[longopt_match
].value
;
429 return longopts
[longopt_match
].value
;
432 return state
->option
;