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.14 2005/11/20 12:37:48 swildner 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') && long_support
== 0)
198 if ((*place
!= '-') ||
199 ((*place
== '-') && (place
[1] == '\0') && long_support
!= 0)) {
200 /* found non-option */
205 * return non-option as argument to option 1
207 optarg
= nargv
[optind
++];
212 * if no permutation wanted, stop parsing
213 * at first non-option
218 if (nonopt_start
== -1)
219 nonopt_start
= optind
;
220 else if (nonopt_end
!= -1) {
221 permute_args(nonopt_start
, nonopt_end
,
223 nonopt_start
= optind
-
224 (nonopt_end
- nonopt_start
);
228 /* process next argument */
231 if (nonopt_start
!= -1 && nonopt_end
== -1)
233 if (place
[1] && *++place
== '-') { /* found "--" */
234 if (place
[1] == '\0') {
237 * We found an option (--), so if we skipped
238 * non-options, we have to permute.
240 if (nonopt_end
!= -1) {
241 permute_args(nonopt_start
, nonopt_end
,
243 optind
-= nonopt_end
- nonopt_start
;
245 nonopt_start
= nonopt_end
= -1;
247 } else if (long_support
) {
253 if (long_support
== 2 && (place
[1] || strchr(options
, *place
) == NULL
))
255 return getopt_internal_short(nargc
, nargv
, options
, long_support
);
259 getopt_internal_short(int nargc
, char * const *nargv
, const char *options
,
262 const char *oli
; /* option letter list index */
265 if ((optchar
= (int)*place
++) == (int)':' ||
266 (oli
= strchr(options
+ (IGNORE_FIRST
? 1 : 0), optchar
)) == NULL
) {
267 /* option letter unknown or ':' */
269 if (long_support
== 2)
270 warnx(illoptstring
, --place
);
272 warnx(illoptchar
, optchar
);
274 if (long_support
== 2)
281 if (long_support
&& optchar
== 'W' && oli
[1] == ';') {
286 if (++optind
>= nargc
) { /* no arg */
289 warnx(recargchar
, optchar
);
292 } else /* white space */
293 place
= nargv
[optind
];
295 * Handle -W arg the same as --arg (which causes getopt to
300 if (*++oli
!= ':') { /* doesn't take argument */
303 } else { /* takes (optional) argument */
305 if (*place
) /* no white space */
307 /* XXX: disable test for :: if PC? (GNU doesn't) */
308 else if (oli
[1] != ':') { /* arg not optional */
309 if (++optind
>= nargc
) { /* no arg */
312 warnx(recargchar
, optchar
);
316 optarg
= nargv
[optind
];
321 /* dump back option letter */
326 getopt_long_internal(int nargc
, char * const *nargv
, const char *options
,
327 const struct option
*long_options
, int *idx
, int long_only
)
331 /* idx may be NULL */
333 retval
= getopt_internal(nargc
, nargv
, options
, long_only
? 2 : 1);
335 if (retval
== -2 || retval
== -3) {
336 char *current_argv
, *has_equal
;
337 size_t current_argv_len
;
340 current_argv
= place
;
346 if ((has_equal
= strchr(current_argv
, '=')) != NULL
) {
347 /* argument found (--option=arg) */
348 current_argv_len
= has_equal
- current_argv
;
351 current_argv_len
= strlen(current_argv
);
353 for (i
= 0; long_options
[i
].name
; i
++) {
354 /* find matching long option */
355 if (strncmp(current_argv
, long_options
[i
].name
,
359 if (strlen(long_options
[i
].name
) ==
360 (unsigned)current_argv_len
) {
365 if (match
== -1) /* partial match */
368 /* ambiguous abbreviation */
370 warnx(ambig
, (int)current_argv_len
,
376 if (match
!= -1) { /* option found */
377 if (long_options
[match
].has_arg
== no_argument
380 warnx(noarg
, (int)current_argv_len
,
383 * XXX: GNU sets optopt to val regardless of
386 if (long_options
[match
].flag
== NULL
)
387 optopt
= long_options
[match
].val
;
392 if (long_options
[match
].has_arg
== required_argument
||
393 long_options
[match
].has_arg
== optional_argument
) {
396 else if (long_options
[match
].has_arg
==
399 * optional argument doesn't use
402 optarg
= nargv
[optind
++];
405 if ((long_options
[match
].has_arg
== required_argument
)
406 && (optarg
== NULL
)) {
408 * Missing argument; leading ':'
409 * indicates no error should be generated
412 warnx(recargstring
, current_argv
);
414 * XXX: GNU sets optopt to val regardless
417 if (long_options
[match
].flag
== NULL
)
418 optopt
= long_options
[match
].val
;
424 } else if (retval
== -3) {
426 place
= current_argv
;
427 retval
= getopt_internal_short(nargc
, nargv
,
428 options
, long_only
? 2 : 1);
430 } else { /* unknown option */
432 warnx(illoptstring
, current_argv
);
436 if (long_options
[match
].flag
) {
437 *long_options
[match
].flag
= long_options
[match
].val
;
440 retval
= long_options
[match
].val
;
447 #ifdef REPLACE_GETOPT
450 * Parse argc/argv argument vector.
452 * [eventually this will replace the real getopt]
455 getopt(int nargc
, char * const *nargv
, const char *options
)
457 return getopt_internal(nargc
, nargv
, options
, 0);
463 * Parse argc/argv argument vector.
467 getopt_long(int nargc
, char * const *nargv
, const char *options
,
468 const struct option
*long_options
, int *idx
)
470 return getopt_long_internal(nargc
, nargv
, options
, long_options
,
475 * getopt_long_only --
476 * Parse argc/argv argument vector.
477 * Prefers long options over short options for single dash arguments.
481 getopt_long_only(int nargc
, char * const *nargv
, const char *options
,
482 const struct option
*long_options
, int *idx
)
484 return getopt_long_internal(nargc
, nargv
, options
, long_options
,