1 /* $NetBSD: getopt_long.c,v 1.16 2003/10/27 00:12:42 lukem Exp $ */
2 /* $DragonFly: src/lib/libc/stdlib/getopt_long.c,v 1.12 2005/03/14 14:26:16 joerg Exp $ */
5 * Copyright (c) 2000 The NetBSD Foundation, Inc.
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Dieter Baron and Thomas Klausner.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
40 #include <sys/cdefs.h>
48 /* XXX BOOTSTRAPPING */
50 #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
54 int opterr = 1; /* if error message should be printed */
55 int optind = 1; /* index into parent argv vector */
56 int optopt = '?'; /* character checked for validity */
57 int optreset; /* reset getopt */
58 char *optarg; /* argument associated with option */
61 #define IGNORE_FIRST (*options == '-' || *options == '+')
62 #define PRINT_ERROR ((opterr) && ((*options != ':') \
63 || (IGNORE_FIRST && options[1] != ':')))
64 #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
65 #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
66 /* XXX: GNU ignores PC if *options == '-' */
67 #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
70 #define BADCH (int)'?'
71 #define BADARG ((IGNORE_FIRST && options[1] == ':') \
72 || (*options == ':') ? (int)':' : (int)'?')
73 #define INORDER (int)1
75 static int getopt_internal(int, char * const *, const char *, int);
76 static int getopt_internal_short(int, char * const *, const char *, int);
77 static int getopt_long_internal(int, char * const *, const char *,
78 const struct option *, int *, int);
79 static int gcd(int, int);
80 static void permute_args(int, int, int, char * const *);
82 static char EMSG[] = {0};
83 static char *place = EMSG; /* option letter processing */
85 /* XXX: set optreset to 1 rather than these two */
86 static int nonopt_start = -1; /* first non option argument (for permute) */
87 static int nonopt_end = -1; /* first option after non options (for permute) */
90 static const char recargchar[] = "option requires an argument -- %c";
91 static const char recargstring[] = "option requires an argument -- %s";
92 static const char ambig[] = "ambiguous option -- %.*s";
93 static const char noarg[] = "option doesn't take an argument -- %.*s";
94 static const char illoptchar[] = "unknown option -- %c";
95 static const char illoptstring[] = "unknown option -- %s";
99 * Compute the greatest common divisor of a and b.
117 * Exchange the block from nonopt_start to nonopt_end with the block
118 * from nonopt_end to opt_end (keeping the same order of arguments
122 permute_args(int panonopt_start, int panonopt_end, int opt_end,
125 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
129 * compute lengths of blocks and number and size of cycles
131 nnonopts = panonopt_end - panonopt_start;
132 nopts = opt_end - panonopt_end;
133 ncycle = gcd(nnonopts, nopts);
134 cyclelen = (opt_end - panonopt_start) / ncycle;
136 for (i = 0; i < ncycle; i++) {
137 cstart = panonopt_end+i;
139 for (j = 0; j < cyclelen; j++) {
140 if (pos >= panonopt_end)
145 /* LINTED const cast */
146 (__DECONST(char **, nargv))[pos] = nargv[cstart];
147 /* LINTED const cast */
148 (__DECONST(char **, nargv))[cstart] = swap;
155 * Parse argc/argv argument vector. Called by user level routines.
156 * Returns -2 if -- is found (can be long option or end of options marker).
159 getopt_internal(int nargc, char * const *nargv, const char *options,
165 * XXX Some programs (like rsyncd) expect to be able to
166 * XXX re-initialize optind to 0 and have getopt_long(3)
167 * XXX properly function again. Work around this braindamage.
173 nonopt_start = nonopt_end = -1;
175 if (optreset || !*place) { /* update scanning pointer */
177 if (optind >= nargc) { /* end of argument vector */
179 if (nonopt_end != -1) {
180 /* do permutation, if we have to */
181 permute_args(nonopt_start, nonopt_end,
183 optind -= nonopt_end - nonopt_start;
185 else if (nonopt_start != -1) {
187 * If we skipped non-options, set optind
188 * to the first of them.
190 optind = nonopt_start;
192 nonopt_start = nonopt_end = -1;
195 place = nargv[optind];
196 if ((*place == '-') && (place[1] == '\0'))
198 if ((*place != '-')) {
199 /* found non-option */
204 * return non-option as argument to option 1
206 optarg = nargv[optind++];
211 * if no permutation wanted, stop parsing
212 * at first non-option
217 if (nonopt_start == -1)
218 nonopt_start = optind;
219 else if (nonopt_end != -1) {
220 permute_args(nonopt_start, nonopt_end,
222 nonopt_start = optind -
223 (nonopt_end - nonopt_start);
227 /* process next argument */
230 if (nonopt_start != -1 && nonopt_end == -1)
232 if (place[1] && *++place == '-') { /* found "--" */
233 if (place[1] == '\0') {
236 * We found an option (--), so if we skipped
237 * non-options, we have to permute.
239 if (nonopt_end != -1) {
240 permute_args(nonopt_start, nonopt_end,
242 optind -= nonopt_end - nonopt_start;
244 nonopt_start = nonopt_end = -1;
246 } else if (long_support) {
252 if (long_support == 2 && (place[1] || strchr(options, *place) == NULL))
254 return getopt_internal_short(nargc, nargv, options, long_support);
258 getopt_internal_short(int nargc, char * const *nargv, const char *options,
261 const char *oli; /* option letter list index */
264 if ((optchar = (int)*place++) == (int)':' ||
265 (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
266 /* option letter unknown or ':' */
268 if (long_support == 2)
269 warnx(illoptstring, --place);
271 warnx(illoptchar, optchar);
273 if (long_support == 2)
280 if (long_support && optchar == 'W' && oli[1] == ';') {
285 if (++optind >= nargc) { /* no arg */
288 warnx(recargchar, optchar);
291 } else /* white space */
292 place = nargv[optind];
294 * Handle -W arg the same as --arg (which causes getopt to
299 if (*++oli != ':') { /* doesn't take argument */
302 } else { /* takes (optional) argument */
304 if (*place) /* no white space */
306 /* XXX: disable test for :: if PC? (GNU doesn't) */
307 else if (oli[1] != ':') { /* arg not optional */
308 if (++optind >= nargc) { /* no arg */
311 warnx(recargchar, optchar);
315 optarg = nargv[optind];
320 /* dump back option letter */
325 getopt_long_internal(int nargc, char * const *nargv, const char *options,
326 const struct option *long_options, int *idx, int long_only)
330 /* idx may be NULL */
332 retval = getopt_internal(nargc, nargv, options, long_only ? 2 : 1);
334 if (retval == -2 || retval == -3) {
335 char *current_argv, *has_equal;
336 size_t current_argv_len;
339 current_argv = place;
345 if ((has_equal = strchr(current_argv, '=')) != NULL) {
346 /* argument found (--option=arg) */
347 current_argv_len = has_equal - current_argv;
350 current_argv_len = strlen(current_argv);
352 for (i = 0; long_options[i].name; i++) {
353 /* find matching long option */
354 if (strncmp(current_argv, long_options[i].name,
358 if (strlen(long_options[i].name) ==
359 (unsigned)current_argv_len) {
364 if (match == -1) /* partial match */
367 /* ambiguous abbreviation */
369 warnx(ambig, (int)current_argv_len,
375 if (match != -1) { /* option found */
376 if (long_options[match].has_arg == no_argument
379 warnx(noarg, (int)current_argv_len,
382 * XXX: GNU sets optopt to val regardless of
385 if (long_options[match].flag == NULL)
386 optopt = long_options[match].val;
391 if (long_options[match].has_arg == required_argument ||
392 long_options[match].has_arg == optional_argument) {
395 else if (long_options[match].has_arg ==
398 * optional argument doesn't use
401 optarg = nargv[optind++];
404 if ((long_options[match].has_arg == required_argument)
405 && (optarg == NULL)) {
407 * Missing argument; leading ':'
408 * indicates no error should be generated
411 warnx(recargstring, current_argv);
413 * XXX: GNU sets optopt to val regardless
416 if (long_options[match].flag == NULL)
417 optopt = long_options[match].val;
423 } else if (retval == -3) {
425 place = current_argv;
426 retval = getopt_internal_short(nargc, nargv,
427 options, long_only ? 2 : 1);
429 } else { /* unknown option */
431 warnx(illoptstring, current_argv);
435 if (long_options[match].flag) {
436 *long_options[match].flag = long_options[match].val;
439 retval = long_options[match].val;
446 #ifdef REPLACE_GETOPT
449 * Parse argc/argv argument vector.
451 * [eventually this will replace the real getopt]
454 getopt(int nargc, char * const *nargv, const char *options)
456 return getopt_internal(nargc, nargv, options, 0);
462 * Parse argc/argv argument vector.
466 getopt_long(int nargc, char * const *nargv, const char *options,
467 const struct option *long_options, int *idx)
469 return getopt_long_internal(nargc, nargv, options, long_options,
474 * getopt_long_only --
475 * Parse argc/argv argument vector.
476 * Prefers long options over short options for single dash arguments.
479 int getopt_long_only(int nargc, char * const *nargv, const char *options,
480 const struct option *long_options, int *idx)
482 return getopt_long_internal(nargc, nargv, options, long_options,