2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
23 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
24 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 2000 The NetBSD Foundation, Inc.
34 * All rights reserved.
36 * This code is derived from software contributed to The NetBSD Foundation
37 * by Dieter Baron and Thomas Klausner.
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. All advertising materials mentioning features or use of this software
48 * must display the following acknowledgement:
49 * This product includes software developed by the NetBSD
50 * Foundation, Inc. and its contributors.
51 * 4. Neither the name of The NetBSD Foundation nor the names of its
52 * contributors may be used to endorse or promote products derived
53 * from this software without specific prior written permission.
55 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
56 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
57 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
58 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
59 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
60 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
61 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
62 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
63 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
65 * POSSIBILITY OF SUCH DAMAGE.
68 #pragma weak _getopt_clip = getopt_clip
69 #pragma weak _getopt_long = getopt_long
70 #pragma weak _getopt_long_only = getopt_long_only
79 #include "_libc_gettext.h"
81 static int optreset
= 0; /* keep track of first entry to getopt() */
82 #define PRINT_ERROR ((opterr) && (*options != ':'))
83 #define FLAG_IS_SET(flag) ((flags & flag) != 0) /* is flag turned on? */
85 /* Determine if an argument is required for this long option */
86 #define LONGOPT_REQUIRES_ARG(longopt) \
87 ((((longopt).has_arg == optional_argument) && \
88 (!FLAG_IS_SET(FLAG_OPTIONAL_ARGS))) || \
89 ((longopt).has_arg == required_argument))
91 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
92 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "1" */
93 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only() */
94 #define FLAG_OPTIONAL_ARGS 0x08 /* allow optional arguments to options */
95 #define FLAG_REQUIRE_EQUIVALENTS 0x10 /* require short<->long equivalents */
96 #define FLAG_ABBREV 0x20 /* long option abbreviation allowed. */
97 #define FLAG_W_SEMICOLON 0x40 /* Support for W; in optstring */
98 #define FLAG_PLUS_DASH_START 0x80 /* leading '+' or '-' in optstring */
101 #define BADCH (int)'?'
102 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
103 #define INORDER (int)1
107 static int getopt_internal(int, char * const *, const char *,
108 const struct option
*, int *, uint_t
);
109 static int parse_long_options(int nargc
, char * const *nargv
, const char *,
110 const struct option
*, int *, int,
112 static int gcd(int, int);
113 static void permute_args(int, int, int, char * const *);
115 static char *place
= EMSG
; /* option letter processing */
117 /* XXX: set optreset to 1 rather than these two */
118 static int nonopt_start
= -1; /* first non option argument (for permute) */
119 static int nonopt_end
= -1; /* first option after non options (for permute) */
122 * Generalized error message output.
124 * NOTE ON ERROR MESSAGES: All the error messages in this file
125 * use %s (not %c) because they are all routed through warnx_getopt(),
126 * which takes a string argument. Character arguments passed
127 * to warnxchar() are converted to strings automatically before
128 * being passed to warnx_getopt().
131 warnx_getopt(const char *argv0
, const char *msg
, const char *arg
) {
133 (void) snprintf(errbuf
, sizeof (errbuf
), msg
, argv0
, arg
);
134 (void) write(2, errbuf
, strlen(errbuf
));
135 (void) write(2, "\n", 1);
139 * Generalized error message output.
142 warnxchar(const char *argv0
, const char *msg
, const char c
) {
146 warnx_getopt(argv0
, msg
, charbuf
);
150 * Generalized error message output.
153 warnxlen(const char *argv0
, const char *msg
, int argLen
, const char *arg
) {
155 (void) strncpy(argbuf
, arg
, argLen
);
156 argbuf
[argLen
< (sizeof (argbuf
)-1)? argLen
:(sizeof (argbuf
)-1)] = '\0';
157 warnx_getopt(argv0
, msg
, argbuf
);
161 * Compute the greatest common divisor of a and b.
179 * Exchange the block from nonopt_start to nonopt_end with the block
180 * from nonopt_end to opt_end (keeping the same order of arguments
184 permute_args(int panonopt_start
, int panonopt_end
, int opt_end
,
187 int cstart
, cyclelen
, i
, j
, ncycle
, nnonopts
, nopts
, pos
;
191 * compute lengths of blocks and number and size of cycles
193 nnonopts
= panonopt_end
- panonopt_start
;
194 nopts
= opt_end
- panonopt_end
;
195 ncycle
= gcd(nnonopts
, nopts
);
196 cyclelen
= (opt_end
- panonopt_start
) / ncycle
;
198 for (i
= 0; i
< ncycle
; i
++) {
199 cstart
= panonopt_end
+i
;
201 for (j
= 0; j
< cyclelen
; j
++) {
202 if (pos
>= panonopt_end
)
207 ((char **)nargv
)[pos
] = nargv
[cstart
];
208 ((char **)nargv
)[cstart
] = swap
;
211 } /* permute_args() */
214 * Verify that each short option (character flag) has a long equivalent,
215 * and that each long option has a short option equivalent. Note that
216 * multiple long options can map to the same character.
218 * This behavior is defined by Sun's CLIP specification (11/12/02),
219 * and currently getopt_clip() is the only getopt variant that
222 * If error output is enabled and an error is found, this function
223 * prints ONE error message (the first error found) and returns an
226 * ASSUMES: options != NULL
227 * ASSUMES: long_options may be NULL
229 * Returns < 0 if an error is found
230 * Returns >= 0 on success
233 /* LINTED: argument unused in function: nargc */
234 verify_short_long_equivalents(int nargc
,
237 const struct option
*long_options
,
245 * Find a long option for each short option
248 for (short_i
= 0; equivFound
&& (options
[short_i
] != 0); ++short_i
) {
249 ch
= options
[short_i
];
254 if (FLAG_IS_SET(FLAG_W_SEMICOLON
) &&
255 (ch
== 'W') && (options
[short_i
+1] == ';')) {
256 /* W; is a special case */
262 if (long_options
!= NULL
) {
263 for (long_i
= 0; ((!equivFound
) &&
264 (long_options
[long_i
].name
!= NULL
));
266 equivFound
= (ch
== long_options
[long_i
].val
);
269 if ((!equivFound
) && (PRINT_ERROR
)) {
272 "%s: equivalent long option required -- %s"),
278 * Find a short option for each long option. Note that if we came
279 * out of the above loop with equivFound==0, we are already done.
281 if (equivFound
&& (long_options
!= NULL
)) {
282 for (long_i
= 0; (equivFound
&&
283 (long_options
[long_i
].name
!= NULL
));
285 equivFound
= ((long_options
[long_i
].val
!= 0) &&
286 (strchr(options
, long_options
[long_i
].val
)
289 if ((!equivFound
) && (PRINT_ERROR
)) {
290 warnx_getopt(nargv
[0],
292 "%s: equivalent short option required -- %s"),
293 long_options
[long_i
].name
);
298 return (equivFound
? 0:-1);
299 } /* verify_short_long_equivalents() */
302 * parse_long_options --
303 * Parse long options in argc/argv argument vector.
304 * Returns -1 if short_too is set and the option does not match long_options.
307 parse_long_options(int nargc
, char * const *nargv
, const char *options
,
308 const struct option
*long_options
, int *idx
, int short_too
,
311 char *current_argv
= NULL
;
312 char *argv_equal_ptr
= NULL
;
313 size_t current_argv_len
= 0;
314 size_t long_option_len
= 0;
318 current_argv
= place
;
323 if ((argv_equal_ptr
= strchr(current_argv
, '=')) != NULL
) {
324 /* argument found (--option=arg) */
325 current_argv_len
= (argv_equal_ptr
- current_argv
);
328 current_argv_len
= strlen(current_argv
);
331 for (i
= 0; (long_options
[i
].name
!= NULL
); i
++) {
333 /* find matching long option */
334 if (strncmp(current_argv
, long_options
[i
].name
,
335 current_argv_len
) != 0) {
336 continue; /* no match */
338 long_option_len
= strlen(long_options
[i
].name
);
339 if ((!FLAG_IS_SET(FLAG_ABBREV
)) &&
340 (long_option_len
> current_argv_len
)) {
341 continue; /* Abbreviations are disabled */
344 if (long_option_len
== current_argv_len
) {
350 * If this is a known short option, don't allow
351 * a partial match of a single character.
353 if (short_too
&& current_argv_len
== 1)
356 if (match
== -1) /* partial match */
359 /* ambiguous abbreviation */
363 "%s: ambiguous option -- %s"),
364 (int)current_argv_len
,
371 if (match
!= -1) { /* option found */
372 if ((long_options
[match
].has_arg
== no_argument
) &&
373 (argv_equal_ptr
!= NULL
)) {
377 "%s: option doesn't take an argument -- %s"),
378 (int)current_argv_len
,
382 * XXX: GNU sets optopt to val regardless of flag
384 if (long_options
[match
].flag
== NULL
)
385 optopt
= long_options
[match
].val
;
390 if (long_options
[match
].has_arg
== required_argument
||
391 long_options
[match
].has_arg
== optional_argument
) {
392 if (argv_equal_ptr
!= NULL
) {
393 optarg
= argv_equal_ptr
;
394 } else if (LONGOPT_REQUIRES_ARG(long_options
[match
])) {
395 /* The next argv must be the option argument */
396 if (optind
< nargc
) {
397 optarg
= nargv
[optind
];
399 ++optind
; /* code below depends on this */
402 if (LONGOPT_REQUIRES_ARG(long_options
[match
]) &&
405 * Missing argument; leading ':' indicates no error
406 * should be generated.
409 warnx_getopt(nargv
[0],
411 "%s: option requires an argument -- %s"),
415 * XXX: GNU sets optopt to val regardless of flag
417 if (long_options
[match
].flag
== NULL
)
418 optopt
= long_options
[match
].val
;
424 } else { /* unknown option */
430 warnx_getopt(nargv
[0],
431 _libc_gettext("%s: illegal option -- %s"),
439 if (long_options
[match
].flag
!= NULL
) {
440 *long_options
[match
].flag
= long_options
[match
].val
;
443 optopt
= long_options
[match
].val
;
446 } /* parse_long_options() */
449 * getopt_internal() --
450 * Parse argc/argv argument vector. Called by user level routines.
452 * This implements all of the getopt_long(), getopt_long_only(),
453 * getopt_clip() variants.
456 getopt_internal(int nargc
, char * const *nargv
, const char *options
,
457 const struct option
*long_options
, int *idx
, uint_t flags
)
459 char *oli
; /* option letter list index */
460 int optchar
, short_too
;
461 static int posixly_correct
= -1;
467 * Disable GNU extensions if POSIXLY_CORRECT is set or options
468 * string begins with a '+'.
470 if (posixly_correct
== -1) {
471 posixly_correct
= (getenv("POSIXLY_CORRECT") != NULL
);
473 if (FLAG_IS_SET(FLAG_PLUS_DASH_START
)) {
475 * + or - at start of optstring takes precedence
476 * over POSIXLY_CORRECT.
478 if (*options
== '+') {
480 * leading + means POSIX-compliant; first non-option
481 * ends option list. Therefore, don't permute args.
484 } else if (*options
== '-') {
486 flags
|= FLAG_ALLARGS
;
488 if ((*options
== '+') || (*options
== '-')) {
491 } /* if FLAG_PLUS_DASH_START */
493 if (posixly_correct
) {
494 flags
&= ~FLAG_PERMUTE
;
495 flags
&= ~FLAG_ALLARGS
;
499 * Some programs (like GNU cvs) set optind to 0 to restart
500 * option processing. Work around this braindamage.
502 * The above problem comes from using global variables. We
503 * should avoid their use in the future.
506 optind
= optreset
= 1;
513 nonopt_start
= nonopt_end
= -1;
517 * On the first call, make sure that there is a short equivalent
518 * for each long option, and vice versa. This is required by
519 * Sun's CLIP specification (11/12/02).
521 if ((optind
== 1) && FLAG_IS_SET(FLAG_REQUIRE_EQUIVALENTS
)) {
522 if (verify_short_long_equivalents(
523 nargc
, nargv
, options
, long_options
, flags
) < 0) {
524 /* function printed any necessary messages */
525 errno
= EINVAL
; /* invalid argument */
531 if (optreset
|| !*place
) { /* update scanning pointer */
533 if (optind
>= nargc
) { /* end of argument vector */
535 if (nonopt_end
!= -1) {
536 /* do permutation, if we have to */
537 permute_args(nonopt_start
, nonopt_end
,
539 optind
-= nonopt_end
- nonopt_start
;
541 } else if (nonopt_start
!= -1) {
543 * If we skipped non-options, set optind
544 * to the first of them.
546 optind
= nonopt_start
;
548 nonopt_start
= nonopt_end
= -1;
551 if ((*(place
= nargv
[optind
]) != '-') || (place
[1] == '\0')) {
552 place
= EMSG
; /* found non-option */
553 if (flags
& FLAG_ALLARGS
) {
556 * return non-option as argument to option '\1'
558 optarg
= nargv
[optind
++];
561 if (!(flags
& FLAG_PERMUTE
)) {
563 * If no permutation wanted, stop parsing
564 * at first non-option.
569 if (nonopt_start
== -1)
570 nonopt_start
= optind
;
571 else if (nonopt_end
!= -1) {
572 permute_args(nonopt_start
, nonopt_end
,
574 nonopt_start
= optind
-
575 (nonopt_end
- nonopt_start
);
579 /* process next argument */
582 if (nonopt_start
!= -1 && nonopt_end
== -1)
586 * Check for "--" or "--foo" with no long options
587 * but if place is simply "-" leave it unmolested.
589 if (place
[1] != '\0' && *++place
== '-' &&
590 (place
[1] == '\0' || long_options
== NULL
)) {
594 * We found an option (--), so if we skipped
595 * non-options, we have to permute.
597 if (nonopt_end
!= -1) {
598 permute_args(nonopt_start
, nonopt_end
,
600 optind
-= nonopt_end
- nonopt_start
;
602 nonopt_start
= nonopt_end
= -1;
608 * Check long options if:
609 * 1) we were passed some
610 * 2) the arg is not just "-"
611 * 3) either the arg starts with -- or we are getopt_long_only()
613 if (long_options
!= NULL
&& place
!= nargv
[optind
] &&
614 (*place
== '-' || (FLAG_IS_SET(FLAG_LONGONLY
)))) {
617 place
++; /* --foo long option */
618 else if (*place
!= ':' && strchr(options
, *place
) != NULL
)
619 short_too
= 1; /* could be short option too */
621 optchar
= parse_long_options(nargc
, nargv
, options
,
622 long_options
, idx
, short_too
, flags
);
629 if ((optchar
= (int)*place
++) == (int)':' ||
630 (oli
= strchr(options
, optchar
)) == NULL
) {
632 * If the user didn't specify '-' as an option,
633 * assume it means -1 as POSIX specifies.
635 if (optchar
== (int)'-')
637 /* option letter unknown or ':' */
642 _libc_gettext("%s: illegal option -- %s"),
647 if (FLAG_IS_SET(FLAG_W_SEMICOLON
) &&
648 (long_options
!= NULL
) && (optchar
== 'W') && (oli
[1] == ';')) {
650 /* LINTED: statement has no consequent: if */
651 if (*place
) { /* no space */
653 } else if (++optind
>= nargc
) { /* no long-option after -W */
658 "%s: option requires an argument -- %s"),
662 } else { /* white space */
663 place
= nargv
[optind
];
665 optchar
= parse_long_options(
666 nargc
, nargv
, options
, long_options
,
670 * PSARC 2003/645 - Match GNU behavior, set optarg to
673 if (optarg
== NULL
) {
674 optarg
= nargv
[optind
-1];
679 if (*++oli
!= ':') { /* doesn't take argument */
682 } else { /* takes (optional) argument */
684 if (*place
) { /* no white space */
686 /* XXX: disable test for :: if PC? (GNU doesn't) */
687 } else if (!(FLAG_IS_SET(FLAG_OPTIONAL_ARGS
) &&
689 /* arg is required (not optional) */
691 if (++optind
>= nargc
) { /* no arg */
696 "%s: option requires an argument -- %s"),
702 optarg
= nargv
[optind
];
707 /* return valid option letter */
708 optopt
= optchar
; /* preserve getopt() behavior */
710 } /* getopt_internal() */
714 * Parse argc/argv argument vector.
716 * Requires that long options be preceded with a two dashes
717 * (e.g., --longoption).
720 getopt_long(int nargc
, char *const *nargv
,
721 const char *optstring
,
722 const struct option
*long_options
, int *long_index
)
725 return (getopt_internal(
726 nargc
, nargv
, optstring
, long_options
, long_index
,
731 | FLAG_PLUS_DASH_START
));
732 } /* getopt_long() */
735 * getopt_long_only() --
736 * Parse argc/argv argument vector.
738 * Long options may be preceded with a single dash (e.g., -longoption)
741 getopt_long_only(int nargc
, char *const *nargv
,
742 const char *optstring
,
743 const struct option
*long_options
, int *long_index
)
746 return (getopt_internal(
747 nargc
, nargv
, optstring
, long_options
, long_index
,
752 | FLAG_PLUS_DASH_START
754 } /* getopt_long_only() */
758 * Parse argc/argv argument vector, requiring compliance with
759 * Sun's CLIP specification (11/12/02)
761 * o Does not allow arguments to be optional (optional_argument is
762 * treated as required_argument).
764 * o Does not allow long options to be abbreviated on the command line
766 * o Does not allow long argument to be preceded by a single dash
767 * (Double-dash '--' is required)
769 * o Stops option processing at the first non-option
771 * o Requires that every long option have a short-option (single
772 * character) equivalent and vice-versa. If a short option or
773 * long option without an equivalent is found, an error message
774 * is printed and -1 is returned on the first call, and errno
777 * o Leading + or - in optstring is ignored, and opstring is
778 * treated as if it began after the + or - .
781 getopt_clip(int nargc
, char *const *nargv
,
782 const char *optstring
,
783 const struct option
*long_options
, int *long_index
)
785 return getopt_internal(
786 nargc
, nargv
, optstring
, long_options
, long_index
,
792 * no support for +- at start of optstring
793 * yes support for "W;" in optstring
796 | FLAG_REQUIRE_EQUIVALENTS
);
797 } /* getopt_clip() */