From 1a57b229147012ec9df012594a6e78c62ecb9eae Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 20 Feb 2004 21:30:44 +0000 Subject: [PATCH] * getopt.c: Replace with latest vanilla(!) OpenBSD version 1.16. --- winsup/cygwin/ChangeLog | 4 + winsup/cygwin/libc/getopt.c | 553 +++++++++++++++++++----------------- 2 files changed, 302 insertions(+), 255 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index abb7de551..3729f5c02 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,7 @@ +2004-02-20 Corinna Vinschen + + * getopt.c: Replace with latest vanilla(!) OpenBSD version 1.16. + 2004-02-18 Christopher Faylor * fork.cc (fork_child): Invert sense of test which defeated correct diff --git a/winsup/cygwin/libc/getopt.c b/winsup/cygwin/libc/getopt.c index 5ce996fbb..6079ce350 100644 --- a/winsup/cygwin/libc/getopt.c +++ b/winsup/cygwin/libc/getopt.c @@ -1,5 +1,25 @@ -/* $NetBSD: getopt_long.c,v 1.16 2003/10/27 00:12:42 lukem Exp $ */ +/* $OpenBSD: getopt_long.c,v 1.16 2004/02/04 18:17:25 millert Exp $ */ +/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ +/* + * 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) 2000 The NetBSD Foundation, Inc. * All rights reserved. @@ -36,74 +56,45 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: getopt_long.c,v 1.16 2003/10/27 00:12:42 lukem Exp $"); +static char *rcsid = "$OpenBSD: getopt_long.c,v 1.16 2004/02/04 18:17:25 millert Exp $"; #endif /* LIBC_SCCS and not lint */ -#ifndef __CYGWIN__ -#include "namespace.h" -#endif - -#include #include #include #include #include #include -#ifdef __CYGWIN__ -#define _DIAGASSERT(x) do {} while (0) -#define HAVE_NBTOOL_CONFIG_H 1 -#define HAVE_GETOPT_LONG 0 -#define HAVE_DECL_OPTIND 0 -#endif - -#if HAVE_NBTOOL_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND -#define REPLACE_GETOPT -#endif +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ #ifdef REPLACE_GETOPT -#ifdef __weak_alias -__weak_alias(getopt,_getopt) -#endif int opterr = 1; /* if error message should be printed */ int optind = 1; /* index into parent argv vector */ int optopt = '?'; /* character checked for validity */ int optreset; /* reset getopt */ char *optarg; /* argument associated with option */ -#elif HAVE_NBTOOL_CONFIG_H && !HAVE_DECL_OPTRESET -static int optreset; #endif -#ifdef __weak_alias -__weak_alias(getopt_long,_getopt_long) -#endif +#define PRINT_ERROR ((opterr) && (*options != ':')) -#if !HAVE_GETOPT_LONG -#define IGNORE_FIRST (*options == '-' || *options == '+') -#define PRINT_ERROR ((opterr) && ((*options != ':') \ - || (IGNORE_FIRST && options[1] != ':'))) -#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) -#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) -/* XXX: GNU ignores PC if *options == '-' */ -#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ /* return values */ -#define BADCH (int)'?' -#define BADARG ((IGNORE_FIRST && options[1] == ':') \ - || (*options == ':') ? (int)':' : (int)'?') -#define INORDER (int)1 +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 -#ifdef __CYGWIN__ -static char EMSG[1]; -#else -#define EMSG "" -#endif +#define EMSG "" -static int getopt_internal __P((int, char * const *, const char *)); -static int gcd __P((int, int)); -static void permute_args __P((int, int, int, char * const *)); +static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char * const *, const char *, + const struct option *, int *, int); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); static char *place = EMSG; /* option letter processing */ @@ -119,14 +110,11 @@ static const char noarg[] = "option doesn't take an argument -- %.*s"; static const char illoptchar[] = "unknown option -- %c"; static const char illoptstring[] = "unknown option -- %s"; - /* * Compute the greatest common divisor of a and b. */ static int -gcd(a, b) - int a; - int b; +gcd(int a, int b) { int c; @@ -136,8 +124,8 @@ gcd(a, b) b = c; c = a % b; } - - return b; + + return (b); } /* @@ -146,17 +134,12 @@ gcd(a, b) * in each block). */ static void -permute_args(panonopt_start, panonopt_end, opt_end, nargv) - int panonopt_start; - int panonopt_end; - int opt_end; - char * const *nargv; +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; - _DIAGASSERT(nargv != NULL); - /* * compute lengths of blocks and number and size of cycles */ @@ -183,32 +166,160 @@ permute_args(panonopt_start, panonopt_end, opt_end, nargv) } /* - * getopt_internal -- - * Parse argc/argv argument vector. Called by user level routines. - * Returns -2 if -- is found (can be long option or end of options marker). + * 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 -getopt_internal(nargc, nargv, options) - int nargc; - char * const *nargv; - const char *options; +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 = place; + match = -1; + + 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 (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (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); +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +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; + int optchar, short_too; + static int posixly_correct = -1; - _DIAGASSERT(nargv != NULL); - _DIAGASSERT(options != NULL); - - optarg = NULL; + if (options == NULL) + return (-1); /* - * XXX Some programs (like rsyncd) expect to be able to - * XXX re-initialize optind to 0 and have getopt_long(3) - * XXX properly function again. Work around this braindamage. + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + if (posixly_correct == -1) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + else if (*options == '-') + flags |= FLAG_ALLARGS; + if (*options == '+' || *options == '-') + options++; + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. */ if (optind == 0) - optind = 1; + optind = optreset = 1; + optarg = NULL; if (optreset) nonopt_start = nonopt_end = -1; start: @@ -230,25 +341,25 @@ start: optind = nonopt_start; } nonopt_start = nonopt_end = -1; - return -1; + return (-1); } - if ((*(place = nargv[optind]) != '-') - || (place[1] == '\0')) { /* found non-option */ - place = EMSG; - if (IN_ORDER) { + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { /* - * GNU extension: + * GNU extension: * return non-option as argument to option 1 */ optarg = nargv[optind++]; - return INORDER; + return (INORDER); } - if (!PERMUTE) { + if (!(flags & FLAG_PERMUTE)) { /* - * if no permutation wanted, stop parsing - * at first non-option + * If no permutation wanted, stop parsing + * at first non-option. */ - return -1; + return (-1); } /* do permutation */ if (nonopt_start == -1) @@ -266,39 +377,82 @@ start: } if (nonopt_start != -1 && nonopt_end == -1) nonopt_end = optind; - if (place[1] && *++place == '-') { /* found "--" */ - place++; - return -2; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = 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 getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + if ((optchar = (int)*place++) == (int)':' || - (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { - /* option letter unknown or ':' */ + optchar == (int)'-' && *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)'-' && *place == '\0') + return (-1); if (!*place) ++optind; if (PRINT_ERROR) warnx(illoptchar, optchar); optopt = optchar; - return BADCH; + return (BADCH); } - if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ - /* XXX: what if no long options provided (called by getopt)? */ - if (*place) - return -2; - - if (++optind >= nargc) { /* no arg */ + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; - return BADARG; + return (BADARG); } else /* white space */ place = nargv[optind]; - /* - * Handle -W arg the same as --arg (which causes getopt to - * stop parsing). - */ - return -2; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); } if (*++oli != ':') { /* doesn't take argument */ if (!*place) @@ -314,15 +468,22 @@ start: if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; - return BADARG; + return (BADARG); } else optarg = nargv[optind]; + } else if (!(flags & FLAG_PERMUTE)) { + /* + * If permutation is disabled, we can accept an + * optional arg separated by whitespace. + */ + if (optind + 1 < nargc) + optarg = nargv[++optind]; } place = EMSG; ++optind; } /* dump back option letter */ - return optchar; + return (optchar); } #ifdef REPLACE_GETOPT @@ -330,36 +491,23 @@ start: * getopt -- * Parse argc/argv argument vector. * - * [eventually this will replace the real getopt] + * [eventually this will replace the BSD getopt] */ int -getopt(nargc, nargv, options) - int nargc; - char * const *nargv; - const char *options; +getopt(int nargc, char * const *nargv, const char *options) { - int retval; - _DIAGASSERT(nargv != NULL); - _DIAGASSERT(options != NULL); - - if ((retval = getopt_internal(nargc, nargv, options)) == -2) { - ++optind; - /* - * We found an option (--), so if we skipped non-options, - * we have to permute. - */ - if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, optind, - nargv); - optind -= nonopt_end - nonopt_start; - } - nonopt_start = nonopt_end = -1; - retval = -1; - } - return retval; + /* + * We dont' pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); } -#endif +#endif /* REPLACE_GETOPT */ /* * getopt_long -- @@ -373,129 +521,24 @@ getopt_long(nargc, nargv, options, long_options, idx) const struct option *long_options; int *idx; { - int retval; - _DIAGASSERT(nargv != NULL); - _DIAGASSERT(options != NULL); - _DIAGASSERT(long_options != NULL); - /* idx may be NULL */ - - if ((retval = getopt_internal(nargc, nargv, options)) == -2) { - char *current_argv, *has_equal; - size_t current_argv_len; - int i, match; - - current_argv = place; - match = -1; - - optind++; - place = EMSG; - - if (*current_argv == '\0') { /* found "--" */ - /* - * We found an option (--), so if we skipped - * non-options, we have to permute. - */ - if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - nonopt_start = nonopt_end = -1; - return -1; - } - 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) == - (unsigned)current_argv_len) { - /* exact match */ - match = i; - break; - } - if (match == -1) /* partial match */ - match = i; - else { - /* ambiguous abbreviation */ - if (PRINT_ERROR) - warnx(ambig, (int)current_argv_len, - current_argv); - optopt = 0; - return BADCH; - } - } - if (match != -1) { /* option found */ - if (long_options[match].has_arg == no_argument - && has_equal) { - if (PRINT_ERROR) - warnx(noarg, (int)current_argv_len, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of - * flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - return BADARG; - } - if (long_options[match].has_arg == required_argument || - long_options[match].has_arg == optional_argument) { - if (has_equal) - optarg = has_equal; - else if (long_options[match].has_arg == - required_argument) { - /* - * optional argument doesn't use - * next nargv - */ - optarg = nargv[optind++]; - } - } - if ((long_options[match].has_arg == required_argument) - && (optarg == NULL)) { - /* - * Missing argument; leading ':' - * indicates no error should be generated - */ - if (PRINT_ERROR) - warnx(recargstring, current_argv); - /* - * XXX: GNU sets optopt to val regardless - * of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - --optind; - return BADARG; - } - } else { /* unknown option */ - if (PRINT_ERROR) - warnx(illoptstring, current_argv); - optopt = 0; - return BADCH; - } - if (long_options[match].flag) { - *long_options[match].flag = long_options[match].val; - retval = 0; - } else - retval = long_options[match].val; - if (idx) - *idx = match; - } - return retval; + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(nargc, nargv, options, long_options, idx) + int nargc; + char * const *nargv; + const char *options; + const struct option *long_options; + int *idx; +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); } -#endif /* !GETOPT_LONG */