41f59de5e50651a3e76a7f247ee07a15eb172ca9
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) 1990, 1993
23 * The Regents of the University of California. All rights reserved.
25 * Redistribution and use in source and binary forms, with or without
26 * modification, are permitted provided that the following conditions
28 * 1. Redistributions of source code must retain the above copyright
29 * notice, this list of conditions and the following disclaimer.
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the distribution.
33 * 3. Neither the name of the University nor the names of its contributors
34 * may be used to endorse or promote products derived from this software
35 * without specific prior written permission.
37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * Copyright (c) 2000 The NetBSD Foundation, Inc.
52 * All rights reserved.
54 * This code is derived from software contributed to The NetBSD Foundation
55 * by Dieter Baron and Thomas Klausner.
57 * Redistribution and use in source and binary forms, with or without
58 * modification, are permitted provided that the following conditions
60 * 1. Redistributions of source code must retain the above copyright
61 * notice, this list of conditions and the following disclaimer.
62 * 2. Redistributions in binary form must reproduce the above copyright
63 * notice, this list of conditions and the following disclaimer in the
64 * documentation and/or other materials provided with the distribution.
66 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
67 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
68 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
69 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
70 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
71 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
72 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
73 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
74 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
75 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
76 * POSSIBILITY OF SUCH DAMAGE.
79 /* https://git.datadissipation.net */
80 #ifndef GETOPT_LONG_H_
81 #define GETOPT_LONG_H_ 1
83 #ifdef GETOPT_LONG_INCLUDE_LIBC
88 #endif /* GETOPT_LONG_INCLUDE_LIBC */
90 #ifndef HAVE_GETOPT_LONG
91 #define HAVE_GETOPT_LONG 1
94 #define required_argument 1
95 #define optional_argument 2
98 * structs are in their own namespace, so this should be OK
99 * the worst it can do is make compiler messages worse
101 #define option i_option_
103 #define optarg i_optarg_
104 #define suboptarg i_suboptarg_
105 #define optind i_optind_
106 #define opterr i_opterr_
107 #define optopt i_optopt_
108 #define optreset i_optreset_
110 #define getopt i_getopt_
111 #define getsubopt i_getsubopt_
112 #define getopt_long i_getopt_long_
113 #define getopt_long_only i_getopt_long_only_
115 #ifndef GETOPT_LONG_IMPLEMENTATION
116 extern char *i_optarg_
;
117 extern char *i_suboptarg_
;
118 extern int i_optind_
, i_opterr_
, i_optopt_
, i_optreset_
;
119 #endif /* !GETOPT_LONG_IMPLEMENTATION */
124 * one of no_argument, required_argument, and optional_argument:
125 * whether option takes an argument
128 /* if not NULL, set *flag to val when option found */
130 /* if flag not NULL, value to set *flag to; else return value */
134 int i_getopt_(int argc
, char * const *argv
, const char *optstring
);
135 int i_getsubopt_(char **optionp
, char * const *tokens
, char **valuep
);
136 int i_getopt_long_(int argc
, char * const *argv
, const char *optstring
,
137 const struct option
*longopts
, int *longindex
);
138 int i_getopt_long_only_(int argc
, char * const *argv
, const char *optstring
,
139 const struct option
*longopts
, int *longindex
);
141 #endif /* !HAVE_GETOPT_LONG */
143 #ifdef GETOPT_LONG_IMPLEMENTATION
144 #define I_PRINT_ERROR_ ((i_opterr_) && (*options != ':'))
146 #define I_FLAG_PERMUTE_ 0x01 /* permute non-options to the end of argv */
147 #define I_FLAG_ALLARGS_ 0x02 /* treat non-options as args to option "-1" */
148 #define I_FLAG_LONGONLY_ 0x04 /* operate as getopt_long_only */
151 #define I_BADCH_ (int)'?'
152 #define I_BADARG_ ((*options == ':') ? (int)':' : (int)'?')
153 #define I_INORDER_ (int)1
157 int i_opterr_
= 1; /* if error message should be printed */
158 int i_optind_
= 1; /* index into parent argv vector */
159 int i_optopt_
= '?'; /* character checked for validity */
160 int i_optreset_
; /* reset getopt */
161 char *i_optarg_
; /* argument associated with option */
162 char *i_suboptarg_
; /* argument associated with suboption */
164 /* XXX: set optreset to 1 rather than these two */
165 static int i_nonopt_start_
= -1; /* first non option argument (for permute) */
166 static int i_nonopt_end_
= -1; /* first option after non options (for permute) */
167 static char *i_place_
= I_EMSG_
; /* option letter processing */
170 static const char i_recargchar_
[] = "option requires an argument -- %c";
171 static const char i_recargstring_
[] = "option requires an argument -- %s";
172 static const char i_ambig_
[] = "i_ambig_uous option -- %.*s";
173 static const char i_noarg_
[] = "option doesn't take an argument -- %.*s";
174 static const char i_illoptchar_
[] = "unknown option -- %c";
175 static const char i_illoptstring_
[] = "unknown option -- %s";
177 static void i_warnx_(const char *, ...);
178 static int i_getopt_internal_(int, char * const *, const char *,
179 const struct option
*, int *, int);
180 static int i_parse_long_options__(char * const *, const char *,
181 const struct option
*, int *, int);
182 static int i_gcd_(int, int);
183 static void i_permute_args_(int, int, int, char * const *);
186 * Own warnx() for portability
189 i_warnx_(const char *fmt
, ...)
193 /* Linux "program_invocation_short_name" is a GNU extension, so we don't use it */
194 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
195 #define I_GET_PROG_NAME_() getprogname()
197 #define I_GET_PROG_NAME_() "warnx"
201 fprintf(stderr
, "%s: ", I_GET_PROG_NAME_());
202 vfprintf(stderr
, fmt
, args
);
208 * Compute the greatest common divisor of a and b.
226 * Exchange the block from nonopt_start to nonopt_end with the block
227 * from nonopt_end to opt_end (keeping the same order of arguments
231 i_permute_args_(int panonopt_start
, int panonopt_end
, int opt_end
,
234 int cstart
, cyclelen
, i
, j
, ncycle
, nnonopts
, nopts
, pos
;
238 * compute lengths of blocks and number and size of cycles
240 nnonopts
= panonopt_end
- panonopt_start
;
241 nopts
= opt_end
- panonopt_end
;
242 ncycle
= i_gcd_(nnonopts
, nopts
);
243 cyclelen
= (opt_end
- panonopt_start
) / ncycle
;
245 for (i
= 0; i
< ncycle
; i
++) {
246 cstart
= panonopt_end
+i
;
248 for (j
= 0; j
< cyclelen
; j
++) {
249 if (pos
>= panonopt_end
)
254 /* LINTED const cast */
255 ((char **) nargv
)[pos
] = nargv
[cstart
];
256 /* LINTED const cast */
257 ((char **)nargv
)[cstart
] = swap
;
263 * i_parse_long_options__ --
264 * Parse long options in argc/argv argument vector.
265 * Returns -1 if short_too is set and the option does not match long_options.
268 i_parse_long_options__(char * const *nargv
, const char *options
,
269 const struct option
*long_options
, int *idx
, int short_too
)
271 char *current_argv
, *has_equal
;
272 size_t current_argv_len
;
275 current_argv
= i_place_
;
280 if ((has_equal
= strchr(current_argv
, '=')) != NULL
) {
281 /* argument found (--option=arg) */
282 current_argv_len
= has_equal
- current_argv
;
285 current_argv_len
= strlen(current_argv
);
287 for (i
= 0; long_options
[i
].name
; i
++) {
288 /* find matching long option */
289 if (strncmp(current_argv
, long_options
[i
].name
,
293 if (strlen(long_options
[i
].name
) == current_argv_len
) {
299 * If this is a known short option, don't allow
300 * a partial match of a single character.
302 if (short_too
&& current_argv_len
== 1)
305 if (match
== -1) { /* partial match */
308 /* ambiguous abbreviation */
310 i_warnx_(i_ambig_
, (int)current_argv_len
,
316 if (match
!= -1) { /* option found */
317 if (long_options
[match
].has_arg
== no_argument
320 i_warnx_(i_noarg_
, (int)current_argv_len
,
323 * XXX: GNU sets optopt to val regardless of flag
325 if (long_options
[match
].flag
== NULL
)
326 i_optopt_
= long_options
[match
].val
;
331 if (long_options
[match
].has_arg
== required_argument
||
332 long_options
[match
].has_arg
== optional_argument
) {
334 i_optarg_
= has_equal
;
335 else if (long_options
[match
].has_arg
==
338 * optional argument doesn't use next nargv
340 i_optarg_
= nargv
[i_optind_
++];
343 if ((long_options
[match
].has_arg
== required_argument
)
344 && (i_optarg_
== NULL
)) {
346 * Missing argument; leading ':' indicates no error
347 * should be generated.
350 i_warnx_(i_recargstring_
,
353 * XXX: GNU sets optopt to val regardless of flag
355 if (long_options
[match
].flag
== NULL
)
356 i_optopt_
= long_options
[match
].val
;
362 } else { /* unknown option */
368 i_warnx_(i_illoptstring_
, current_argv
);
374 if (long_options
[match
].flag
) {
375 *long_options
[match
].flag
= long_options
[match
].val
;
378 return (long_options
[match
].val
);
382 * i_getopt_internal_ --
383 * Parse argc/argv argument vector. Called by user level routines.
386 i_getopt_internal_(int nargc
, char *const *nargv
, const char *options
,
387 const struct option
*long_options
, int *idx
, int flags
)
389 char *oli
; /* option letter list index */
390 int optchar
, short_too
;
391 static int posix_me_harder
= -1;
397 * XXX Some GNU programs (like cvs) set optind to 0 instead of
398 * XXX using optreset. Work around this braindamage.
401 i_optind_
= i_optreset_
= 1;
404 * Disable GNU extensions if POSIXLY_CORRECT is set or options
405 * string begins with a '+'.
407 if (posix_me_harder
== -1 || i_optreset_
)
408 posix_me_harder
= (getenv("POSIXLY_CORRECT") != NULL
);
410 flags
|= I_FLAG_ALLARGS_
;
411 else if (posix_me_harder
|| *options
== '+')
412 flags
&= ~I_FLAG_PERMUTE_
;
413 if (*options
== '+' || *options
== '-')
418 i_nonopt_start_
= i_nonopt_end_
= -1;
420 if (i_optreset_
|| !*i_place_
) { /* update scanning pointer */
422 if (i_optind_
>= nargc
) { /* end of argument vector */
424 if (i_nonopt_end_
!= -1) {
425 /* do permutation, if we have to */
426 i_permute_args_(i_nonopt_start_
, i_nonopt_end_
,
428 i_optind_
-= i_nonopt_end_
- i_nonopt_start_
;
429 } else if (i_nonopt_start_
!= -1) {
431 * If we skipped non-options, set optind
432 * to the first of them.
434 i_optind_
= i_nonopt_start_
;
436 i_nonopt_start_
= i_nonopt_end_
= -1;
439 if (*(i_place_
= nargv
[i_optind_
]) != '-' ||
440 (i_place_
[1] == '\0' && strchr(options
, '-') == NULL
)) {
441 i_place_
= I_EMSG_
; /* found non-option */
442 if (flags
& I_FLAG_ALLARGS_
) {
445 * return non-option as argument to option 1
447 i_optarg_
= nargv
[i_optind_
++];
450 if (!(flags
& I_FLAG_PERMUTE_
)) {
452 * If no permutation wanted, stop parsing
453 * at first non-option.
458 if (i_nonopt_start_
== -1) {
459 i_nonopt_start_
= i_optind_
;
460 } else if (i_nonopt_end_
!= -1) {
461 i_permute_args_(i_nonopt_start_
, i_nonopt_end_
,
463 i_nonopt_start_
= i_optind_
-
464 (i_nonopt_end_
- i_nonopt_start_
);
468 /* process next argument */
471 if (i_nonopt_start_
!= -1 && i_nonopt_end_
== -1)
472 i_nonopt_end_
= i_optind_
;
475 * If we have "-" do nothing, if "--" we are done.
477 if (i_place_
[1] != '\0' && *++i_place_
== '-' && i_place_
[1] == '\0') {
481 * We found an option (--), so if we skipped
482 * non-options, we have to permute.
484 if (i_nonopt_end_
!= -1) {
485 i_permute_args_(i_nonopt_start_
, i_nonopt_end_
,
487 i_optind_
-= i_nonopt_end_
- i_nonopt_start_
;
489 i_nonopt_start_
= i_nonopt_end_
= -1;
495 * Check long options if:
496 * 1) we were passed some
497 * 2) the arg is not just "-"
498 * 3) either the arg starts with -- we are i_getopt_long_only()
500 if (long_options
!= NULL
&& i_place_
!= nargv
[i_optind_
] &&
501 (*i_place_
== '-' || (flags
& I_FLAG_LONGONLY_
))) {
503 if (*i_place_
== '-')
504 i_place_
++; /* --foo long option */
505 else if (*i_place_
!= ':'
506 && strchr(options
, *i_place_
) != NULL
)
507 short_too
= 1; /* could be short option too */
509 optchar
= i_parse_long_options__(nargv
, options
, long_options
,
517 if ((optchar
= (int)*i_place_
++) == (int)':' ||
518 (optchar
== (int)'-' && *i_place_
!= '\0') ||
519 (oli
= strchr(options
, optchar
)) == NULL
) {
521 * If the user specified "-" and '-' isn't listed in
522 * options, return -1 (non-option) as per POSIX.
523 * Otherwise, it is an unknown option character (or ':').
525 if (optchar
== (int)'-' && *i_place_
== '\0')
530 i_warnx_(i_illoptchar_
, optchar
);
534 if (long_options
!= NULL
&& optchar
== 'W' && oli
[1] == ';') {
536 if (*i_place_
) { /* no space */
538 } else if (++i_optind_
>= nargc
) { /* no arg */
541 i_warnx_(i_recargchar_
, optchar
);
544 } else { /* white space */
545 i_place_
= nargv
[i_optind_
];
547 optchar
= i_parse_long_options__(nargv
, options
, long_options
,
552 if (*++oli
!= ':') { /* doesn't take argument */
555 } else { /* takes (optional) argument */
557 if (*i_place_
) /* no white space */
558 i_optarg_
= i_place_
;
559 else if (oli
[1] != ':') { /* arg not optional */
560 if (++i_optind_
>= nargc
) { /* no arg */
563 i_warnx_(i_recargchar_
, optchar
);
567 i_optarg_
= nargv
[i_optind_
];
573 /* dump back option letter */
578 i_getsubopt_(char **optionp
, char * const *tokens
, char **valuep
)
583 i_suboptarg_
= *valuep
= NULL
;
585 if (!optionp
|| !*optionp
)
588 /* skip leading white-space, commas */
589 for (p
= *optionp
; *p
&& (*p
== ',' || *p
== ' ' || *p
== '\t'); ++p
);
596 /* save the start of the token, and skip the rest of the token. */
597 for (i_suboptarg_
= p
;
598 *++p
&& *p
!= ',' && *p
!= '=' && *p
!= ' ' && *p
!= '\t';);
602 * If there's an equals sign, set the value pointer, and
603 * skip over the value part of the token. Terminate the
609 *p
&& *p
!= ',' && *p
!= ' ' && *p
!= '\t'; ++p
);
615 /* Skip any whitespace or commas after this token. */
616 for (; *p
&& (*p
== ',' || *p
== ' ' || *p
== '\t'); ++p
);
619 /* set optionp for next round. */
622 for (cnt
= 0; *tokens
; ++tokens
, ++cnt
)
623 if (!strcmp(i_suboptarg_
, *tokens
))
629 i_getopt_(int argc
, char * const *argv
, const char *optstring
)
631 #ifdef GETOPT_PERMUTE_ARGS
632 return (i_getopt_internal_(argc
, argv
, optstring
, NULL
, NULL
,
635 return (i_getopt_internal_(argc
, argv
, optstring
, NULL
, NULL
, 0));
640 i_getopt_long_(int argc
, char * const *argv
, const char *optstring
,
641 const struct option
*longopts
, int *longindex
)
643 #ifdef GETOPT_LONG_PERMUTE_ARGS
644 return (i_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
,
647 return (i_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
, 0));
653 i_getopt_long_only_(int argc
, char * const *argv
, const char *optstring
,
654 const struct option
*longopts
, int *longindex
)
656 #ifdef GETOPT_LONG_ONLY_PERMUTE_ARGS
657 return (i_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
,
658 I_FLAG_PERMUTE_
| I_FLAG_LONGONLY_
));
660 return (i_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
,
664 #endif /* GETOPT_LONG_IMPLEMENTATION */
665 #endif /* !GETOPT_LONG_H_ */