switch the "namespace" to "lce"
[libcext.git] / getopt_long.h
1 /*
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Dieter Baron and Thomas Klausner.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
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.
22 *
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.
34 *
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.
38 */
39
40 /* https://git.datadissipation.net */
41 #ifndef LCE_GETOPT_LONG_H
42 #define LCE_GETOPT_LONG_H 1
43
44 #ifdef LCE_GETOPT_LONG_INCLUDE_LIBC
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #endif /* LCE_GETOPT_LONG_INCLUDE_LIBC */
50
51 #ifndef HAVE_GETOPT_LONG
52 #define HAVE_GETOPT_LONG 1
53 #ifndef HAVE_GETOPT
54 #define HAVE_GETOPT 1
55 #endif /* !HAVE_GETOPT */
56
57 #define no_argument 0
58 #define required_argument 1
59 #define optional_argument 2
60
61 /*
62 * structs are in their own namespace, so this should be OK
63 * the worst it can do is make compiler messages worse
64 */
65 #define option lce_option_
66
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_
73
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_
78
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 */
84
85 struct lce_option_ {
86 const char *name;
87 /*
88 * one of no_argument, required_argument, and optional_argument:
89 * whether option takes an argument
90 */
91 int has_arg;
92 /* if not NULL, set *flag to val when option found */
93 int *flag;
94 /* if flag not NULL, value to set *flag to; else return value */
95 int val;
96 };
97
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);
104
105 #endif /* !HAVE_GETOPT_LONG */
106
107 #ifdef LCE_GETOPT_LONG_IMPLEMENTATION
108 #define LCE_PRINT_ERROR_ ((lce_opterr_) && (*options != ':'))
109
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 */
113
114 /* return values */
115 #define LCE_BADCH_ (int) '?'
116 #define LCE_BADARG_ ((*options == ':') ? (int) ':' : (int) '?')
117 #define LCE_INORDER_ (int) 1
118
119 #define LCE_EMSG_ ""
120
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 */
127
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] */
133
134 /* Error messages */
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";
141
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 *);
149
150 /*
151 * Own warnx() for portability
152 */
153 void
154 lce_warnx_(const char *fmt, ...)
155 {
156 va_list args;
157
158 va_start(args, fmt);
159 fprintf(stderr, "%s: ", lce_progname_);
160 vfprintf(stderr, fmt, args);
161 fputc('\n', stderr);
162 va_end(args);
163 }
164
165 /*
166 * Compute the greatest common divisor of a and b.
167 */
168 static int
169 lce_gcd_(int a, int b)
170 {
171 int c;
172
173 c = a % b;
174 while (c != 0) {
175 a = b;
176 b = c;
177 c = a % b;
178 }
179
180 return (b);
181 }
182
183 /*
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
186 * in each block).
187 */
188 static void
189 lce_permute_args_(int panonopt_start, int panonopt_end, int opt_end,
190 char * const *nargv)
191 {
192 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
193 char *swap;
194
195 /*
196 * compute lengths of blocks and number and size of cycles
197 */
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;
202
203 for (i = 0; i < ncycle; i++) {
204 cstart = panonopt_end+i;
205 pos = cstart;
206 for (j = 0; j < cyclelen; j++) {
207 if (pos >= panonopt_end)
208 pos -= nnonopts;
209 else
210 pos += nopts;
211 swap = nargv[pos];
212 /* LINTED const cast */
213 ((char **) nargv)[pos] = nargv[cstart];
214 /* LINTED const cast */
215 ((char **) nargv)[cstart] = swap;
216 }
217 }
218 }
219
220 /*
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.
224 */
225 static int
226 lce_parse_long_options__(char * const *nargv, const char *options,
227 const struct option *long_options, int *idx, int
228 short_too)
229 {
230 char *current_argv, *has_equal;
231 size_t current_argv_len;
232 int i, match;
233
234 current_argv = lce_place_;
235 match = -1;
236
237 lce_optind_++;
238
239 if ((has_equal = strchr(current_argv, '=')) != NULL) {
240 /* argument found (--option=arg) */
241 current_argv_len = has_equal - current_argv;
242 has_equal++;
243 } else {
244 current_argv_len = strlen(current_argv);
245 }
246 for (i = 0; long_options[i].name; i++) {
247 /* find matching long option */
248 if (strncmp(current_argv, long_options[i].name,
249 current_argv_len))
250 continue;
251
252 if (strlen(long_options[i].name) == current_argv_len) {
253 /* exact match */
254 match = i;
255 break;
256 }
257 /*
258 * If this is a known short option, don't allow
259 * a partial match of a single character.
260 */
261 if (short_too && current_argv_len == 1)
262 continue;
263
264 if (match == -1) { /* partial match */
265 match = i;
266 } else {
267 /* ambiguous abbreviation */
268 if (LCE_PRINT_ERROR_)
269 lce_warnx_(lce_ambig_, (int) current_argv_len,
270 current_argv);
271 lce_optopt_ = 0;
272 return (LCE_BADCH_);
273 }
274 }
275 if (match != -1) { /* option found */
276 if (long_options[match].has_arg == no_argument
277 && has_equal) {
278 if (LCE_PRINT_ERROR_)
279 lce_warnx_(lce_noarg_, (int) current_argv_len,
280 current_argv);
281 /*
282 * XXX: GNU sets optopt to val regardless of flag
283 */
284 if (long_options[match].flag == NULL)
285 lce_optopt_ = long_options[match].val;
286 else
287 lce_optopt_ = 0;
288 return (LCE_BADARG_);
289 }
290 if (long_options[match].has_arg == required_argument ||
291 long_options[match].has_arg == optional_argument) {
292 if (has_equal){
293 lce_optarg_ = has_equal;
294 } else if (long_options[match].has_arg ==
295 required_argument) {
296 /*
297 * optional argument doesn't use next nargv
298 */
299 lce_optarg_ = nargv[lce_optind_++];
300 }
301 }
302 if ((long_options[match].has_arg == required_argument)
303 && (lce_optarg_ == NULL)) {
304 /*
305 * Missing argument; leading ':' indicates no error
306 * should be generated.
307 */
308 if (LCE_PRINT_ERROR_)
309 lce_warnx_(lce_recargstring_,
310 current_argv);
311 /*
312 * XXX: GNU sets optopt to val regardless of flag
313 */
314 if (long_options[match].flag == NULL)
315 lce_optopt_ = long_options[match].val;
316 else
317 lce_optopt_ = 0;
318 --lce_optind_;
319 return (LCE_BADARG_);
320 }
321 } else { /* unknown option */
322 if (short_too) {
323 --lce_optind_;
324 return (-1);
325 }
326 if (LCE_PRINT_ERROR_)
327 lce_warnx_(lce_illoptstring_, current_argv);
328 lce_optopt_ = 0;
329 return (LCE_BADCH_);
330 }
331 if (idx)
332 *idx = match;
333 if (long_options[match].flag) {
334 *long_options[match].flag = long_options[match].val;
335 return (0);
336 } else {
337 return (long_options[match].val);
338 }
339 }
340
341 /*
342 * lce_getopt_internal_ --
343 * Parse argc/argv argument vector. Called by user level routines.
344 */
345 static int
346 lce_getopt_internal_(int nargc, char *const *nargv, const char *options,
347 const struct option *long_options, int *idx, int flags)
348 {
349 char *oli; /* option letter list index */
350 int optchar, short_too;
351 static int posix_me_harder = -1;
352
353 if (options == NULL)
354 return (-1);
355
356 lce_progname_ = nargv[0];
357
358 /*
359 * XXX Some GNU programs (like cvs) set optind to 0 instead of
360 * XXX using optreset. Work around this braindamage.
361 */
362 if (lce_optind_ == 0)
363 lce_optind_ = lce_optreset_ = 1;
364
365 /*
366 * Disable GNU extensions if POSIXLY_CORRECT is set or options
367 * string begins with a '+'.
368 */
369 if (posix_me_harder == -1 || lce_optreset_)
370 posix_me_harder = (getenv("POSIXLY_CORRECT") != NULL);
371 if (*options == '-')
372 flags |= LCE_FLAG_ALLARGS_;
373 else if (posix_me_harder || *options == '+')
374 flags &= ~LCE_FLAG_PERMUTE_;
375 if (*options == '+' || *options == '-')
376 options++;
377
378 lce_optarg_ = NULL;
379 if (lce_optreset_)
380 lce_nonopt_start_ = lce_nonopt_end_ = -1;
381 start:
382 if (lce_optreset_ || !*lce_place_) { /* update scanning pointer */
383 lce_optreset_ = 0;
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_,
389 lce_optind_, nargv);
390 lce_optind_ -= lce_nonopt_end_ - lce_nonopt_start_;
391 } else if (lce_nonopt_start_ != -1) {
392 /*
393 * If we skipped non-options, set optind
394 * to the first of them.
395 */
396 lce_optind_ = lce_nonopt_start_;
397 }
398 lce_nonopt_start_ = lce_nonopt_end_ = -1;
399 return (-1);
400 }
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_) {
405 /*
406 * GNU extension:
407 * return non-option as argument to option 1
408 */
409 lce_optarg_ = nargv[lce_optind_++];
410 return (LCE_INORDER_);
411 }
412 if (!(flags & LCE_FLAG_PERMUTE_)) {
413 /*
414 * If no permutation wanted, stop parsing
415 * at first non-option.
416 */
417 return (-1);
418 }
419 /* do permutation */
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_,
424 lce_optind_, nargv);
425 lce_nonopt_start_ = lce_optind_ -
426 (lce_nonopt_end_ -
427 lce_nonopt_start_);
428 lce_nonopt_end_ = -1;
429 }
430 lce_optind_++;
431 /* process next argument */
432 goto start;
433 }
434 if (lce_nonopt_start_ != -1 && lce_nonopt_end_ == -1)
435 lce_nonopt_end_ = lce_optind_;
436
437 /*
438 * If we have "-" do nothing, if "--" we are done.
439 */
440 if (lce_place_[1] != '\0' && *++lce_place_ == '-' && lce_place_[1] ==
441 '\0') {
442 lce_optind_++;
443 lce_place_ = LCE_EMSG_;
444 /*
445 * We found an option (--), so if we skipped
446 * non-options, we have to permute.
447 */
448 if (lce_nonopt_end_ != -1) {
449 lce_permute_args_(lce_nonopt_start_, lce_nonopt_end_,
450 lce_optind_, nargv);
451 lce_optind_ -= lce_nonopt_end_ - lce_nonopt_start_;
452 }
453 lce_nonopt_start_ = lce_nonopt_end_ = -1;
454 return (-1);
455 }
456 }
457
458 /*
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()
463 */
464 if (long_options != NULL && lce_place_ != nargv[lce_optind_] &&
465 (*lce_place_ == '-' || (flags & LCE_FLAG_LONGONLY_))) {
466 short_too = 0;
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 */
472
473 optchar = lce_parse_long_options__(nargv, options, long_options,
474 idx, short_too);
475 if (optchar != -1) {
476 lce_place_ = LCE_EMSG_;
477 return (optchar);
478 }
479 }
480
481 if ((optchar = (int) *lce_place_++) == (int) ':' ||
482 (optchar == (int) '-' && *lce_place_ != '\0') ||
483 (oli = strchr(options, optchar)) == NULL) {
484 /*
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 ':').
488 */
489 if (optchar == (int) '-' && *lce_place_ == '\0')
490 return (-1);
491 if (!*lce_place_)
492 ++lce_optind_;
493 if (LCE_PRINT_ERROR_)
494 lce_warnx_(lce_illoptchar_, optchar);
495 lce_optopt_ = optchar;
496 return (LCE_BADCH_);
497 }
498 if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
499 /* -W long-option */
500 if (*lce_place_) { /* no space */
501 /* NOTHING */
502 ;
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_];
511 }
512 optchar = lce_parse_long_options__(nargv, options, long_options,
513 idx, 0);
514 lce_place_ = LCE_EMSG_;
515 return (optchar);
516 }
517 if (*++oli != ':') { /* doesn't take argument */
518 if (!*lce_place_)
519 ++lce_optind_;
520 } else { /* takes (optional) argument */
521 lce_optarg_ = NULL;
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_);
531 } else {
532 lce_optarg_ = nargv[lce_optind_];
533 }
534 }
535 lce_place_ = LCE_EMSG_;
536 ++lce_optind_;
537 }
538 /* dump back option letter */
539 return (optchar);
540 }
541
542 int
543 lce_getsubopt_(char **optionp, char * const *tokens, char **valuep)
544 {
545 int cnt;
546 char *p;
547
548 lce_suboptarg_ = *valuep = NULL;
549
550 if (!optionp || !*optionp)
551 return (-1);
552
553 /* skip leading white-space, commas */
554 for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p) ;
555
556 if (!*p) {
557 *optionp = p;
558 return (-1);
559 }
560
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';) ;
564
565 if (*p) {
566 /*
567 * If there's an equals sign, set the value pointer, and
568 * skip over the value part of the token. Terminate the
569 * token.
570 */
571 if (*p == '=') {
572 *p = '\0';
573 for (*valuep = ++p;
574 *p && *p != ',' && *p != ' ' && *p != '\t'; ++p) ;
575 if (*p)
576 *p++ = '\0';
577 } else {
578 *p++ = '\0';
579 }
580 /* Skip any whitespace or commas after this token. */
581 for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p) ;
582 }
583
584 /* set optionp for next round. */
585 *optionp = p;
586
587 for (cnt = 0; *tokens; ++tokens, ++cnt)
588 if (!strcmp(lce_suboptarg_, *tokens))
589 return (cnt);
590 return (-1);
591 }
592
593 int
594 lce_getopt_(int argc, char * const *argv, const char *optstring)
595 {
596 #ifdef LCE_GETOPT_PERMUTE_ARGS
597 return (lce_getopt_internal_(argc, argv, optstring, NULL, NULL,
598 LCE_FLAG_PERMUTE_));
599 #else
600 return (lce_getopt_internal_(argc, argv, optstring, NULL, NULL, 0));
601 #endif /* LCE_GETOPT_PERMUTE_ARGS */
602 }
603
604 int
605 lce_getopt_long_(int argc, char * const *argv, const char *optstring,
606 const struct option *longopts, int *longindex)
607 {
608 #ifdef LCE_GETOPT_LONG_PERMUTE_ARGS
609 return (lce_getopt_internal_(argc, argv, optstring, longopts, longindex,
610 LCE_FLAG_PERMUTE_));
611 #else
612 return (lce_getopt_internal_(argc, argv, optstring, longopts, longindex, 0
613 ));
614 #endif /* LCE_GETOPT_LONG_PERMUTE_ARGS */
615 }
616
617 int
618 lce_getopt_long_only_(int argc, char * const *argv, const char *optstring,
619 const struct option *longopts, int *longindex)
620 {
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_));
624 #else
625 return (lce_getopt_internal_(argc, argv, optstring, longopts, longindex,
626 LCE_FLAG_LONGONLY_));
627 #endif /* LCE_GETOPT_LONG_ONLY_PERMUTE_ARGS */
628 }
629 #endif /* LCE_GETOPT_LONG_IMPLEMENTATION */
630 #endif /* !LCE_GETOPT_LONG_H */