2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
6 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
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. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
35 * Sponsored in part by the Defense Advanced Research Projects
36 * Agency (DARPA) and Air Force Research Laboratory, Air Force
37 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
40 /* https://git.datadissipation.net */
41 #ifndef LCE_GETOPT_LONG_H
42 #define LCE_GETOPT_LONG_H 1
44 #ifdef LCE_GETOPT_LONG_INCLUDE_LIBC
49 #endif /* LCE_GETOPT_LONG_INCLUDE_LIBC */
51 #ifndef HAVE_GETOPT_LONG
52 #define HAVE_GETOPT_LONG 1
55 #endif /* !HAVE_GETOPT */
58 #define required_argument 1
59 #define optional_argument 2
62 * structs are in their own namespace, so this should be OK
63 * the worst it can do is make compiler messages worse
65 #define option lce_option_
67 #define optarg lce_optarg_
68 #define suboptarg lce_suboptarg_
69 #define optind lce_optind_
70 #define opterr lce_opterr_
71 #define optopt lce_optopt_
72 #define optreset lce_optreset_
74 #define getopt lce_getopt_
75 #define getsubopt lce_getsubopt_
76 #define getopt_long lce_getopt_long_
77 #define getopt_long_only lce_getopt_long_only_
79 #ifndef LCE_GETOPT_LONG_IMPLEMENTATION
80 extern char *lce_optarg_
;
81 extern char *lce_suboptarg_
;
82 extern int lce_optind_
, lce_opterr_
, lce_optopt_
, lce_optreset_
;
83 #endif /* !LCE_GETOPT_LONG_IMPLEMENTATION */
88 * one of no_argument, required_argument, and optional_argument:
89 * whether option takes an argument
92 /* if not NULL, set *flag to val when option found */
94 /* if flag not NULL, value to set *flag to; else return value */
98 int lce_getopt_(int argc
, char * const *argv
, const char *optstring
);
99 int lce_getsubopt_(char **optionp
, char * const *tokens
, char **valuep
);
100 int lce_getopt_long_(int argc
, char * const *argv
, const char *optstring
,
101 const struct option
*longopts
, int *longindex
);
102 int lce_getopt_long_only_(int argc
, char * const *argv
, const char *optstring
,
103 const struct option
*longopts
, int *longindex
);
105 #endif /* !HAVE_GETOPT_LONG */
107 #ifdef LCE_GETOPT_LONG_IMPLEMENTATION
108 #define LCE_PRINT_ERROR_ ((lce_opterr_) && (*options != ':'))
110 #define LCE_FLAG_PERMUTE_ 0x01 /* permute non-options to the end of argv */
111 #define LCE_FLAG_ALLARGS_ 0x02 /* treat non-options as args to option "-1" */
112 #define LCE_FLAG_LONGONLY_ 0x04 /* operate as getopt_long_only */
115 #define LCE_BADCH_ (int) '?'
116 #define LCE_BADARG_ ((*options == ':') ? (int) ':' : (int) '?')
117 #define LCE_INORDER_ (int) 1
121 int lce_opterr_
= 1; /* if error message should be printed */
122 int lce_optind_
= 1; /* index into parent argv vector */
123 int lce_optopt_
= '?'; /* character checked for validity */
124 int lce_optreset_
; /* reset getopt */
125 char *lce_optarg_
; /* argument associated with option */
126 char *lce_suboptarg_
; /* argument associated with suboption */
128 /* XXX: set optreset to 1 rather than these two */
129 static int lce_nonopt_start_
= -1; /* first non option argument (for permute) */
130 static int lce_nonopt_end_
= -1; /* first option after non options (for permute) */
131 static char *lce_place_
= LCE_EMSG_
; /* option letter processing */
132 static char *lce_progname_
; /* program name == argv[0] */
135 static const char lce_recargchar_
[] = "option requires an argument -- %c";
136 static const char lce_recargstring_
[] = "option requires an argument -- %s";
137 static const char lce_ambig_
[] = "ambiguous option -- %.*s";
138 static const char lce_noarg_
[] = "option doesn't take an argument -- %.*s";
139 static const char lce_illoptchar_
[] = "unknown option -- %c";
140 static const char lce_illoptstring_
[] = "unknown option -- %s";
142 static void lce_warnx_(const char *, ...);
143 static int lce_getopt_internal_(int, char * const *, const char *,
144 const struct option
*, int *, int);
145 static int lce_parse_long_options__(char * const *, const char *,
146 const struct option
*, int *, int);
147 static int lce_gcd_(int, int);
148 static void lce_permute_args_(int, int, int, char * const *);
151 * Own warnx() for portability
154 lce_warnx_(const char *fmt
, ...)
159 fprintf(stderr
, "%s: ", lce_progname_
);
160 vfprintf(stderr
, fmt
, args
);
166 * Compute the greatest common divisor of a and b.
169 lce_gcd_(int a
, int b
)
184 * Exchange the block from nonopt_start to nonopt_end with the block
185 * from nonopt_end to opt_end (keeping the same order of arguments
189 lce_permute_args_(int panonopt_start
, int panonopt_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
= panonopt_end
- panonopt_start
;
199 nopts
= opt_end
- panonopt_end
;
200 ncycle
= lce_gcd_(nnonopts
, nopts
);
201 cyclelen
= (opt_end
- panonopt_start
) / ncycle
;
203 for (i
= 0; i
< ncycle
; i
++) {
204 cstart
= panonopt_end
+i
;
206 for (j
= 0; j
< cyclelen
; j
++) {
207 if (pos
>= panonopt_end
)
212 /* LINTED const cast */
213 ((char **) nargv
)[pos
] = nargv
[cstart
];
214 /* LINTED const cast */
215 ((char **) nargv
)[cstart
] = swap
;
221 * lce_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 lce_parse_long_options__(char * const *nargv
, const char *options
,
227 const struct option
*long_options
, int *idx
, int
230 char *current_argv
, *has_equal
;
231 size_t current_argv_len
;
234 current_argv
= lce_place_
;
239 if ((has_equal
= strchr(current_argv
, '=')) != NULL
) {
240 /* argument found (--option=arg) */
241 current_argv_len
= has_equal
- current_argv
;
244 current_argv_len
= strlen(current_argv
);
246 for (i
= 0; long_options
[i
].name
; i
++) {
247 /* find matching long option */
248 if (strncmp(current_argv
, long_options
[i
].name
,
252 if (strlen(long_options
[i
].name
) == current_argv_len
) {
258 * If this is a known short option, don't allow
259 * a partial match of a single character.
261 if (short_too
&& current_argv_len
== 1)
264 if (match
== -1) { /* partial match */
267 /* ambiguous abbreviation */
268 if (LCE_PRINT_ERROR_
)
269 lce_warnx_(lce_ambig_
, (int) current_argv_len
,
275 if (match
!= -1) { /* option found */
276 if (long_options
[match
].has_arg
== no_argument
278 if (LCE_PRINT_ERROR_
)
279 lce_warnx_(lce_noarg_
, (int) current_argv_len
,
282 * XXX: GNU sets optopt to val regardless of flag
284 if (long_options
[match
].flag
== NULL
)
285 lce_optopt_
= long_options
[match
].val
;
288 return (LCE_BADARG_
);
290 if (long_options
[match
].has_arg
== required_argument
||
291 long_options
[match
].has_arg
== optional_argument
) {
293 lce_optarg_
= has_equal
;
294 } else if (long_options
[match
].has_arg
==
297 * optional argument doesn't use next nargv
299 lce_optarg_
= nargv
[lce_optind_
++];
302 if ((long_options
[match
].has_arg
== required_argument
)
303 && (lce_optarg_
== NULL
)) {
305 * Missing argument; leading ':' indicates no error
306 * should be generated.
308 if (LCE_PRINT_ERROR_
)
309 lce_warnx_(lce_recargstring_
,
312 * XXX: GNU sets optopt to val regardless of flag
314 if (long_options
[match
].flag
== NULL
)
315 lce_optopt_
= long_options
[match
].val
;
319 return (LCE_BADARG_
);
321 } else { /* unknown option */
326 if (LCE_PRINT_ERROR_
)
327 lce_warnx_(lce_illoptstring_
, current_argv
);
333 if (long_options
[match
].flag
) {
334 *long_options
[match
].flag
= long_options
[match
].val
;
337 return (long_options
[match
].val
);
342 * lce_getopt_internal_ --
343 * Parse argc/argv argument vector. Called by user level routines.
346 lce_getopt_internal_(int nargc
, char *const *nargv
, const char *options
,
347 const struct option
*long_options
, int *idx
, int flags
)
349 char *oli
; /* option letter list index */
350 int optchar
, short_too
;
351 static int posix_me_harder
= -1;
356 lce_progname_
= nargv
[0];
359 * XXX Some GNU programs (like cvs) set optind to 0 instead of
360 * XXX using optreset. Work around this braindamage.
362 if (lce_optind_
== 0)
363 lce_optind_
= lce_optreset_
= 1;
366 * Disable GNU extensions if POSIXLY_CORRECT is set or options
367 * string begins with a '+'.
369 if (posix_me_harder
== -1 || lce_optreset_
)
370 posix_me_harder
= (getenv("POSIXLY_CORRECT") != NULL
);
372 flags
|= LCE_FLAG_ALLARGS_
;
373 else if (posix_me_harder
|| *options
== '+')
374 flags
&= ~LCE_FLAG_PERMUTE_
;
375 if (*options
== '+' || *options
== '-')
380 lce_nonopt_start_
= lce_nonopt_end_
= -1;
382 if (lce_optreset_
|| !*lce_place_
) { /* update scanning pointer */
384 if (lce_optind_
>= nargc
) { /* end of argument vector */
385 lce_place_
= LCE_EMSG_
;
386 if (lce_nonopt_end_
!= -1) {
387 /* do permutation, if we have to */
388 lce_permute_args_(lce_nonopt_start_
, lce_nonopt_end_
,
390 lce_optind_
-= lce_nonopt_end_
- lce_nonopt_start_
;
391 } else if (lce_nonopt_start_
!= -1) {
393 * If we skipped non-options, set optind
394 * to the first of them.
396 lce_optind_
= lce_nonopt_start_
;
398 lce_nonopt_start_
= lce_nonopt_end_
= -1;
401 if (*(lce_place_
= nargv
[lce_optind_
]) != '-' ||
402 (lce_place_
[1] == '\0' && strchr(options
, '-') == NULL
)) {
403 lce_place_
= LCE_EMSG_
; /* found non-option */
404 if (flags
& LCE_FLAG_ALLARGS_
) {
407 * return non-option as argument to option 1
409 lce_optarg_
= nargv
[lce_optind_
++];
410 return (LCE_INORDER_
);
412 if (!(flags
& LCE_FLAG_PERMUTE_
)) {
414 * If no permutation wanted, stop parsing
415 * at first non-option.
420 if (lce_nonopt_start_
== -1) {
421 lce_nonopt_start_
= lce_optind_
;
422 } else if (lce_nonopt_end_
!= -1) {
423 lce_permute_args_(lce_nonopt_start_
, lce_nonopt_end_
,
425 lce_nonopt_start_
= lce_optind_
-
428 lce_nonopt_end_
= -1;
431 /* process next argument */
434 if (lce_nonopt_start_
!= -1 && lce_nonopt_end_
== -1)
435 lce_nonopt_end_
= lce_optind_
;
438 * If we have "-" do nothing, if "--" we are done.
440 if (lce_place_
[1] != '\0' && *++lce_place_
== '-' && lce_place_
[1] ==
443 lce_place_
= LCE_EMSG_
;
445 * We found an option (--), so if we skipped
446 * non-options, we have to permute.
448 if (lce_nonopt_end_
!= -1) {
449 lce_permute_args_(lce_nonopt_start_
, lce_nonopt_end_
,
451 lce_optind_
-= lce_nonopt_end_
- lce_nonopt_start_
;
453 lce_nonopt_start_
= lce_nonopt_end_
= -1;
459 * Check long options if:
460 * 1) we were passed some
461 * 2) the arg is not just "-"
462 * 3) either the arg starts with -- we are lce_getopt_long_only()
464 if (long_options
!= NULL
&& lce_place_
!= nargv
[lce_optind_
] &&
465 (*lce_place_
== '-' || (flags
& LCE_FLAG_LONGONLY_
))) {
467 if (*lce_place_
== '-')
468 lce_place_
++; /* --foo long option */
469 else if (*lce_place_
!= ':'
470 && strchr(options
, *lce_place_
) != NULL
)
471 short_too
= 1; /* could be short option too */
473 optchar
= lce_parse_long_options__(nargv
, options
, long_options
,
476 lce_place_
= LCE_EMSG_
;
481 if ((optchar
= (int) *lce_place_
++) == (int) ':' ||
482 (optchar
== (int) '-' && *lce_place_
!= '\0') ||
483 (oli
= strchr(options
, optchar
)) == NULL
) {
485 * If the user specified "-" and '-' isn't listed in
486 * options, return -1 (non-option) as per POSIX.
487 * Otherwise, it is an unknown option character (or ':').
489 if (optchar
== (int) '-' && *lce_place_
== '\0')
493 if (LCE_PRINT_ERROR_
)
494 lce_warnx_(lce_illoptchar_
, optchar
);
495 lce_optopt_
= optchar
;
498 if (long_options
!= NULL
&& optchar
== 'W' && oli
[1] == ';') {
500 if (*lce_place_
) { /* no space */
503 } else if (++lce_optind_
>= nargc
) { /* no arg */
504 lce_place_
= LCE_EMSG_
;
505 if (LCE_PRINT_ERROR_
)
506 lce_warnx_(lce_recargchar_
, optchar
);
507 lce_optopt_
= optchar
;
508 return (LCE_BADARG_
);
509 } else { /* white space */
510 lce_place_
= nargv
[lce_optind_
];
512 optchar
= lce_parse_long_options__(nargv
, options
, long_options
,
514 lce_place_
= LCE_EMSG_
;
517 if (*++oli
!= ':') { /* doesn't take argument */
520 } else { /* takes (optional) argument */
522 if (*lce_place_
){ /* no white space */
523 lce_optarg_
= lce_place_
;
524 } else if (oli
[1] != ':'){ /* arg not optional */
525 if (++lce_optind_
>= nargc
) { /* no arg */
526 lce_place_
= LCE_EMSG_
;
527 if (LCE_PRINT_ERROR_
)
528 lce_warnx_(lce_recargchar_
, optchar
);
529 lce_optopt_
= optchar
;
530 return (LCE_BADARG_
);
532 lce_optarg_
= nargv
[lce_optind_
];
535 lce_place_
= LCE_EMSG_
;
538 /* dump back option letter */
543 lce_getsubopt_(char **optionp
, char * const *tokens
, char **valuep
)
548 lce_suboptarg_
= *valuep
= NULL
;
550 if (!optionp
|| !*optionp
)
553 /* skip leading white-space, commas */
554 for (p
= *optionp
; *p
&& (*p
== ',' || *p
== ' ' || *p
== '\t'); ++p
) ;
561 /* save the start of the token, and skip the rest of the token. */
562 for (lce_suboptarg_
= p
;
563 *++p
&& *p
!= ',' && *p
!= '=' && *p
!= ' ' && *p
!= '\t';) ;
567 * If there's an equals sign, set the value pointer, and
568 * skip over the value part of the token. Terminate the
574 *p
&& *p
!= ',' && *p
!= ' ' && *p
!= '\t'; ++p
) ;
580 /* Skip any whitespace or commas after this token. */
581 for (; *p
&& (*p
== ',' || *p
== ' ' || *p
== '\t'); ++p
) ;
584 /* set optionp for next round. */
587 for (cnt
= 0; *tokens
; ++tokens
, ++cnt
)
588 if (!strcmp(lce_suboptarg_
, *tokens
))
594 lce_getopt_(int argc
, char * const *argv
, const char *optstring
)
596 #ifdef LCE_GETOPT_PERMUTE_ARGS
597 return (lce_getopt_internal_(argc
, argv
, optstring
, NULL
, NULL
,
600 return (lce_getopt_internal_(argc
, argv
, optstring
, NULL
, NULL
, 0));
601 #endif /* LCE_GETOPT_PERMUTE_ARGS */
605 lce_getopt_long_(int argc
, char * const *argv
, const char *optstring
,
606 const struct option
*longopts
, int *longindex
)
608 #ifdef LCE_GETOPT_LONG_PERMUTE_ARGS
609 return (lce_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
,
612 return (lce_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
, 0
614 #endif /* LCE_GETOPT_LONG_PERMUTE_ARGS */
618 lce_getopt_long_only_(int argc
, char * const *argv
, const char *optstring
,
619 const struct option
*longopts
, int *longindex
)
621 #ifdef LCE_GETOPT_LONG_ONLY_PERMUTE_ARGS
622 return (lce_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
,
623 LCE_FLAG_PERMUTE_
| I_FLAG_LONGONLY_
));
625 return (lce_getopt_internal_(argc
, argv
, optstring
, longopts
, longindex
,
626 LCE_FLAG_LONGONLY_
));
627 #endif /* LCE_GETOPT_LONG_ONLY_PERMUTE_ARGS */
629 #endif /* LCE_GETOPT_LONG_IMPLEMENTATION */
630 #endif /* !LCE_GETOPT_LONG_H */