prism2.device: fix strict aliasing issue detected with gcc 4.8.3
[AROS.git] / compiler / posixc / getopt_long.c
blobc5ddae1e632e4445a7e4e7763d576e53eeb841e0
1 /* $OpenBSD: getopt_long.c,v 1.21 2006/09/22 17:22:05 millert Exp $ */
2 /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
4 /*
5 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * Sponsored in part by the Defense Advanced Research Projects
20 * Agency (DARPA) and Air Force Research Laboratory, Air Force
21 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
23 /*-
24 * Copyright (c) 2000 The NetBSD Foundation, Inc.
25 * All rights reserved.
27 * This code is derived from software contributed to The NetBSD Foundation
28 * by Dieter Baron and Thomas Klausner.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the NetBSD
41 * Foundation, Inc. and its contributors.
42 * 4. Neither the name of The NetBSD Foundation nor the names of its
43 * contributors may be used to endorse or promote products derived
44 * from this software without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
47 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
48 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
49 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
50 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
51 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
52 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
53 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
54 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
56 * POSSIBILITY OF SUCH DAMAGE.
59 #if 0
60 #if defined(LIBC_SCCS) && !defined(lint)
61 static char *rcsid = "$OpenBSD: getopt_long.c,v 1.16 2004/02/04 18:17:25 millert Exp $";
62 #endif /* LIBC_SCCS and not lint */
63 #endif
65 #if defined(__AROS__)
66 void warnx(const char * s, ...) {}
67 // FIXME: implement me
68 #else
69 #include <err.h>
70 #endif
72 #include <errno.h>
73 #include <getopt.h>
74 #include <stdlib.h>
75 #include <string.h>
77 #define GNU_COMPATIBLE /* Be more compatible, configure's use us! */
79 #if 0 /* we prefer to keep our getopt(3) */
80 #define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
81 #endif
83 #ifdef REPLACE_GETOPT
84 int opterr = 1; /* if error message should be printed */
85 int optind = 1; /* index into parent argv vector */
86 int optopt = '?'; /* character checked for validity */
87 int optreset; /* reset getopt */
88 char *optarg; /* argument associated with option */
89 #endif
91 #define PRINT_ERROR ((opterr) && (*options != ':'))
93 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
94 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
95 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
97 /* return values */
98 #define BADCH (int)'?'
99 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
100 #define INORDER (int)1
102 #define EMSG ""
104 #ifdef GNU_COMPATIBLE
105 #define NO_PREFIX (-1)
106 #define D_PREFIX 0
107 #define DD_PREFIX 1
108 #define W_PREFIX 2
109 #endif
111 static int getopt_internal(int, char * const *, const char *,
112 const struct option *, int *, int);
113 static int parse_long_options(char * const *, const char *,
114 const struct option *, int *, int, int);
115 static int gcd(int, int);
116 static void permute_args(int, int, int, char * const *);
118 static char *place = EMSG; /* option letter processing */
120 /* XXX: set optreset to 1 rather than these two */
121 static int nonopt_start = -1; /* first non option argument (for permute) */
122 static int nonopt_end = -1; /* first option after non options (for permute) */
124 /* Error messages */
125 static const char recargchar[] = "option requires an argument -- %c";
126 static const char illoptchar[] = "illegal option -- %c"; /* From P1003.2 */
127 #ifdef GNU_COMPATIBLE
128 static int dash_prefix = NO_PREFIX;
129 static const char gnuoptchar[] = "invalid option -- %c";
131 static const char recargstring[] = "option `%s%s' requires an argument";
132 static const char ambig[] = "option `%s%.*s' is ambiguous";
133 static const char noarg[] = "option `%s%.*s' doesn't allow an argument";
134 static const char illoptstring[] = "unrecognized option `%s%s'";
135 #else
136 static const char recargstring[] = "option requires an argument -- %s";
137 static const char ambig[] = "ambiguous option -- %.*s";
138 static const char noarg[] = "option doesn't take an argument -- %.*s";
139 static const char illoptstring[] = "unknown option -- %s";
140 #endif
143 * Compute the greatest common divisor of a and b.
145 static int
146 gcd(int a, int b)
148 int c;
150 c = a % b;
151 while (c != 0) {
152 a = b;
153 b = c;
154 c = a % b;
157 return (b);
161 * Exchange the block from nonopt_start to nonopt_end with the block
162 * from nonopt_end to opt_end (keeping the same order of arguments
163 * in each block).
165 static void
166 permute_args(int panonopt_start, int panonopt_end, int opt_end,
167 char * const *nargv)
169 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
170 char *swap;
173 * compute lengths of blocks and number and size of cycles
175 nnonopts = panonopt_end - panonopt_start;
176 nopts = opt_end - panonopt_end;
177 ncycle = gcd(nnonopts, nopts);
178 cyclelen = (opt_end - panonopt_start) / ncycle;
180 for (i = 0; i < ncycle; i++) {
181 cstart = panonopt_end+i;
182 pos = cstart;
183 for (j = 0; j < cyclelen; j++) {
184 if (pos >= panonopt_end)
185 pos -= nnonopts;
186 else
187 pos += nopts;
188 swap = nargv[pos];
189 /* LINTED const cast */
190 ((char **) nargv)[pos] = nargv[cstart];
191 /* LINTED const cast */
192 ((char **)nargv)[cstart] = swap;
198 * parse_long_options --
199 * Parse long options in argc/argv argument vector.
200 * Returns -1 if short_too is set and the option does not match long_options.
202 static int
203 parse_long_options(char * const *nargv, const char *options,
204 const struct option *long_options, int *idx, int short_too, int flags)
206 char *current_argv, *has_equal;
207 #ifdef GNU_COMPATIBLE
208 char *current_dash;
209 #endif
210 size_t current_argv_len;
211 int i, match, exact_match, second_partial_match;
213 current_argv = place;
214 #ifdef GNU_COMPATIBLE
215 switch (dash_prefix) {
216 case D_PREFIX:
217 current_dash = "-";
218 break;
219 case DD_PREFIX:
220 current_dash = "--";
221 break;
222 case W_PREFIX:
223 current_dash = "-W ";
224 break;
225 default:
226 current_dash = "";
227 break;
229 #endif
230 match = -1;
231 exact_match = 0;
232 second_partial_match = 0;
234 optind++;
236 if ((has_equal = strchr(current_argv, '=')) != NULL) {
237 /* argument found (--option=arg) */
238 current_argv_len = has_equal - current_argv;
239 has_equal++;
240 } else
241 current_argv_len = strlen(current_argv);
243 for (i = 0; long_options[i].name; i++) {
244 /* find matching long option */
245 if (strncmp(current_argv, long_options[i].name,
246 current_argv_len))
247 continue;
249 if (strlen(long_options[i].name) == current_argv_len) {
250 /* exact match */
251 match = i;
252 exact_match = 1;
253 break;
256 * If this is a known short option, don't allow
257 * a partial match of a single character.
259 if (short_too && current_argv_len == 1)
260 continue;
262 if (match == -1) /* first partial match */
263 match = i;
264 else if ((flags & FLAG_LONGONLY) ||
265 long_options[i].has_arg !=
266 long_options[match].has_arg ||
267 long_options[i].flag != long_options[match].flag ||
268 long_options[i].val != long_options[match].val)
269 second_partial_match = 1;
271 if (!exact_match && second_partial_match) {
272 /* ambiguous abbreviation */
273 if (PRINT_ERROR)
274 warnx(ambig,
275 #ifdef GNU_COMPATIBLE
276 current_dash,
277 #endif
278 (int)current_argv_len,
279 current_argv);
280 optopt = 0;
281 return (BADCH);
283 if (match != -1) { /* option found */
284 if (long_options[match].has_arg == no_argument
285 && has_equal) {
286 if (PRINT_ERROR)
287 warnx(noarg,
288 #ifdef GNU_COMPATIBLE
289 current_dash,
290 #endif
291 (int)current_argv_len,
292 current_argv);
294 * XXX: GNU sets optopt to val regardless of flag
296 if (long_options[match].flag == NULL)
297 optopt = long_options[match].val;
298 else
299 optopt = 0;
300 #ifdef GNU_COMPATIBLE
301 return (BADCH);
302 #else
303 return (BADARG);
304 #endif
306 if (long_options[match].has_arg == required_argument ||
307 long_options[match].has_arg == optional_argument) {
308 if (has_equal)
309 optarg = has_equal;
310 else if (long_options[match].has_arg ==
311 required_argument) {
313 * optional argument doesn't use next nargv
315 optarg = nargv[optind++];
318 if ((long_options[match].has_arg == required_argument)
319 && (optarg == NULL)) {
321 * Missing argument; leading ':' indicates no error
322 * should be generated.
324 if (PRINT_ERROR)
325 warnx(recargstring,
326 #ifdef GNU_COMPATIBLE
327 current_dash,
328 #endif
329 current_argv);
331 * XXX: GNU sets optopt to val regardless of flag
333 if (long_options[match].flag == NULL)
334 optopt = long_options[match].val;
335 else
336 optopt = 0;
337 --optind;
338 return (BADARG);
340 } else { /* unknown option */
341 if (short_too) {
342 --optind;
343 return (-1);
345 if (PRINT_ERROR)
346 warnx(illoptstring,
347 #ifdef GNU_COMPATIBLE
348 current_dash,
349 #endif
350 current_argv);
351 optopt = 0;
352 return (BADCH);
354 if (idx)
355 *idx = match;
356 if (long_options[match].flag) {
357 *long_options[match].flag = long_options[match].val;
358 return (0);
359 } else
360 return (long_options[match].val);
364 * getopt_internal --
365 * Parse argc/argv argument vector. Called by user level routines.
367 static int
368 getopt_internal(int nargc, char * const *nargv, const char *options,
369 const struct option *long_options, int *idx, int flags)
371 char *oli; /* option letter list index */
372 int optchar, short_too;
373 int posixly_correct; /* no static, can be changed on the fly */
375 if (options == NULL)
376 return (-1);
379 * Disable GNU extensions if POSIXLY_CORRECT is set or options
380 * string begins with a '+'.
382 posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
383 #ifdef GNU_COMPATIBLE
384 if (*options == '-')
385 flags |= FLAG_ALLARGS;
386 else if (posixly_correct || *options == '+')
387 flags &= ~FLAG_PERMUTE;
388 #else
389 if (posixly_correct || *options == '+')
390 flags &= ~FLAG_PERMUTE;
391 else if (*options == '-')
392 flags |= FLAG_ALLARGS;
393 #endif
394 if (*options == '+' || *options == '-')
395 options++;
398 * XXX Some GNU programs (like cvs) set optind to 0 instead of
399 * XXX using optreset. Work around this braindamage.
401 if (optind == 0)
402 optind = optreset = 1;
404 optarg = NULL;
405 if (optreset)
406 nonopt_start = nonopt_end = -1;
407 start:
408 if (optreset || !*place) { /* update scanning pointer */
409 optreset = 0;
410 if (optind >= nargc) { /* end of argument vector */
411 place = EMSG;
412 if (nonopt_end != -1) {
413 /* do permutation, if we have to */
414 permute_args(nonopt_start, nonopt_end,
415 optind, nargv);
416 optind -= nonopt_end - nonopt_start;
418 else if (nonopt_start != -1) {
420 * If we skipped non-options, set optind
421 * to the first of them.
423 optind = nonopt_start;
425 nonopt_start = nonopt_end = -1;
426 return (-1);
428 if (*(place = nargv[optind]) != '-' ||
429 #ifdef GNU_COMPATIBLE
430 place[1] == '\0') {
431 #else
432 (place[1] == '\0' && strchr(options, '-') == NULL)) {
433 #endif
434 place = EMSG; /* found non-option */
435 if (flags & FLAG_ALLARGS) {
437 * GNU extension:
438 * return non-option as argument to option 1
440 optarg = nargv[optind++];
441 return (INORDER);
443 if (!(flags & FLAG_PERMUTE)) {
445 * If no permutation wanted, stop parsing
446 * at first non-option.
448 return (-1);
450 /* do permutation */
451 if (nonopt_start == -1)
452 nonopt_start = optind;
453 else if (nonopt_end != -1) {
454 permute_args(nonopt_start, nonopt_end,
455 optind, nargv);
456 nonopt_start = optind -
457 (nonopt_end - nonopt_start);
458 nonopt_end = -1;
460 optind++;
461 /* process next argument */
462 goto start;
464 if (nonopt_start != -1 && nonopt_end == -1)
465 nonopt_end = optind;
468 * If we have "-" do nothing, if "--" we are done.
470 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
471 optind++;
472 place = EMSG;
474 * We found an option (--), so if we skipped
475 * non-options, we have to permute.
477 if (nonopt_end != -1) {
478 permute_args(nonopt_start, nonopt_end,
479 optind, nargv);
480 optind -= nonopt_end - nonopt_start;
482 nonopt_start = nonopt_end = -1;
483 return (-1);
488 * Check long options if:
489 * 1) we were passed some
490 * 2) the arg is not just "-"
491 * 3) either the arg starts with -- we are getopt_long_only()
493 if (long_options != NULL && place != nargv[optind] &&
494 (*place == '-' || (flags & FLAG_LONGONLY))) {
495 short_too = 0;
496 #ifdef GNU_COMPATIBLE
497 dash_prefix = D_PREFIX;
498 #endif
499 if (*place == '-') {
500 place++; /* --foo long option */
501 #ifdef GNU_COMPATIBLE
502 dash_prefix = DD_PREFIX;
503 #endif
504 } else if (*place != ':' && strchr(options, *place) != NULL)
505 short_too = 1; /* could be short option too */
507 optchar = parse_long_options(nargv, options, long_options,
508 idx, short_too, flags);
509 if (optchar != -1) {
510 place = EMSG;
511 return (optchar);
515 if ((optchar = (int)*place++) == (int)':' ||
516 (optchar == (int)'-' && *place != '\0') ||
517 (oli = strchr(options, optchar)) == NULL) {
519 * If the user specified "-" and '-' isn't listed in
520 * options, return -1 (non-option) as per POSIX.
521 * Otherwise, it is an unknown option character (or ':').
523 if (optchar == (int)'-' && *place == '\0')
524 return (-1);
525 if (!*place)
526 ++optind;
527 #ifdef GNU_COMPATIBLE
528 if (PRINT_ERROR)
529 warnx(posixly_correct ? illoptchar : gnuoptchar,
530 optchar);
531 #else
532 if (PRINT_ERROR)
533 warnx(illoptchar, optchar);
534 #endif
535 optopt = optchar;
536 return (BADCH);
538 if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
539 /* -W long-option */
540 if (*place) /* no space */
541 /* NOTHING */;
542 else if (++optind >= nargc) { /* no arg */
543 place = EMSG;
544 if (PRINT_ERROR)
545 warnx(recargchar, optchar);
546 optopt = optchar;
547 return (BADARG);
548 } else /* white space */
549 place = nargv[optind];
550 #ifdef GNU_COMPATIBLE
551 dash_prefix = W_PREFIX;
552 #endif
553 optchar = parse_long_options(nargv, options, long_options,
554 idx, 0, flags);
555 place = EMSG;
556 return (optchar);
558 if (*++oli != ':') { /* doesn't take argument */
559 if (!*place)
560 ++optind;
561 } else { /* takes (optional) argument */
562 optarg = NULL;
563 if (*place) /* no white space */
564 optarg = place;
565 else if (oli[1] != ':') { /* arg not optional */
566 if (++optind >= nargc) { /* no arg */
567 place = EMSG;
568 if (PRINT_ERROR)
569 warnx(recargchar, optchar);
570 optopt = optchar;
571 return (BADARG);
572 } else
573 optarg = nargv[optind];
575 place = EMSG;
576 ++optind;
578 /* dump back option letter */
579 return (optchar);
582 #ifdef REPLACE_GETOPT
584 * getopt --
585 * Parse argc/argv argument vector.
587 * [eventually this will replace the BSD getopt]
590 getopt(int nargc, char * const *nargv, const char *options)
594 * We don't pass FLAG_PERMUTE to getopt_internal() since
595 * the BSD getopt(3) (unlike GNU) has never done this.
597 * Furthermore, since many privileged programs call getopt()
598 * before dropping privileges it makes sense to keep things
599 * as simple (and bug-free) as possible.
601 return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
603 #endif /* REPLACE_GETOPT */
606 /*****************************************************************************
608 NAME */
609 int getopt_long(
611 /* SYNOPSIS */
612 int nargc,
613 char * const *nargv,
614 const char *options,
615 const struct option *long_options,
616 int *idx)
618 /* FUNCTION
619 The getopt_long() function is similar to getopt() but it accepts options
620 in two forms: words and characters. The getopt_long() function provides
621 a superset of the functionality of getopt(3). The getopt_long() function
622 can be used in two ways. In the first way, every long option understood
623 by the program has a corresponding short option, and the option structure
624 is only used to translate from long options to short options. When used
625 in this fashion, getopt_long() behaves identically to getopt(3). This is
626 a good way to add long option processing to an existing program with the
627 minimum of rewriting.
629 In the second mechanism, a long option sets a flag in the option struc-
630 ture passed, or will store a pointer to the command line argument in the
631 option structure passed to it for options that take arguments. Addition-
632 ally, the long option's argument may be specified as a single argument
633 with an equal sign, e.g.,
635 myprogram --myoption=somevalue
637 When a long option is processed, the call to getopt_long() will return 0.
638 For this reason, long option processing without shortcuts is not back-
639 wards compatible with getopt(3).
641 It is possible to combine these methods, providing for long options pro-
642 cessing with short option equivalents for some options. Less frequently
643 used options would be processed as long options only.
645 The getopt_long() call requires a structure to be initialized describing
646 the long options. The structure is:
648 struct option {
649 char *name;
650 int has_arg;
651 int *flag;
652 int val;
655 The name field should contain the option name without the leading double
656 dash.
658 The has_arg field should be one of:
660 no_argument no argument to the option is expect
661 required_argument an argument to the option is required
662 optional_argument an argument to the option may be presented.
664 If flag is not NULL, then the integer pointed to by it will be set to the
665 value in the val field. If the flag field is NULL, then the val field
666 will be returned. Setting flag to NULL and setting val to the corre-
667 sponding short option will make this function act just like getopt(3).
669 If the longindex field is not NULL, then the integer pointed to by it
670 will be set to the index of the long option relative to longopts.
672 The last element of the longopts array has to be filled with zeroes.
674 INPUTS
675 See above
677 RESULT
678 If the flag field in struct option is NULL, getopt_long() and
679 getopt_long_only() return the value specified in the val field, which is
680 usually just the corresponding short option. If flag is not NULL, these
681 functions return 0 and store val in the location pointed to by flag.
682 These functions return `:' if there was a missing option argument, `?' if
683 the user specified an unknown or ambiguous option, and -1 when the argu-
684 ment list has been exhausted.
686 NOTES
687 Due to the usage of global variables this function is now put in
688 the static link library. This means each compilation unit using
689 getopt_long has its own getopt_long state tracking.
691 EXAMPLE
693 BUGS
695 SEE ALSO
696 getopt()
698 INTERNALS
700 ******************************************************************************/
703 return (getopt_internal(nargc, nargv, options, long_options, idx,
704 FLAG_PERMUTE));
708 /*****************************************************************************
710 NAME */
711 int getopt_long_only(
713 /* SYNOPSIS */
714 int nargc,
715 char * const *nargv,
716 const char *options,
717 const struct option *long_options,
718 int *idx)
720 /* FUNCTION
721 The getopt_long_only() function behaves identically to getopt_long() with
722 the exception that long options may start with `-' in addition to `--'.
723 If an option starting with `-' does not match a long option but does
724 match a single-character option, the single-character option is returned.
726 INPUTS
728 RESULT
730 NOTES
732 EXAMPLE
734 BUGS
736 SEE ALSO
737 getopt(), getopt_long()
739 INTERNALS
741 ******************************************************************************/
744 return (getopt_internal(nargc, nargv, options, long_options, idx,
745 FLAG_PERMUTE|FLAG_LONGONLY));