diff --git a/argp-parse.c b/argp-parse.c index 10bff92..3a95512 100644 --- a/argp-parse.c +++ b/argp-parse.c @@ -1,26 +1,21 @@ -/* Hierarchial argument parsing - Copyright (C) 1995, 96, 97, 98, 99, 2000,2003 Free Software Foundation, Inc. +/* Hierarchial argument parsing, layered over getopt + Copyright (C) 1995-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader . The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ #ifdef HAVE_CONFIG_H #include @@ -28,11 +23,11 @@ /* AIX requires this to be the first thing in the file. */ #ifndef __GNUC__ -# if HAVE_ALLOCA_H +# if HAVE_ALLOCA_H || 0 # include # else # ifdef _AIX - #pragma alloca +#pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ char *alloca (); @@ -45,16 +40,17 @@ char *alloca (); #include #include #include -#include +#include #ifndef _ /* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */ -# if defined HAVE_LIBINTL_H || defined _LIBC +# if defined HAVE_LIBINTL_H || 0 # include -# ifdef _LIBC +# if 0 # undef dgettext -# define dgettext(domain, msgid) __dcgettext (domain, msgid, LC_MESSAGES) +# define dgettext(domain, msgid) \ + __dcgettext (domain, msgid, LC_MESSAGES) # endif # else # define dgettext(domain, msgid) (msgid) @@ -65,25 +61,27 @@ char *alloca (); # define N_(msgid) (msgid) #endif -#if _LIBC - 0 -#include -#else -#ifdef HAVE_CTHREADS_H -#include -#endif -#endif /* _LIBC */ - -#include "argp.h" +#include #include "argp-namefrob.h" +/* Getopt return values. */ +#define KEY_END (-1) /* The end of the options. */ +#define KEY_ARG 1 /* A non-option argument. */ +#define KEY_ERR '?' /* An error parsing the options. */ /* The meta-argument used to prevent any further arguments being interpreted as options. */ #define QUOTE "--" +/* The number of bits we steal in a long-option value for our own use. */ +#define GROUP_BITS CHAR_BIT + +/* The number of bits available for the user value. */ +#define USER_BITS ((sizeof ((struct option *)0)->val * CHAR_BIT) - GROUP_BITS) +#define USER_MASK ((1 << USER_BITS) - 1) + /* EZ alias for ARGP_ERR_UNKNOWN. */ #define EBADKEY ARGP_ERR_UNKNOWN - /* Default options. */ @@ -91,7 +89,7 @@ char *alloca (); for one second intervals, decrementing _ARGP_HANG until it's zero. Thus you can force the program to continue by attaching a debugger and setting it to 0 yourself. */ -volatile int _argp_hang; +static volatile int _argp_hang; #define OPT_PROGNAME -2 #define OPT_USAGE -3 @@ -99,13 +97,13 @@ volatile int _argp_hang; static const struct argp_option argp_default_options[] = { - {"help", '?', 0, 0, N_("Give this help list"), -1}, - {"usage", OPT_USAGE, 0, 0, N_("Give a short usage message"), 0 }, - {"program-name",OPT_PROGNAME,"NAME", OPTION_HIDDEN, - N_("Set the program name"), 0}, - {"HANG", OPT_HANG, "SECS", OPTION_ARG_OPTIONAL | OPTION_HIDDEN, - N_("Hang for SECS seconds (default 3600)"), 0 }, - {0, 0, 0, 0, 0, 0} + {"help", '?', 0, 0, N_("Give this help list"), -1}, + {"usage", OPT_USAGE, 0, 0, N_("Give a short usage message")}, + {"program-name",OPT_PROGNAME, N_("NAME"), OPTION_HIDDEN, + N_("Set the program name")}, + {"HANG", OPT_HANG, N_("SECS"), OPTION_ARG_OPTIONAL | OPTION_HIDDEN, + N_("Hang for SECS seconds (default 3600)")}, + {0, 0} }; static error_t @@ -122,7 +120,7 @@ argp_default_parser (int key, char *arg, struct argp_state *state) break; case OPT_PROGNAME: /* Set the program name. */ -#if HAVE_DECL_PROGRAM_INVOCATION_NAME +#if 0 || HAVE_DECL_PROGRAM_INVOCATION_NAME program_invocation_name = arg; #endif /* [Note that some systems only have PROGRAM_INVOCATION_SHORT_NAME (aka @@ -130,10 +128,13 @@ argp_default_parser (int key, char *arg, struct argp_state *state) to be that, so we have to be a bit careful here.] */ /* Update what we use for messages. */ + state->name = strrchr (arg, '/'); + if (state->name) + state->name++; + else + state->name = arg; - state->name = __argp_basename(arg); - -#if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME +#if 0 || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME program_invocation_short_name = state->name; #endif @@ -146,8 +147,6 @@ argp_default_parser (int key, char *arg, struct argp_state *state) case OPT_HANG: _argp_hang = atoi (arg ? arg : "3600"); - fprintf(state->err_stream, "%s: pid = %ld\n", - state->name, (long) getpid()); while (_argp_hang-- > 0) __sleep (1); break; @@ -164,12 +163,12 @@ static const struct argp argp_default_argp = static const struct argp_option argp_version_options[] = { - {"version", 'V', 0, 0, N_("Print program version"), -1}, - {0, 0, 0, 0, 0, 0 } + {"version", 'V', 0, 0, N_("Print program version"), -1}, + {0, 0} }; static error_t -argp_version_parser (int key, char *arg UNUSED, struct argp_state *state) +argp_version_parser (int key, char *arg, struct argp_state *state) { switch (key) { @@ -193,6 +192,23 @@ argp_version_parser (int key, char *arg UNUSED, struct argp_state *state) static const struct argp argp_version_argp = {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL, "libc"}; +/* Returns the offset into the getopt long options array LONG_OPTIONS of a + long option with called NAME, or -1 if none is found. Passing NULL as + NAME will return the number of options. */ +static int +find_long_option (struct option *long_options, const char *name) +{ + struct option *l = long_options; + while (l->name != NULL) + if (name != NULL && strcmp (l->name, name) == 0) + return l - long_options; + else + l++; + if (name == NULL) + return l - long_options; + else + return -1; +} /* The state of a `group' during parsing. Each group corresponds to a @@ -206,6 +222,11 @@ struct group /* Which argp this group is from. */ const struct argp *argp; + /* Points to the point in SHORT_OPTS corresponding to the end of the short + options for this group. We use it to determine from which group a + particular short options is from. */ + char *short_end; + /* The number of non-option args sucessfully handled by this parser. */ unsigned args_processed; @@ -244,180 +265,32 @@ struct parser { const struct argp *argp; - const char *posixly_correct; - - /* True if there are only no-option arguments left, which are just - passed verbatim with ARGP_KEY_ARG. This is set if we encounter a - quote, or the end of the proper options, but may be cleared again - if the user moves the next argument pointer backwards. */ - int args_only; - - /* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, the default is - REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is - defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; stop option - processing when the first non-option is seen. This is what Unix - does. This mode of operation is selected by either setting the - environment variable POSIXLY_CORRECT, or using `+' as the first - character of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we - scan, so that eventually all the non-options are at the end. This - allows options to be given in any order, even with programs that - were not written to expect this. - - RETURN_IN_ORDER is an option available to programs that were - written to expect options and other ARGV-elements in any order - and that care about the ordering of the two. We describe each - non-option ARGV-element as if it were the argument of an option - with character code 1. Using `-' as the first character of the - list of option characters selects this mode of operation. - - */ - enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; - - /* A segment of non-option arguments that have been skipped for - later processing, after all options. `first_nonopt' is the index - in ARGV of the first of them; `last_nonopt' is the index after - the last of them. - - If quoted or args_only is non-zero, this segment should be empty. */ - - /* FIXME: I'd prefer to use unsigned, but it's more consistent to - use the same type as for state.next. */ - int first_nonopt; - int last_nonopt; - - /* String of all recognized short options. Needed for ARGP_LONG_ONLY. */ - /* FIXME: Perhaps change to a pointer to a suitable bitmap instead? */ + /* SHORT_OPTS is the getopt short options string for the union of all the + groups of options. */ char *short_opts; + /* LONG_OPTS is the array of getop long option structures for the union of + all the groups of options. */ + struct option *long_opts; - /* For parsing combined short options. */ - char *nextchar; - /* States of the various parsing groups. */ struct group *groups; /* The end of the GROUPS array. */ struct group *egroup; /* An vector containing storage for the CHILD_INPUTS field in all groups. */ void **child_inputs; - + + /* True if we think using getopt is still useful; if false, then + remaining arguments are just passed verbatim with ARGP_KEY_ARG. This is + cleared whenever getopt returns KEY_END, but may be set again if the user + moves the next argument pointer backwards. */ + int try_getopt; + /* State block supplied to parsing routines. */ struct argp_state state; /* Memory used by this parser. */ void *storage; }; - -/* Search for a group defining a short option. */ -static const struct argp_option * -find_short_option(struct parser *parser, int key, struct group **p) -{ - struct group *group; - - assert(key >= 0); - assert(isascii(key)); - - for (group = parser->groups; group < parser->egroup; group++) - { - const struct argp_option *opts; - - for (opts = group->argp->options; !__option_is_end(opts); opts++) - if (opts->key == key) - { - *p = group; - return opts; - } - } - return NULL; -} - -enum match_result { MATCH_EXACT, MATCH_PARTIAL, MATCH_NO }; - -/* If defined, allow complete.el-like abbreviations of long options. */ -#ifndef ARGP_COMPLETE -#define ARGP_COMPLETE 0 -#endif - -/* Matches an encountern long-option argument ARG against an option NAME. - * ARG is terminated by NUL or '='. */ -static enum match_result -match_option(const char *arg, const char *name) -{ - unsigned i, j; - for (i = j = 0;; i++, j++) - { - switch(arg[i]) - { - case '\0': - case '=': - return name[j] ? MATCH_PARTIAL : MATCH_EXACT; -#if ARGP_COMPLETE - case '-': - while (name[j] != '-') - if (!name[j++]) - return MATCH_NO; - break; -#endif - default: - if (arg[i] != name[j]) - return MATCH_NO; - } - } -} - -static const struct argp_option * -find_long_option(struct parser *parser, - const char *arg, - struct group **p) -{ - struct group *group; - - /* Partial match found so far. */ - struct group *matched_group = NULL; - const struct argp_option *matched_option = NULL; - - /* Number of partial matches. */ - int num_partial = 0; - - for (group = parser->groups; group < parser->egroup; group++) - { - const struct argp_option *opts; - - for (opts = group->argp->options; !__option_is_end(opts); opts++) - { - if (!opts->name) - continue; - switch (match_option(arg, opts->name)) - { - case MATCH_NO: - break; - case MATCH_PARTIAL: - num_partial++; - - matched_group = group; - matched_option = opts; - - break; - case MATCH_EXACT: - /* Exact match. */ - *p = group; - return opts; - } - } - } - if (num_partial == 1) - { - *p = matched_group; - return matched_option; - } - - return NULL; -} - /* The next usable entries in the various parser tables being filled in by convert_options. */ @@ -425,40 +298,88 @@ struct parser_convert_state { struct parser *parser; char *short_end; + struct option *long_end; void **child_inputs_end; }; -/* Initialize GROUP from ARGP. If CVT->SHORT_END is non-NULL, short - options are recorded in the short options string. Returns the next - unused group entry. CVT holds state used during the conversion. */ +/* Converts all options in ARGP (which is put in GROUP) and ancestors + into getopt options stored in SHORT_OPTS and LONG_OPTS; SHORT_END and + CVT->LONG_END are the points at which new options are added. Returns the + next unused group entry. CVT holds state used during the conversion. */ static struct group * convert_options (const struct argp *argp, struct group *parent, unsigned parent_index, struct group *group, struct parser_convert_state *cvt) { - const struct argp_option *opt = argp->options; + /* REAL is the most recent non-alias value of OPT. */ + const struct argp_option *real = argp->options; const struct argp_child *children = argp->children; - if (opt || argp->parser) + if (real || argp->parser) { - /* This parser needs a group. */ - if (cvt->short_end) - { - /* Record any short options. */ - for ( ; !__option_is_end (opt); opt++) - if (__option_is_short(opt)) - *cvt->short_end++ = opt->key; - } - + const struct argp_option *opt; + + if (real) + for (opt = real; !__option_is_end (opt); opt++) + { + if (! (opt->flags & OPTION_ALIAS)) + /* OPT isn't an alias, so we can use values from it. */ + real = opt; + + if (! (real->flags & OPTION_DOC)) + /* A real option (not just documentation). */ + { + if (__option_is_short (opt)) + /* OPT can be used as a short option. */ + { + *cvt->short_end++ = opt->key; + if (real->arg) + { + *cvt->short_end++ = ':'; + if (real->flags & OPTION_ARG_OPTIONAL) + *cvt->short_end++ = ':'; + } + *cvt->short_end = '\0'; /* keep 0 terminated */ + } + + if (opt->name + && find_long_option (cvt->parser->long_opts, opt->name) < 0) + /* OPT can be used as a long option. */ + { + cvt->long_end->name = opt->name; + cvt->long_end->has_arg = + (real->arg + ? (real->flags & OPTION_ARG_OPTIONAL + ? optional_argument + : required_argument) + : no_argument); + cvt->long_end->flag = 0; + /* we add a disambiguating code to all the user's + values (which is removed before we actually call + the function to parse the value); this means that + the user loses use of the high 8 bits in all his + values (the sign of the lower bits is preserved + however)... */ + cvt->long_end->val = + ((opt->key ? opt->key : real->key) & USER_MASK) + + (((group - cvt->parser->groups) + 1) << USER_BITS); + + /* Keep the LONG_OPTS list terminated. */ + (++cvt->long_end)->name = NULL; + } + } + } + group->parser = argp->parser; group->argp = argp; + group->short_end = cvt->short_end; group->args_processed = 0; group->parent = parent; group->parent_index = parent_index; group->input = 0; group->hook = 0; group->child_inputs = 0; - + if (children) /* Assign GROUP's CHILD_INPUTS field some space from CVT->child_inputs_end.*/ @@ -469,6 +390,7 @@ convert_options (const struct argp *argp, group->child_inputs = cvt->child_inputs_end; cvt->child_inputs_end += num_children; } + parent = group++; } else @@ -484,42 +406,47 @@ convert_options (const struct argp *argp, return group; } -/* Allocate and initialize the group structures, so that they are - ordered as if by traversing the corresponding argp parser tree in - pre-order. Also build the list of short options, if that is needed. */ + +/* Find the merged set of getopt options, with keys appropriately prefixed. */ static void -parser_convert (struct parser *parser, const struct argp *argp) +parser_convert (struct parser *parser, const struct argp *argp, int flags) { struct parser_convert_state cvt; cvt.parser = parser; cvt.short_end = parser->short_opts; + cvt.long_end = parser->long_opts; cvt.child_inputs_end = parser->child_inputs; + if (flags & ARGP_IN_ORDER) + *cvt.short_end++ = '-'; + else if (flags & ARGP_NO_ARGS) + *cvt.short_end++ = '+'; + *cvt.short_end = '\0'; + + cvt.long_end->name = NULL; + parser->argp = argp; if (argp) parser->egroup = convert_options (argp, 0, 0, parser->groups, &cvt); else parser->egroup = parser->groups; /* No parsers at all! */ - - if (parser->short_opts) - *cvt.short_end ='\0'; } /* Lengths of various parser fields which we will allocated. */ struct parser_sizes { - /* Needed only ARGP_LONG_ONLY */ - size_t short_len; /* Number of short options. */ - + size_t short_len; /* Getopt short options string. */ + size_t long_len; /* Getopt long options vector. */ size_t num_groups; /* Group structures we allocate. */ size_t num_child_inputs; /* Child input slots. */ }; -/* For ARGP, increments the NUM_GROUPS field in SZS by the total - number of argp structures descended from it, and the SHORT_LEN by - the total number of short options. */ +/* For ARGP, increments the NUM_GROUPS field in SZS by the total number of + argp structures descended from it, and the SHORT_LEN & LONG_LEN fields by + the maximum lengths of the resulting merged getopt short options string and + long-options array, respectively. */ static void calc_sizes (const struct argp *argp, struct parser_sizes *szs) { @@ -528,12 +455,14 @@ calc_sizes (const struct argp *argp, struct parser_sizes *szs) if (opt || argp->parser) { - /* This parser needs a group. */ szs->num_groups++; if (opt) { - while (__option_is_short (opt++)) - szs->short_len++; + int num_opts = 0; + while (!__option_is_end (opt++)) + num_opts++; + szs->short_len += num_opts * 3; /* opt + up to 2 `:'s */ + szs->long_len += num_opts; } } @@ -554,64 +483,44 @@ parser_init (struct parser *parser, const struct argp *argp, struct group *group; struct parser_sizes szs; - parser->posixly_correct = getenv ("POSIXLY_CORRECT"); - - if (flags & ARGP_IN_ORDER) - parser->ordering = RETURN_IN_ORDER; - else if (flags & ARGP_NO_ARGS) - parser->ordering = REQUIRE_ORDER; - else if (parser->posixly_correct) - parser->ordering = REQUIRE_ORDER; - else - parser->ordering = PERMUTE; - - szs.short_len = 0; + szs.short_len = (flags & ARGP_NO_ARGS) ? 0 : 1; + szs.long_len = 0; szs.num_groups = 0; szs.num_child_inputs = 0; if (argp) calc_sizes (argp, &szs); - if (!(flags & ARGP_LONG_ONLY)) - /* We have no use for the short option array. */ - szs.short_len = 0; - /* Lengths of the various bits of storage used by PARSER. */ #define GLEN (szs.num_groups + 1) * sizeof (struct group) #define CLEN (szs.num_child_inputs * sizeof (void *)) +#define LLEN ((szs.long_len + 1) * sizeof (struct option)) #define SLEN (szs.short_len + 1) -#define STORAGE(offset) ((void *) (((char *) parser->storage) + (offset))) - parser->storage = malloc (GLEN + CLEN + SLEN); + parser->storage = malloc (GLEN + CLEN + LLEN + SLEN); if (! parser->storage) return ENOMEM; parser->groups = parser->storage; + parser->child_inputs = parser->storage + GLEN; + parser->long_opts = parser->storage + GLEN + CLEN; + parser->short_opts = parser->storage + GLEN + CLEN + LLEN; - parser->child_inputs = STORAGE(GLEN); memset (parser->child_inputs, 0, szs.num_child_inputs * sizeof (void *)); - - if (flags & ARGP_LONG_ONLY) - parser->short_opts = STORAGE(GLEN + CLEN); - else - parser->short_opts = NULL; - - parser_convert (parser, argp); + parser_convert (parser, argp, flags); memset (&parser->state, 0, sizeof (struct argp_state)); - parser->state.root_argp = parser->argp; parser->state.argc = argc; parser->state.argv = argv; parser->state.flags = flags; parser->state.err_stream = stderr; parser->state.out_stream = stdout; + parser->state.next = 0; /* Tell getopt to initialize. */ parser->state.pstate = parser; - parser->args_only = 0; - parser->nextchar = NULL; - parser->first_nonopt = parser->last_nonopt = 0; - + parser->try_getopt = 1; + /* Call each parser for the first time, giving it a chance to propagate values to child parsers. */ if (parser->groups < parser->egroup) @@ -639,17 +548,26 @@ parser_init (struct parser *parser, const struct argp *argp, if (err) return err; - if (argv[0] && !(parser->state.flags & ARGP_PARSE_ARGV0)) - /* There's an argv[0]; use it for messages. */ + if (parser->state.flags & ARGP_NO_ERRS) { - parser->state.name = __argp_basename(argv[0]); - - /* Don't parse it as an argument. */ - parser->state.next = 1; + opterr = 0; + if (parser->state.flags & ARGP_PARSE_ARGV0) + /* getopt always skips ARGV[0], so we have to fake it out. As long + as OPTERR is 0, then it shouldn't actually try to access it. */ + parser->state.argv--, parser->state.argc++; } else - parser->state.name = __argp_short_program_name(NULL); - + opterr = 1; /* Print error messages. */ + + if (parser->state.argv == argv && argv[0]) + /* There's an argv[0]; use it for messages. */ + { + char *short_name = strrchr (argv[0], '/'); + parser->state.name = short_name ? short_name + 1 : argv[0]; + } + else + parser->state.name = __argp_short_program_name (); + return 0; } @@ -745,16 +663,17 @@ parser_finalize (struct parser *parser, return err; } -/* Call the user parsers to parse the non-option argument VAL, at the - current position, returning any error. The state NEXT pointer - should point to the argument; this function will adjust it - correctly to reflect however many args actually end up being - consumed. */ +/* Call the user parsers to parse the non-option argument VAL, at the current + position, returning any error. The state NEXT pointer is assumed to have + been adjusted (by getopt) to point after this argument; this function will + adjust it correctly to reflect however many args actually end up being + consumed. */ static error_t parser_parse_arg (struct parser *parser, char *val) { - /* Save the starting value of NEXT */ - int index = parser->state.next; + /* Save the starting value of NEXT, first adjusting it so that the arg + we're parsing is again the front of the arg vector. */ + int index = --parser->state.next; error_t err = EBADKEY; struct group *group; int key = 0; /* Which of ARGP_KEY_ARG[S] we used. */ @@ -791,141 +710,70 @@ parser_parse_arg (struct parser *parser, char *val) the clock back. */ (--group)->args_processed += (parser->state.next - index); else - /* The user wants to reparse some args, so try looking for options again. */ - parser->args_only = 0; + /* The user wants to reparse some args, give getopt another try. */ + parser->try_getopt = 1; } return err; } -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,next), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. */ - -static void -exchange (struct parser *parser) +/* Call the user parsers to parse the option OPT, with argument VAL, at the + current position, returning any error. */ +static error_t +parser_parse_opt (struct parser *parser, int opt, char *val) { - int bottom = parser->first_nonopt; - int middle = parser->last_nonopt; - int top = parser->state.next; - char **argv = parser->state.argv; - - char *tem; + /* The group key encoded in the high bits; 0 for short opts or + group_number + 1 for long opts. */ + int group_key = opt >> USER_BITS; + error_t err = EBADKEY; - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. - It leaves the longer segment in the right place overall, - but it consists of two parts that need to be swapped next. */ - - while (top > middle && middle > bottom) + if (group_key == 0) + /* A short option. By comparing OPT's position in SHORT_OPTS to the + various starting positions in each group's SHORT_END field, we can + determine which group OPT came from. */ { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; + struct group *group; + char *short_index = strchr (parser->short_opts, opt); - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) + if (short_index) + for (group = parser->groups; group < parser->egroup; group++) + if (group->short_end > short_index) { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; + err = group_parse (group, &parser->state, opt, optarg); + break; } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } + } + else + /* A long option. We use shifts instead of masking for extracting + the user value in order to preserve the sign. */ + err = + group_parse (&parser->groups[group_key - 1], &parser->state, + (opt << GROUP_BITS) >> GROUP_BITS, optarg); + + if (err == EBADKEY) + /* At least currently, an option not recognized is an error in the + parser, because we pre-compute which parser is supposed to deal + with each option. */ + { + static const char bad_key_err[] = + N_("(PROGRAM ERROR) Option should have been recognized!?"); + if (group_key == 0) + __argp_error (&parser->state, "-%c: %s", opt, + dgettext (parser->argp->argp_domain, bad_key_err)); else { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; + struct option *long_opt = parser->long_opts; + while (long_opt->val != opt && long_opt->name) + long_opt++; + __argp_error (&parser->state, "--%s: %s", + long_opt->name ? long_opt->name : "???", + dgettext (parser->argp->argp_domain, bad_key_err)); } } - /* Update records for the slots the non-options now occupy. */ - - parser->first_nonopt += (parser->state.next - parser->last_nonopt); - parser->last_nonopt = parser->state.next; + return err; } - - -enum arg_type { ARG_ARG, ARG_SHORT_OPTION, - ARG_LONG_OPTION, ARG_LONG_ONLY_OPTION, - ARG_QUOTE }; - -static enum arg_type -classify_arg(struct parser *parser, char *arg, char **opt) -{ - if (arg[0] == '-') - /* Looks like an option... */ - switch (arg[1]) - { - case '\0': - /* "-" is not an option. */ - return ARG_ARG; - case '-': - /* Long option, or quote. */ - if (!arg[2]) - return ARG_QUOTE; - - /* A long option. */ - if (opt) - *opt = arg + 2; - return ARG_LONG_OPTION; - - default: - /* Short option. But if ARGP_LONG_ONLY, it can also be a long option. */ - - if (opt) - *opt = arg + 1; - - if (parser->state.flags & ARGP_LONG_ONLY) - { - /* Rules from getopt.c: - - If long_only and the ARGV-element has the form "-f", - where f is a valid short option, don't consider it an - abbreviated form of a long option that starts with f. - Otherwise there would be no way to give the -f short - option. - - On the other hand, if there's a long option "fubar" and - the ARGV-element is "-fu", do consider that an - abbreviation of the long option, just like "--fu", and - not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - assert(parser->short_opts); - - if (arg[2] || !strchr(parser->short_opts, arg[1])) - return ARG_LONG_ONLY_OPTION; - } - - return ARG_SHORT_OPTION; - } - - else - return ARG_ARG; -} - /* Parse the next argument in PARSER (as indicated by PARSER->state.next). Any error from the parsers is returned, and *ARGP_EBADKEY indicates whether a value of EBADKEY is due to an unrecognized argument (which is @@ -933,268 +781,86 @@ classify_arg(struct parser *parser, char *arg, char **opt) static error_t parser_parse_next (struct parser *parser, int *arg_ebadkey) { + int opt; + error_t err = 0; + if (parser->state.quoted && parser->state.next < parser->state.quoted) /* The next argument pointer has been moved to before the quoted - region, so pretend we never saw the quoting `--', and start - looking for options again. If the `--' is still there we'll just - process it one more time. */ - parser->state.quoted = parser->args_only = 0; + region, so pretend we never saw the quoting `--', and give getopt + another chance. If the user hasn't removed it, getopt will just + process it again. */ + parser->state.quoted = 0; - /* Give FIRST_NONOPT & LAST_NONOPT rational values if NEXT has been - moved back by the user (who may also have changed the arguments). */ - if (parser->last_nonopt > parser->state.next) - parser->last_nonopt = parser->state.next; - if (parser->first_nonopt > parser->state.next) - parser->first_nonopt = parser->state.next; - - if (parser->nextchar) - /* Deal with short options. */ + if (parser->try_getopt && !parser->state.quoted) + /* Give getopt a chance to parse this. */ { - struct group *group; - char c; - const struct argp_option *option; - char *value = NULL;; + /* Put it back in OPTIND for getopt. */ + optind = parser->state.next; + /* Distinguish KEY_ERR from a real option. */ + optopt = KEY_END; + if (parser->state.flags & ARGP_LONG_ONLY) + opt = getopt_long_only (parser->state.argc, parser->state.argv, + parser->short_opts, parser->long_opts, 0); + else + opt = getopt_long (parser->state.argc, parser->state.argv, + parser->short_opts, parser->long_opts, 0); + /* And see what getopt did. */ + parser->state.next = optind; - assert(!parser->args_only); - - c = *parser->nextchar++; - - option = find_short_option(parser, c, &group); - if (!option) + if (opt == KEY_END) + /* Getopt says there are no more options, so stop using + getopt; we'll continue if necessary on our own. */ + { + parser->try_getopt = 0; + if (parser->state.next > 1 + && strcmp (parser->state.argv[parser->state.next - 1], QUOTE) + == 0) + /* Not only is this the end of the options, but it's a + `quoted' region, which may have args that *look* like + options, so we definitely shouldn't try to use getopt past + here, whatever happens. */ + parser->state.quoted = parser->state.next; + } + else if (opt == KEY_ERR && optopt != KEY_END) + /* KEY_ERR can have the same value as a valid user short + option, but in the case of a real error, getopt sets OPTOPT + to the offending character, which can never be KEY_END. */ { - if (parser->posixly_correct) - /* 1003.2 specifies the format of this message. */ - fprintf (parser->state.err_stream, - dgettext(parser->state.root_argp->argp_domain, - "%s: illegal option -- %c\n"), - parser->state.name, c); - else - fprintf (parser->state.err_stream, - dgettext(parser->state.root_argp->argp_domain, - "%s: invalid option -- %c\n"), - parser->state.name, c); - *arg_ebadkey = 0; return EBADKEY; } - - if (!*parser->nextchar) - parser->nextchar = NULL; - - if (option->arg) - { - value = parser->nextchar; - parser->nextchar = NULL; - - if (!value - && !(option->flags & OPTION_ARG_OPTIONAL)) - /* We need an mandatory argument. */ - { - if (parser->state.next == parser->state.argc) - /* Missing argument */ - { - /* 1003.2 specifies the format of this message. */ - fprintf (parser->state.err_stream, - dgettext(parser->state.root_argp->argp_domain, - "%s: option requires an argument -- %c\n"), - parser->state.name, c); - - *arg_ebadkey = 0; - return EBADKEY; - } - value = parser->state.argv[parser->state.next++]; - } - } - return group_parse(group, &parser->state, - option->key, value); } else - /* Advance to the next ARGV-element. */ - { - if (parser->args_only) - { - *arg_ebadkey = 1; - if (parser->state.next >= parser->state.argc) - /* We're done. */ - return EBADKEY; - else - return parser_parse_arg(parser, - parser->state.argv[parser->state.next]); - } - - if (parser->state.next >= parser->state.argc) - /* Almost done. If there are non-options that we skipped - previously, we should process them now. */ - { - *arg_ebadkey = 1; - if (parser->first_nonopt != parser->last_nonopt) - { - exchange(parser); - - /* Start processing the arguments we skipped previously. */ - parser->state.next = parser->first_nonopt; - - parser->first_nonopt = parser->last_nonopt = 0; + opt = KEY_END; - parser->args_only = 1; - return 0; - } - else - /* Indicate that we're really done. */ - return EBADKEY; + if (opt == KEY_END) + { + /* We're past what getopt considers the options. */ + if (parser->state.next >= parser->state.argc + || (parser->state.flags & ARGP_NO_ARGS)) + /* Indicate that we're done. */ + { + *arg_ebadkey = 1; + return EBADKEY; } else - /* Look for options. */ + /* A non-option arg; simulate what getopt might have done. */ { - char *arg = parser->state.argv[parser->state.next]; - - char *optstart; - enum arg_type token = classify_arg(parser, arg, &optstart); - - switch (token) - { - case ARG_ARG: - switch (parser->ordering) - { - case PERMUTE: - if (parser->first_nonopt == parser->last_nonopt) - /* Skipped sequence is empty; start a new one. */ - parser->first_nonopt = parser->last_nonopt = parser->state.next; - - else if (parser->last_nonopt != parser->state.next) - /* We have a non-empty skipped sequence, and - we're not at the end-point, so move it. */ - exchange(parser); - - assert(parser->last_nonopt == parser->state.next); - - /* Skip this argument for now. */ - parser->state.next++; - parser->last_nonopt = parser->state.next; - - return 0; - - case REQUIRE_ORDER: - /* Implicit quote before the first argument. */ - parser->args_only = 1; - return 0; - - case RETURN_IN_ORDER: - *arg_ebadkey = 1; - return parser_parse_arg(parser, arg); - - default: - abort(); - } - case ARG_QUOTE: - /* Skip it, then exchange with any previous non-options. */ - parser->state.next++; - assert (parser->last_nonopt != parser->state.next); - - if (parser->first_nonopt != parser->last_nonopt) - { - exchange(parser); - - /* Start processing the skipped and the quoted - arguments. */ - - parser->state.quoted = parser->state.next = parser->first_nonopt; - - /* Also empty the skipped-list, to avoid confusion - if the user resets the next pointer. */ - parser->first_nonopt = parser->last_nonopt = 0; - } - else - parser->state.quoted = parser->state.next; - - parser->args_only = 1; - return 0; - - case ARG_LONG_ONLY_OPTION: - case ARG_LONG_OPTION: - { - struct group *group; - const struct argp_option *option; - char *value; - - parser->state.next++; - option = find_long_option(parser, optstart, &group); - - if (!option) - { - /* NOTE: This includes any "=something" in the output. */ - fprintf (parser->state.err_stream, - dgettext(parser->state.root_argp->argp_domain, - "%s: unrecognized option `%s'\n"), - parser->state.name, arg); - *arg_ebadkey = 0; - return EBADKEY; - } - - value = strchr(optstart, '='); - if (value) - value++; - - if (value && !option->arg) - /* Unexpected argument. */ - { - if (token == ARG_LONG_OPTION) - /* --option */ - fprintf (parser->state.err_stream, - dgettext(parser->state.root_argp->argp_domain, - "%s: option `--%s' doesn't allow an argument\n"), - parser->state.name, option->name); - else - /* +option or -option */ - fprintf (parser->state.err_stream, - dgettext(parser->state.root_argp->argp_domain, - "%s: option `%c%s' doesn't allow an argument\n"), - parser->state.name, arg[0], option->name); - - *arg_ebadkey = 0; - return EBADKEY; - } - - if (option->arg && !value - && !(option->flags & OPTION_ARG_OPTIONAL)) - /* We need an mandatory argument. */ - { - if (parser->state.next == parser->state.argc) - /* Missing argument */ - { - if (token == ARG_LONG_OPTION) - /* --option */ - fprintf (parser->state.err_stream, - dgettext(parser->state.root_argp->argp_domain, - "%s: option `--%s' requires an argument\n"), - parser->state.name, option->name); - else - /* +option or -option */ - fprintf (parser->state.err_stream, - dgettext(parser->state.root_argp->argp_domain, - "%s: option `%c%s' requires an argument\n"), - parser->state.name, arg[0], option->name); - - *arg_ebadkey = 0; - return EBADKEY; - } - - value = parser->state.argv[parser->state.next++]; - } - *arg_ebadkey = 0; - return group_parse(group, &parser->state, - option->key, value); - } - case ARG_SHORT_OPTION: - parser->state.next++; - parser->nextchar = optstart; - return 0; - - default: - abort(); - } + opt = KEY_ARG; + optarg = parser->state.argv[parser->state.next++]; } } + + if (opt == KEY_ARG) + /* A non-option argument; try each parser in turn. */ + err = parser_parse_arg (parser, optarg); + else + err = parser_parse_opt (parser, opt, optarg); + + if (err == EBADKEY) + *arg_ebadkey = (opt == KEY_END || opt == KEY_ARG); + + return err; } /* Parse the options strings in ARGC & ARGV according to the argp in ARGP. @@ -1273,31 +939,3 @@ __argp_input (const struct argp *argp, const struct argp_state *state) #ifdef weak_alias weak_alias (__argp_input, _argp_input) #endif - -/* Defined here, in case a user is not inlining the definitions in - * argp.h */ -void -__argp_usage (__const struct argp_state *__state) __THROW -{ - __argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE); -} - -int -__option_is_short (__const struct argp_option *__opt) __THROW -{ - if (__opt->flags & OPTION_DOC) - return 0; - else - { - int __key = __opt->key; - /* FIXME: whether or not a particular key implies a short option - * ought not to be locale dependent. */ - return __key > 0 && isprint (__key); - } -} - -int -__option_is_end (__const struct argp_option *__opt) __THROW -{ - return !__opt->key && !__opt->name && !__opt->doc && !__opt->group; -}