X-Git-Url: https://git.datadissipation.net/libcext/blobdiff_plain/fd4273e5b7249057309c65c78ec1bd766bed03fe..HEAD:/getopt_long.h diff --git a/getopt_long.h b/getopt_long.h index f26dd57..06fac1c 100644 --- a/getopt_long.h +++ b/getopt_long.h @@ -1,26 +1,9 @@ /* - * Copyright (c) 2002 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Sponsored in part by the Defense Advanced Research Projects - * Agency (DARPA) and Air Force Research Laboratory, Air Force - * Materiel Command, USAF, under agreement number F39502-99-1-0512. - */ - -/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. * Copyright (c) 2000 The NetBSD Foundation, Inc. - * All rights reserved. + * All rights reserved. + * Copyright (c) 2002 Todd C. Miller * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. @@ -33,39 +16,73 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. */ /* https://git.datadissipation.net */ -#ifndef GETOPT_LONG_H_ - #define GETOPT_LONG_H_ 1 +#ifndef LCE_GETOPT_LONG_H + #define LCE_GETOPT_LONG_H 1 - #ifdef GETOPT_LONG_INCLUDE_LIBC + #ifdef LCE_GETOPT_LONG_INCLUDE_LIBC + #include + #include #include #include - #include - #endif + #endif /* LCE_GETOPT_LONG_INCLUDE_LIBC */ #ifndef HAVE_GETOPT_LONG - #define HAVE_GETOPT_LONG 1 - /* - * structs are in their own namespace, so this should be OK - * the worst it can do is make compiler messages worse - */ - #define option i_option_ - - struct i_option_ { + #define HAVE_GETOPT_LONG 1 + #ifndef HAVE_GETOPT + #define HAVE_GETOPT 1 + #endif /* !HAVE_GETOPT */ + + #define no_argument 0 + #define required_argument 1 + #define optional_argument 2 + +/* + * structs are in their own namespace, so this should be OK + * the worst it can do is make compiler messages worse + */ + #define option lce_option_ + + #define optarg lce_optarg_ + #define suboptarg lce_suboptarg_ + #define optind lce_optind_ + #define opterr lce_opterr_ + #define optopt lce_optopt_ + #define optreset lce_optreset_ + + #define getopt lce_getopt_ + #define getsubopt lce_getsubopt_ + #define getopt_long lce_getopt_long_ + #define getopt_long_only lce_getopt_long_only_ + + #ifndef LCE_GETOPT_LONG_IMPLEMENTATION +extern char *lce_optarg_; +extern char *lce_suboptarg_; +extern int lce_optind_, lce_opterr_, lce_optopt_, lce_optreset_; + #endif /* !LCE_GETOPT_LONG_IMPLEMENTATION */ + +struct lce_option_ { const char *name; /* * one of no_argument, required_argument, and optional_argument: @@ -76,497 +93,538 @@ int *flag; /* if flag not NULL, value to set *flag to; else return value */ int val; - }; +}; - int i_getopt_(int argc, char *argv[], const char *optstring); - int i_getsubopt_(char *restrict optionp[], const char *restrict tokens[], - char *restrict valuep[]); - int i_getopt_long_(int argc, char *argv[], const char *optstring, - const struct option *longopts, int *longindex); - int i_getopt_long_only_(int argc, char *argv[], const char *optstring, - const struct option *longopts, int *longindex); +int lce_getopt_(int argc, char * const *argv, const char *optstring); +int lce_getsubopt_(char **optionp, char * const *tokens, char **valuep); +int lce_getopt_long_(int argc, char * const *argv, const char *optstring, + const struct option *longopts, int *longindex); +int lce_getopt_long_only_(int argc, char * const *argv, const char *optstring, + const struct option *longopts, int *longindex); - #define no_argument 0 - #define required_argument 1 - #define optional_argument 2 + #endif /* !HAVE_GETOPT_LONG */ - #define getopt(c,v,o) i_getopt_(c,v,o) - #define getsubopt(o,t,v) i_getsubopt_(o,t,v) - #define getopt_long(c,v,o,l,i) i_getopt_long_(c,v,o,l,i) - #define getopt_long_only(c,v,o,l,i) i_getopt_long_only_(c,v,o,l,i) + #ifdef LCE_GETOPT_LONG_IMPLEMENTATION + #define LCE_PRINT_ERROR_ ((lce_opterr_) && (*options != ':')) + + #define LCE_FLAG_PERMUTE_ 0x01 /* permute non-options to the end of argv */ + #define LCE_FLAG_ALLARGS_ 0x02 /* treat non-options as args to option "-1" */ + #define LCE_FLAG_LONGONLY_ 0x04 /* operate as getopt_long_only */ + +/* return values */ + #define LCE_BADCH_ (int) '?' + #define LCE_BADARG_ ((*options == ':') ? (int) ':' : (int) '?') + #define LCE_INORDER_ (int) 1 + + #define LCE_EMSG_ "" + +int lce_opterr_ = 1; /* if error message should be printed */ +int lce_optind_ = 1; /* index into parent argv vector */ +int lce_optopt_ = '?'; /* character checked for validity */ +int lce_optreset_; /* reset getopt */ +char *lce_optarg_; /* argument associated with option */ +char *lce_suboptarg_; /* argument associated with suboption */ + +/* XXX: set optreset to 1 rather than these two */ +static int lce_nonopt_start_ = -1; /* first non option argument (for permute) */ +static int lce_nonopt_end_ = -1; /* first option after non options (for permute) */ +static char *lce_place_ = LCE_EMSG_; /* option letter processing */ +static char *lce_progname_; /* program name == argv[0] */ + +/* Error messages */ +static const char lce_recargchar_[] = "option requires an argument -- %c"; +static const char lce_recargstring_[] = "option requires an argument -- %s"; +static const char lce_ambig_[] = "ambiguous option -- %.*s"; +static const char lce_noarg_[] = "option doesn't take an argument -- %.*s"; +static const char lce_illoptchar_[] = "unknown option -- %c"; +static const char lce_illoptstring_[] = "unknown option -- %s"; + +static void lce_warnx_(const char *, ...); +static int lce_getopt_internal_(int, char * const *, const char *, + const struct option *, int *, int); +static int lce_parse_long_options__(char * const *, const char *, + const struct option *, int *, int); +static int lce_gcd_(int, int); +static void lce_permute_args_(int, int, int, char * const *); - #endif /* !HAVE_GETOPT_LONG */ - - #ifdef GETOPT_LONG_IMPLEMENTATION - #define I_PRINT_ERROR_ ((i_opterr_) && (*options != ':')) - - #define I_FLAG_PERMUTE_ 0x01 /* permute non-options to the end of argv */ - #define I_FLAG_ALLARGS_ 0x02 /* treat non-options as args to option "-1" */ - #define I_FLAG_LONGONLY_ 0x04 /* operate as i_getopt_long_only */ - - /* return values */ - #define I_BADCH_ (int)'?' - #define I_BADARG_ ((*options == ':') ? (int)':' : (int)'?') - #define I_INORDER_ (int)1 - - #define I_EMSG_ "" - - static void i_warnx_(const char *, ...); - static int i_getopt_internal_(int, char **, const char *, - const struct option *, int *, int); - static int i_parse_long_options__(char * const *, const char *, - const struct option *, int *, int); - static int i_gcd_(int, int); - static void i_permute_args_(int, int, int, char * const *); - - - /* XXX: set i_optreeset_ to 1 rather than these two */ - static int i_nonopt_start_ = -1; /* first non option argument (for permute) */ - static int i_nonopt_end_ = -1; /* first option after non options (for permute) */ - static int i_opterr_ = 1; /* if error message should be printed */ - static int i_optind_ = 1; /* index into parent argv vector */ - static int i_optopt_ = '?'; /* character checked for validity */ - static int i_optreeset_; /* reset getopt */ - static char *i_optarg_; /* argument associated with option */ - static char *i_place_ = I_EMSG_; /* option letter processing */ - - /* Error messages */ - static const char i_recargchar_[] = "option requires an argument -- %c"; - static const char i_recargstring_[] = "option requires an argument -- %s"; - static const char i_ambig_[] = "i_ambig_uous option -- %.*s"; - static const char i_noarg_[] = "option doesn't take an argument -- %.*s"; - static const char i_illoptchar_[] = "unknown option -- %c"; - static const char i_illoptstring_[] = "unknown option -- %s"; - - /* - * Own warnx() for portability - */ - void - i_warnx_(const char *fmt, ...) - { - va_list args; - - #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - #define I_GET_PROG_NAME_() getprogname() - #elif defined(__linux__) - #include - #define I_GET_PROG_NAME_() program_invocation_short_name - #else - #define I_GET_PROG_NAME_() "warnx" - #endif - - va_start(args, fmt); - fprintf(stderr, "%s: ", I_GET_PROG_NAME_()); - vfprintf(stderr, fmt, args); - fputc('\n', stderr); - va_end(args); - } - - /* - * Compute the greatest common divisor of a and b. - */ - static int - i_gcd_(int a, int b) - { - int c; - - c = a % b; - while (c != 0) { - a = b; - b = c; - c = a % b; - } - - return (b); - } - - /* - * Exchange the block from i_nonopt_start_ to i_nonopt_end_ with the block - * from i_nonopt_end_ to opt_end (keeping the same order of arguments - * in each block). - */ - static void - i_permute_args_(int pai_nonopt_start_, int pai_nonopt_end_, int opt_end, - char * const *nargv) - { - int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; - char *swap; - - /* - * compute lengths of blocks and number and size of cycles - */ - nnonopts = pai_nonopt_end_ - pai_nonopt_start_; - nopts = opt_end - pai_nonopt_end_; - ncycle = i_gcd_(nnonopts, nopts); - cyclelen = (opt_end - pai_nonopt_start_) / ncycle; - - for (i = 0; i < ncycle; i++) { - cstart = pai_nonopt_end_+i; +/* + * Own warnx() for portability + */ +void +lce_warnx_(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + fprintf(stderr, "%s: ", lce_progname_); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + va_end(args); +} + +/* + * Compute the greatest common divisor of a and b. + */ +static int +lce_gcd_(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +lce_permute_args_(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = lce_gcd_(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; pos = cstart; for (j = 0; j < cyclelen; j++) { - if (pos >= pai_nonopt_end_) - pos -= nnonopts; - else - pos += nopts; - swap = nargv[pos]; - /* LINTED const cast */ - ((char **) nargv)[pos] = nargv[cstart]; - /* LINTED const cast */ - ((char **)nargv)[cstart] = swap; - } - } - } - - /* - * i_parse_long_options__ -- - * Parse long options in argc/argv argument vector. - * Returns -1 if short_too is set and the option does not match long_options. - */ - static int - i_parse_long_options__(char * const *nargv, const char *options, - const struct option *long_options, int *idx, int short_too) - { - char *current_argv, *has_equal; - size_t current_argv_len; - int i, match; - - current_argv = i_place_; - match = -1; - - i_optind_++; - - if ((has_equal = strchr(current_argv, '=')) != NULL) { - /* argument found (--option=arg) */ - current_argv_len = has_equal - current_argv; - has_equal++; - } else { - current_argv_len = strlen(current_argv); - } - for (i = 0; long_options[i].name; i++) { - /* find matching long option */ - if (strncmp(current_argv, long_options[i].name, - current_argv_len)) - continue; - - if (strlen(long_options[i].name) == current_argv_len) { - /* exact match */ - match = i; - break; - } - /* - * If this is a known short option, don't allow - * a partial match of a single character. - */ - if (short_too && current_argv_len == 1) - continue; - - if (match == -1) { /* partial match */ - match = i; - } else { - /* i_ambig_uous abbreviation */ - if (I_PRINT_ERROR_) - i_warnx_(i_ambig_, (int)current_argv_len, - current_argv); - i_optopt_ = 0; - return (I_BADCH_); - } - } - if (match != -1) { /* option found */ - if (long_options[match].has_arg == no_argument - && has_equal) { - if (I_PRINT_ERROR_) - i_warnx_(i_noarg_, (int)current_argv_len, - current_argv); - /* - * XXX: GNU sets i_optopt_ to val regardless of flag - */ - if (long_options[match].flag == NULL) - i_optopt_ = long_options[match].val; - else - i_optopt_ = 0; - return (I_BADARG_); - } - if (long_options[match].has_arg == required_argument || - long_options[match].has_arg == optional_argument) { - if (has_equal) - i_optarg_ = has_equal; - else if (long_options[match].has_arg == - required_argument) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **) nargv)[cstart] = swap; + } + } +} + +/* + * lce_parse_long_options__ -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +lce_parse_long_options__(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int + short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, match; + + current_argv = lce_place_; + match = -1; + + lce_optind_++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else { + current_argv_len = strlen(current_argv); + } + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) { /* partial match */ + match = i; + } else { + /* ambiguous abbreviation */ + if (LCE_PRINT_ERROR_) + lce_warnx_(lce_ambig_, (int) current_argv_len, + current_argv); + lce_optopt_ = 0; + return (LCE_BADCH_); + } + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (LCE_PRINT_ERROR_) + lce_warnx_(lce_noarg_, (int) current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + lce_optopt_ = long_options[match].val; + else + lce_optopt_ = 0; + return (LCE_BADARG_); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal){ + lce_optarg_ = has_equal; + } else if (long_options[match].has_arg == + required_argument) { /* * optional argument doesn't use next nargv */ - i_optarg_ = nargv[i_optind_++]; - } - } - if ((long_options[match].has_arg == required_argument) - && (i_optarg_ == NULL)) { + lce_optarg_ = nargv[lce_optind_++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (lce_optarg_ == NULL)) { /* * Missing argument; leading ':' indicates no error * should be generated. */ - if (I_PRINT_ERROR_) - i_warnx_(i_recargstring_, - current_argv); + if (LCE_PRINT_ERROR_) + lce_warnx_(lce_recargstring_, + current_argv); /* - * XXX: GNU sets i_optopt_ to val regardless of flag + * XXX: GNU sets optopt to val regardless of flag */ if (long_options[match].flag == NULL) - i_optopt_ = long_options[match].val; + lce_optopt_ = long_options[match].val; else - i_optopt_ = 0; - --i_optind_; - return (I_BADARG_); - } - } else { /* unknown option */ - if (short_too) { - --i_optind_; - return (-1); - } - if (I_PRINT_ERROR_) - i_warnx_(i_illoptstring_, current_argv); - i_optopt_ = 0; - return (I_BADCH_); - } - if (idx) - *idx = match; - if (long_options[match].flag) { - *long_options[match].flag = long_options[match].val; - return (0); - } else - return (long_options[match].val); - } - - /* - * i_getopt_internal_ -- - * Parse argc/argv argument vector. Called by user level routines. - */ - static int - i_getopt_internal_(int nargc, char **nargv, const char *options, - const struct option *long_options, int *idx, int flags) - { - char *oli; /* option letter list index */ - int optchar, short_too; - static int posix_me_harder = -1; - - if (options == NULL) - return (-1); - - /* - * XXX Some GNU programs (like cvs) set optind to 0 instead of - * XXX using optreeset. Work around this braindamage. - */ - if (i_optind_ == 0) - i_optind_ = i_optreeset_ = 1; - - /* - * Disable GNU extensions if POSIXLY_CORRECT is set or options - * string begins with a '+'. - */ - if (posix_me_harder == -1 || i_optreeset_) - posix_me_harder = (getenv("POSIXLY_CORRECT") != NULL); - if (*options == '-') - flags |= I_FLAG_ALLARGS_; - else if (posix_me_harder || *options == '+') - flags &= ~I_FLAG_PERMUTE_; - if (*options == '+' || *options == '-') - options++; - - i_optarg_ = NULL; - if (i_optreeset_) - i_nonopt_start_ = i_nonopt_end_ = -1; - start: - if (i_optreeset_ || !*i_place_) { /* update scanning pointer */ - i_optreeset_ = 0; - if (i_optind_ >= nargc) { /* end of argument vector */ - i_place_ = I_EMSG_; - if (i_nonopt_end_ != -1) { - /* do permutation, if we have to */ - i_permute_args_(i_nonopt_start_, i_nonopt_end_, - i_optind_, nargv); - i_optind_ -= i_nonopt_end_ - i_nonopt_start_; - } else if (i_nonopt_start_ != -1) { - /* - * If we skipped non-options, set i_optind_ - * to the first of them. - */ - i_optind_ = i_nonopt_start_; - } - i_nonopt_start_ = i_nonopt_end_ = -1; - return (-1); - } - if (*(i_place_ = nargv[i_optind_]) != '-' || - (i_place_[1] == '\0' && strchr(options, '-') == NULL)) { - i_place_ = I_EMSG_; /* found non-option */ - if (flags & I_FLAG_ALLARGS_) { - /* - * GNU extension: - * return non-option as argument to option 1 - */ - i_optarg_ = nargv[i_optind_++]; - return (I_INORDER_); - } - if (!(flags & I_FLAG_PERMUTE_)) { + lce_optopt_ = 0; + --lce_optind_; + return (LCE_BADARG_); + } + } else { /* unknown option */ + if (short_too) { + --lce_optind_; + return (-1); + } + if (LCE_PRINT_ERROR_) + lce_warnx_(lce_illoptstring_, current_argv); + lce_optopt_ = 0; + return (LCE_BADCH_); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else { + return (long_options[match].val); + } +} + +/* + * lce_getopt_internal_ -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +lce_getopt_internal_(int nargc, char *const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posix_me_harder = -1; + + if (options == NULL) + return (-1); + + lce_progname_ = nargv[0]; + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (lce_optind_ == 0) + lce_optind_ = lce_optreset_ = 1; + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + if (posix_me_harder == -1 || lce_optreset_) + posix_me_harder = (getenv("POSIXLY_CORRECT") != NULL); + if (*options == '-') + flags |= LCE_FLAG_ALLARGS_; + else if (posix_me_harder || *options == '+') + flags &= ~LCE_FLAG_PERMUTE_; + if (*options == '+' || *options == '-') + options++; + + lce_optarg_ = NULL; + if (lce_optreset_) + lce_nonopt_start_ = lce_nonopt_end_ = -1; +start: + if (lce_optreset_ || !*lce_place_) { /* update scanning pointer */ + lce_optreset_ = 0; + if (lce_optind_ >= nargc) { /* end of argument vector */ + lce_place_ = LCE_EMSG_; + if (lce_nonopt_end_ != -1) { + /* do permutation, if we have to */ + lce_permute_args_(lce_nonopt_start_, lce_nonopt_end_, + lce_optind_, nargv); + lce_optind_ -= lce_nonopt_end_ - lce_nonopt_start_; + } else if (lce_nonopt_start_ != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + lce_optind_ = lce_nonopt_start_; + } + lce_nonopt_start_ = lce_nonopt_end_ = -1; + return (-1); + } + if (*(lce_place_ = nargv[lce_optind_]) != '-' || + (lce_place_[1] == '\0' && strchr(options, '-') == NULL)) { + lce_place_ = LCE_EMSG_; /* found non-option */ + if (flags & LCE_FLAG_ALLARGS_) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + lce_optarg_ = nargv[lce_optind_++]; + return (LCE_INORDER_); + } + if (!(flags & LCE_FLAG_PERMUTE_)) { /* * If no permutation wanted, stop parsing * at first non-option. */ return (-1); - } - /* do permutation */ - if (i_nonopt_start_ == -1) { - i_nonopt_start_ = i_optind_; - } else if (i_nonopt_end_ != -1) { - i_permute_args_(i_nonopt_start_, i_nonopt_end_, - i_optind_, nargv); - i_nonopt_start_ = i_optind_ - - (i_nonopt_end_ - i_nonopt_start_); - i_nonopt_end_ = -1; - } - i_optind_++; - /* process next argument */ - goto start; - } - if (i_nonopt_start_ != -1 && i_nonopt_end_ == -1) - i_nonopt_end_ = i_optind_; - - /* - * If we have "-" do nothing, if "--" we are done. - */ - if (i_place_[1] != '\0' && *++i_place_ == '-' && i_place_[1] == '\0') { - i_optind_++; - i_place_ = I_EMSG_; - /* - * We found an option (--), so if we skipped - * non-options, we have to permute. - */ - if (i_nonopt_end_ != -1) { - i_permute_args_(i_nonopt_start_, i_nonopt_end_, - i_optind_, nargv); - i_optind_ -= i_nonopt_end_ - i_nonopt_start_; - } - i_nonopt_start_ = i_nonopt_end_ = -1; - return (-1); - } - } - - /* - * Check long options if: - * 1) we were passed some - * 2) the arg is not just "-" - * 3) either the arg starts with -- we are i_getopt_long_only() - */ - if (long_options != NULL && i_place_ != nargv[i_optind_] && - (*i_place_ == '-' || (flags & I_FLAG_LONGONLY_))) { - short_too = 0; - if (*i_place_ == '-') - i_place_++; /* --foo long option */ - else if (*i_place_ != ':' - && strchr(options, *i_place_) != NULL) - short_too = 1; /* could be short option too */ - - optchar = i_parse_long_options__(nargv, options, long_options, - idx, short_too); - if (optchar != -1) { - i_place_ = I_EMSG_; - return (optchar); - } - } - - if ((optchar = (int)*i_place_++) == (int)':' || - (optchar == (int)'-' && *i_place_ != '\0') || + } + /* do permutation */ + if (lce_nonopt_start_ == -1) { + lce_nonopt_start_ = lce_optind_; + } else if (lce_nonopt_end_ != -1) { + lce_permute_args_(lce_nonopt_start_, lce_nonopt_end_, + lce_optind_, nargv); + lce_nonopt_start_ = lce_optind_ - + (lce_nonopt_end_ - + lce_nonopt_start_); + lce_nonopt_end_ = -1; + } + lce_optind_++; + /* process next argument */ + goto start; + } + if (lce_nonopt_start_ != -1 && lce_nonopt_end_ == -1) + lce_nonopt_end_ = lce_optind_; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (lce_place_[1] != '\0' && *++lce_place_ == '-' && lce_place_[1] == + '\0') { + lce_optind_++; + lce_place_ = LCE_EMSG_; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (lce_nonopt_end_ != -1) { + lce_permute_args_(lce_nonopt_start_, lce_nonopt_end_, + lce_optind_, nargv); + lce_optind_ -= lce_nonopt_end_ - lce_nonopt_start_; + } + lce_nonopt_start_ = lce_nonopt_end_ = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are lce_getopt_long_only() + */ + if (long_options != NULL && lce_place_ != nargv[lce_optind_] && + (*lce_place_ == '-' || (flags & LCE_FLAG_LONGONLY_))) { + short_too = 0; + if (*lce_place_ == '-') + lce_place_++; /* --foo long option */ + else if (*lce_place_ != ':' + && strchr(options, *lce_place_) != NULL) + short_too = 1; /* could be short option too */ + + optchar = lce_parse_long_options__(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + lce_place_ = LCE_EMSG_; + return (optchar); + } + } + + if ((optchar = (int) *lce_place_++) == (int) ':' || + (optchar == (int) '-' && *lce_place_ != '\0') || (oli = strchr(options, optchar)) == NULL) { - /* - * If the user specified "-" and '-' isn't listed in - * options, return -1 (non-option) as per POSIX. - * Otherwise, it is an unknown option character (or ':'). - */ - if (optchar == (int)'-' && *i_place_ == '\0') - return (-1); - if (!*i_place_) - ++i_optind_; - if (I_PRINT_ERROR_) - i_warnx_(i_illoptchar_, optchar); - i_optopt_ = optchar; - return (I_BADCH_); - } - if (long_options != NULL && optchar == 'W' && oli[1] == ';') { - /* -W long-option */ - if (*i_place_) { /* no space */ - /* NOTHING */; - } else if (++i_optind_ >= nargc) { /* no arg */ - i_place_ = I_EMSG_; - if (I_PRINT_ERROR_) - i_warnx_(i_recargchar_, optchar); - i_optopt_ = optchar; - return (I_BADARG_); - } else { /* white space */ - i_place_ = nargv[i_optind_]; - } - optchar = i_parse_long_options__(nargv, options, long_options, - idx, 0); - i_place_ = I_EMSG_; - return (optchar); - } - if (*++oli != ':') { /* doesn't take argument */ - if (!*i_place_) - ++i_optind_; - } else { /* takes (optional) argument */ - i_optarg_ = NULL; - if (*i_place_) /* no white space */ - i_optarg_ = i_place_; - else if (oli[1] != ':') { /* arg not optional */ - if (++i_optind_ >= nargc) { /* no arg */ - i_place_ = I_EMSG_; - if (I_PRINT_ERROR_) - i_warnx_(i_recargchar_, optchar); - i_optopt_ = optchar; - return (I_BADARG_); - } else { - i_optarg_ = nargv[i_optind_]; - } - } - i_place_ = I_EMSG_; - ++i_optind_; - } - /* dump back option letter */ - return (optchar); - } - - int - i_getopt_(int argc, char *argv[], const char *optstring) - { - #ifdef GETOPT_PERMUTE_ARGS - return (i_getopt_internal_(argc, argv, optstring, NULL, NULL, - I_FLAG_PERMUTE_)); - #else - return (i_getopt_internal_(argc, argv, optstring, NULL, NULL, 0)); - #endif - } - - int - i_getopt_long_(int argc, char *argv[], const char *optstring, - const struct option *longopts, int *longindex) - { - #ifdef GETOPT_LONG_PERMUTE_ARGS - return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, - I_FLAG_PERMUTE_)); - #else - return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, 0)); - #endif - - } - - int - i_getopt_long_only_(int argc, char *argv[], const char *optstring, - const struct option *longopts, int *longindex) - { - #ifdef GETOPT_LONG_ONLY_PERMUTE_ARGS - return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, - I_FLAG_PERMUTE_ | I_FLAG_LONGONLY_)); - #else - return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, - I_FLAG_LONGONLY_)); - #endif - } - #endif /* GETOPT_LONG_IMPLEMENTATION */ -#endif /* !GETOPT_LONG_H_ */ + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int) '-' && *lce_place_ == '\0') + return (-1); + if (!*lce_place_) + ++lce_optind_; + if (LCE_PRINT_ERROR_) + lce_warnx_(lce_illoptchar_, optchar); + lce_optopt_ = optchar; + return (LCE_BADCH_); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*lce_place_) { /* no space */ + /* NOTHING */ + ; + } else if (++lce_optind_ >= nargc) { /* no arg */ + lce_place_ = LCE_EMSG_; + if (LCE_PRINT_ERROR_) + lce_warnx_(lce_recargchar_, optchar); + lce_optopt_ = optchar; + return (LCE_BADARG_); + } else { /* white space */ + lce_place_ = nargv[lce_optind_]; + } + optchar = lce_parse_long_options__(nargv, options, long_options, + idx, 0); + lce_place_ = LCE_EMSG_; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*lce_place_) + ++lce_optind_; + } else { /* takes (optional) argument */ + lce_optarg_ = NULL; + if (*lce_place_){ /* no white space */ + lce_optarg_ = lce_place_; + } else if (oli[1] != ':'){ /* arg not optional */ + if (++lce_optind_ >= nargc) { /* no arg */ + lce_place_ = LCE_EMSG_; + if (LCE_PRINT_ERROR_) + lce_warnx_(lce_recargchar_, optchar); + lce_optopt_ = optchar; + return (LCE_BADARG_); + } else { + lce_optarg_ = nargv[lce_optind_]; + } + } + lce_place_ = LCE_EMSG_; + ++lce_optind_; + } + /* dump back option letter */ + return (optchar); +} + +int +lce_getsubopt_(char **optionp, char * const *tokens, char **valuep) +{ + int cnt; + char *p; + + lce_suboptarg_ = *valuep = NULL; + + if (!optionp || !*optionp) + return (-1); + + /* skip leading white-space, commas */ + for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p) ; + + if (!*p) { + *optionp = p; + return (-1); + } + + /* save the start of the token, and skip the rest of the token. */ + for (lce_suboptarg_ = p; + *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';) ; + + if (*p) { + /* + * If there's an equals sign, set the value pointer, and + * skip over the value part of the token. Terminate the + * token. + */ + if (*p == '=') { + *p = '\0'; + for (*valuep = ++p; + *p && *p != ',' && *p != ' ' && *p != '\t'; ++p) ; + if (*p) + *p++ = '\0'; + } else { + *p++ = '\0'; + } + /* Skip any whitespace or commas after this token. */ + for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p) ; + } + + /* set optionp for next round. */ + *optionp = p; + + for (cnt = 0; *tokens; ++tokens, ++cnt) + if (!strcmp(lce_suboptarg_, *tokens)) + return (cnt); + return (-1); +} + +int +lce_getopt_(int argc, char * const *argv, const char *optstring) +{ +#ifdef LCE_GETOPT_PERMUTE_ARGS + return (lce_getopt_internal_(argc, argv, optstring, NULL, NULL, + LCE_FLAG_PERMUTE_)); +#else + return (lce_getopt_internal_(argc, argv, optstring, NULL, NULL, 0)); +#endif /* LCE_GETOPT_PERMUTE_ARGS */ +} + +int +lce_getopt_long_(int argc, char * const *argv, const char *optstring, + const struct option *longopts, int *longindex) +{ +#ifdef LCE_GETOPT_LONG_PERMUTE_ARGS + return (lce_getopt_internal_(argc, argv, optstring, longopts, longindex, + LCE_FLAG_PERMUTE_)); +#else + return (lce_getopt_internal_(argc, argv, optstring, longopts, longindex, 0 + )); +#endif /* LCE_GETOPT_LONG_PERMUTE_ARGS */ +} + +int +lce_getopt_long_only_(int argc, char * const *argv, const char *optstring, + const struct option *longopts, int *longindex) +{ +#ifdef LCE_GETOPT_LONG_ONLY_PERMUTE_ARGS + return (lce_getopt_internal_(argc, argv, optstring, longopts, longindex, + LCE_FLAG_PERMUTE_ | I_FLAG_LONGONLY_)); +#else + return (lce_getopt_internal_(argc, argv, optstring, longopts, longindex, + LCE_FLAG_LONGONLY_)); +#endif /* LCE_GETOPT_LONG_ONLY_PERMUTE_ARGS */ +} + #endif /* LCE_GETOPT_LONG_IMPLEMENTATION */ +#endif /* !LCE_GETOPT_LONG_H */