2 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 * Sponsored in part by the Defense Advanced Research Projects
17 * Agency (DARPA) and Air Force Research Laboratory, Air Force
18 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22 * Copyright (c) 2000 The NetBSD Foundation, Inc.
23 * All rights reserved.
25 * This code is derived from software contributed to The NetBSD Foundation
26 * by Dieter Baron and Thomas Klausner.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
37 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
38 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
39 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
41 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
43 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
44 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
45 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
47 * POSSIBILITY OF SUCH DAMAGE.
50 /* https://git.datadissipation.net */
51 #ifndef GETOPT_LONG_H_
52 #define GETOPT_LONG_H_ 1
54 #ifdef GETOPT_LONG_INCLUDE_LIBC
60 #ifndef HAVE_GETOPT_LONG
61 #define HAVE_GETOPT_LONG 1
63 * structs are in their own namespace, so this should be OK
64 * the worst it can do is make compiler messages worse
66 #define option i_option_
71 * one of no_argument, required_argument, and optional_argument:
72 * whether option takes an argument
75 /* if not NULL, set *flag to val when option found */
77 /* if flag not NULL, value to set *flag to; else return value */
81 int i_getopt_(int argc
, char *argv
[], const char *optstring
);
82 int i_getsubopt_(char *restrict optionp
[], const char *restrict tokens
[],
83 char *restrict valuep
[]);
84 int i_getopt_long_(int argc
, char *argv
[], const char *optstring
,
85 const struct option
*longopts
, int *longindex
);
86 int i_getopt_long_only_(int argc
, char *argv
[], const char *optstring
,
87 const struct option
*longopts
, int *longindex
);
90 #define required_argument 1
91 #define optional_argument 2
93 #define getopt(c,v,o) i_getopt_(c,v,o)
94 #define getsubopt(o,t,v) i_getsubopt_(o,t,v)
95 #define getopt_long(c,v,o,l,i) i_getopt_long_(c,v,o,l,i)
96 #define getopt_long_only(c,v,o,l,i) i_getopt_long_only_(c,v,o,l,i)
98 #endif /* !HAVE_GETOPT_LONG */
100 #ifdef GETOPT_LONG_IMPLEMENTATION
101 #define I_PRINT_ERROR_ ((i_opterr_) && (*options != ':'))
103 #define I_FLAG_PERMUTE_ 0x01 /* permute non-options to the end of argv */
104 #define I_FLAG_ALLARGS_ 0x02 /* treat non-options as args to option "-1" */
105 #define I_FLAG_LONGONLY_ 0x04 /* operate as i_getopt_long_only */
108 #define I_BADCH_ (int)'?'
109 #define I_BADARG_ ((*options == ':') ? (int)':' : (int)'?')
110 #define I_INORDER_ (int)1
114 static void i_warnx_(const char *, ...);
115 static int i_getopt_internal_(int, char **, const char *,
116 const struct option
*, int *, int);
117 static int i_parse_long_options__(char * const *, const char *,
118 const struct option
*, int *, int);
119 static int i_gcd_(int, int);
120 static void i_permute_args_(int, int, int, char * const *);
123 /* XXX: set i_optreeset_ to 1 rather than these two */
124 static int i_nonopt_start_
= -1; /* first non option argument (for permute) */
125 static int i_nonopt_end_
= -1; /* first option after non options (for permute) */
126 static int i_opterr_
= 1; /* if error message should be printed */
127 static int i_optind_
= 1; /* index into parent argv vector */
128 static int i_optopt_
= '?'; /* character checked for validity */
129 static int i_optreeset_
; /* reset getopt */
130 static char *i_optarg_
; /* argument associated with option */
131 static char *i_place_
= I_EMSG_
; /* option letter processing */
134 static const char i_recargchar_
[] = "option requires an argument -- %c";
135 static const char i_recargstring_
[] = "option requires an argument -- %s";
136 static const char i_ambig_
[] = "i_ambig_uous option -- %.*s";
137 static const char i_noarg_
[] = "option doesn't take an argument -- %.*s";
138 static const char i_illoptchar_
[] = "unknown option -- %c";
139 static const char i_illoptstring_
[] = "unknown option -- %s";
142 * Own warnx() for portability
145 i_warnx_(const char *fmt
, ...)
149 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
150 #define I_GET_PROG_NAME_() getprogname()
151 #elif defined(__linux__)
153 #define I_GET_PROG_NAME_() program_invocation_short_name
155 #define I_GET_PROG_NAME_() "warnx"
159 fprintf(stderr
, "%s: ", I_GET_PROG_NAME_());
160 vfprintf(stderr
, fmt
, args
);
166 * Compute the greatest common divisor of a and b.
184 * Exchange the block from i_nonopt_start_ to i_nonopt_end_ with the block
185 * from i_nonopt_end_ to opt_end (keeping the same order of arguments
189 i_permute_args_(int pai_nonopt_start_
, int pai_nonopt_end_
, int opt_end
,
192 int cstart
, cyclelen
, i
, j
, ncycle
, nnonopts
, nopts
, pos
;
196 * compute lengths of blocks and number and size of cycles
198 nnonopts
= pai_nonopt_end_
- pai_nonopt_start_
;
199 nopts
= opt_end
- pai_nonopt_end_
;
200 ncycle
= i_gcd_(nnonopts
, nopts
);
201 cyclelen
= (opt_end
- pai_nonopt_start_
) / ncycle
;
203 for (i
= 0; i
< ncycle
; i
++) {
204 cstart
= pai_nonopt_end_
+i
;
206 for (j
= 0; j
< cyclelen
; j
++) {
207 if (pos
>= pai_nonopt_end_
)
212 /* LINTED const cast */
213 ((char **) nargv
)[pos
] = nargv
[cstart
];
214 /* LINTED const cast */
215 ((char **)nargv
)[cstart
] = swap
;
221 * i_parse_long_options__ --
222 * Parse long options in argc/argv argument vector.
223 * Returns -1 if short_too is set and the option does not match long_options.
226 i_parse_long_options__(char * const *nargv
, const char *options
,
227 const struct option
*long_options
, int *idx
, int short_too
)
229 char *current_argv
, *has_equal
;
230 size_t current_argv_len
;
233 current_argv
= i_place_
;
238 if ((has_equal
= strchr(current_argv
, '=')) != NULL
) {
239 /* argument found (--option=arg) */
240 current_argv_len
= has_equal
- current_argv
;
243 current_argv_len
= strlen(current_argv
);
245 for (i
= 0; long_options
[i
].name
; i
++) {
246 /* find matching long option */
247 if (strncmp(current_argv
, long_options
[i
].name
,
251 if (strlen(long_options
[i
].name
) == current_argv_len
) {
257 * If this is a known short option, don't allow
258 * a partial match of a single character.
260 if (short_too
&& current_argv_len
== 1)
263 if (match
== -1) { /* partial match */
266 /* i_ambig_uous abbreviation */
268 i_warnx_(i_ambig_
, (int)current_argv_len
,
274 if (match
!= -1) { /* option found */
275 if (long_options
[match
].has_arg
== no_argument
278 i_warnx_(i_noarg_
, (int)current_argv_len
,
281 * XXX: GNU sets i_optopt_ to val regardless of flag
283 if (long_options
[match
].flag
== NULL
)
284 i_optopt_
= long_options
[match
].val
;
289 if (long_options
[match
].has_arg
== required_argument
||
290 long_options
[match
].has_arg
== optional_argument
) {
292 i_optarg_
= has_equal
;
293 else if (long_options
[match
].has_arg
==
296 * optional argument doesn't use next nargv
298 i_optarg_
= nargv
[i_optind_
++];
301 if ((long_options
[match
].has_arg
== required_argument
)
302 && (i_optarg_
== NULL
)) {
304 * Missing argument; leading ':' indicates no error
305 * should be generated.
308 i_warnx_(i_recargstring_
,
311 * XXX: GNU sets i_optopt_ to val regardless of flag
313 if (long_options
[match
].flag
== NULL
)
314 i_optopt_
= long_options
[match
].val
;
320 } else { /* unknown option */
326 i_warnx_(i_illoptstring_
, current_argv
);
332 if (long_options
[match
].flag
) {
333 *long_options
[match
].flag
= long_options
[match
].val
;
336 return (long_options
[match
].val
);
340 * i_getopt_internal_ --
341 * Parse argc/argv argument vector. Called by user level routines.
344 i_getopt_internal_(int nargc
, char **nargv
, const char *options
,
345 const struct option
*long_options
, int *idx
, int flags
)
347 char *oli
; /* option letter list index */
348 int optchar
, short_too
;
349 static int posix_me_harder
= -1;
355 * XXX Some GNU programs (like cvs) set optind to 0 instead of
356 * XXX using optreeset. Work around this braindamage.
359 i_optind_
= i_optreeset_
= 1;
362 * Disable GNU extensions if POSIXLY_CORRECT is set or options
363 * string begins with a '+'.
365 if (posix_me_harder
== -1 || i_optreeset_
)
366 posix_me_harder
= (getenv("POSIXLY_CORRECT") != NULL
);
368 flags
|= I_FLAG_ALLARGS_
;
369 else if (posix_me_harder
|| *options
== '+')
370 flags
&= ~I_FLAG_PERMUTE_
;
371 if (*options
== '+' || *options
== '-')
376 i_nonopt_start_
= i_nonopt_end_
= -1;
378 if (i_optreeset_
|| !*i_place_
) { /* update scanning pointer */
380 if (i_optind_
>= nargc
) { /* end of argument vector */
382 if (i_nonopt_end_
!= -1) {
383 /* do permutation, if we have to */
384 i_permute_args_(i_nonopt_start_
, i_nonopt_end_
,
386 i_optind_
-= i_nonopt_end_
- i_nonopt_start_
;
387 } else if (i_nonopt_start_
!= -1) {
389 * If we skipped non-options, set i_optind_
390 * to the first of them.
392 i_optind_
= i_nonopt_start_
;
394 i_nonopt_start_
= i_nonopt_end_
= -1;
397 if (*(i_place_
= nargv
[i_optind_
]) != '-' ||
398 (i_place_
[1] == '\0' && strchr(options
, '-') == NULL
)) {
399 i_place_
= I_EMSG_
; /* found non-option */
400 if (flags
& I_FLAG_ALLARGS_
) {
403 * return non-option as argument to option 1
405 i_optarg_
= nargv
[i_optind_
++];
408 if (!(flags
& I_FLAG_PERMUTE_
)) {
410 * If no permutation wanted, stop parsing
411 * at first non-option.
416 if (i_nonopt_start_
== -1) {
417 i_nonopt_start_
= i_optind_
;
418 } else if (i_nonopt_end_
!= -1) {
419 i_permute_args_(i_nonopt_start_
, i_nonopt_end_
,
421 i_nonopt_start_
= i_optind_
-
422 (i_nonopt_end_
- i_nonopt_start_
);
426 /* process next argument */
429 if (i_nonopt_start_
!= -1 && i_nonopt_end_
== -1)
430 i_nonopt_end_
= i_optind_
;
433 * If we have "-" do nothing, if "--" we are done.
435 if (i_place_
[1] != '\0' && *++i_place_
== '-' && i_place_
[1] == '\0') {
439 * We found an option (--), so if we skipped
440 * non-options, we have to permute.
442 if (i_nonopt_end_
!= -1) {
443 i_permute_args_(i_nonopt_start_
, i_nonopt_end_
,
445 i_optind_
-= i_nonopt_end_
- i_nonopt_start_
;
447 i_nonopt_start_
= i_nonopt_end_
= -1;
453 * Check long options if:
454 * 1) we were passed some
455 * 2) the arg is not just "-"
456 * 3) either the arg starts with -- we are i_getopt_long_only()
458 if (long_options
!= NULL
&& i_place_
!= nargv
[i_optind_
] &&
459 (*i_place_
== '-' || (flags
& I_FLAG_LONGONLY_
))) {
461 if (*i_place_
== '-')
462 i_place_
++; /* --foo long option */
463 else if (*i_place_
!= ':'
464 && strchr(options
, *i_place_
) != NULL
)
465 short_too
= 1; /* could be short option too */
467 optchar
= i_parse_long_options__(nargv
, options
, long_options
,
475 if ((optchar
= (int)*i_place_
++) == (int)':' ||
476 (optchar
== (int)'-' && *i_place_
!= '\0') ||
477 (oli
= strchr(options
, optchar
)) == NULL
) {
479 * If the user specified "-" and '-' isn't listed in
480 * options, return -1 (non-option) as per POSIX.
481 * Otherwise, it is an unknown option character (or ':').
483 if (optchar
== (int)'-' && *i_place_
== '\0')
488 i_warnx_(i_illoptchar_
, optchar
);
492 if (long_options
!= NULL
&& optchar
== 'W' && oli
[1] == ';') {
494 if (*i_place_
) { /* no space */
496 } else if (++i_optind_
>= nargc
) { /* no arg */
499 i_warnx_(i_recargchar_
, optchar
);
502 } else { /* white space */
503 i_place_
= nargv
[i_optind_
];
505 optchar
= i_parse_long_options__(nargv
, options
, long_options
,
510 if (*++oli
!= ':') { /* doesn't take argument */
513 } else { /* takes (optional) argument */
515 if (*i_place_
) /* no white space */
516 i_optarg_
= i_place_
;
517 else if (oli
[1] != ':') { /* arg not optional */
518 if (++i_optind_
>= nargc
) { /* no arg */
521 i_warnx_(i_recargchar_
, optchar
);
525 i_optarg_
= nargv
[i_optind_
];
531 /* dump back option letter */
536 i_getopt_(int argc
, char *argv
[], const char *optstring
)
538 #ifdef GETOPT_PERMUTE_ARGS
539 return (i_getopt_internal_(argc
, argv
, optstring
, NULL
, NULL
,
542 return (i_getopt_internal_(argc
, argv
, optstring
, NULL
, NULL
, 0));
547 i_getopt_long_(int argc
, char *argv
[], const char *optstring
,
548 const struct option
*longopts
, int *longindex
)
550 #ifdef GETOPT_LONG_PERMUTE_ARGS
551 return (i_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
,
554 return (i_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
, 0));
560 i_getopt_long_only_(int argc
, char *argv
[], const char *optstring
,
561 const struct option
*longopts
, int *longindex
)
563 #ifdef GETOPT_LONG_ONLY_PERMUTE_ARGS
564 return (i_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
,
565 I_FLAG_PERMUTE_
| I_FLAG_LONGONLY_
));
567 return (i_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
,
571 #endif /* GETOPT_LONG_IMPLEMENTATION */
572 #endif /* !GETOPT_LONG_H_ */