diff options
Diffstat (limited to 'argp')
-rw-r--r-- | argp/argp-parse.c | 126 | ||||
-rw-r--r-- | argp/argp.h | 11 |
2 files changed, 100 insertions, 37 deletions
diff --git a/argp/argp-parse.c b/argp/argp-parse.c index edc5516851..018a97807e 100644 --- a/argp/argp-parse.c +++ b/argp/argp-parse.c @@ -38,6 +38,7 @@ # define _(msgid) (msgid) # define gettext(msgid) (msgid) #endif +#define N_(msgid) (msgid) #endif #if _LIBC - 0 @@ -84,11 +85,11 @@ volatile int _argp_hang = 0; static const struct argp_option argp_default_options[] = { - {"help", '?', 0, 0, "Give this help list", -1}, - {"usage", OPT_USAGE, 0, 0, "Give a short usage message"}, - {"program-name",OPT_PROGNAME,"NAME", OPTION_HIDDEN, "Set the program name"}, + {"help", '?', 0, 0, N_("Give this help list"), -1}, + {"usage", OPT_USAGE, 0, 0, N_("Give a short usage message")}, + {"program-name",OPT_PROGNAME,"NAME", OPTION_HIDDEN, N_("Set the program name")}, {"HANG", OPT_HANG, "SECS", OPTION_ARG_OPTIONAL | OPTION_HIDDEN, - "Hang for SECS seconds (default 3600)"}, + N_("Hang for SECS seconds (default 3600)")}, {0, 0} }; @@ -145,7 +146,7 @@ static const struct argp argp_default_argp = static const struct argp_option argp_version_options[] = { - {"version", 'V', 0, 0, "Print program version", -1}, + {"version", 'V', 0, 0, N_("Print program version"), -1}, {0, 0} }; @@ -160,7 +161,7 @@ argp_version_parser (int key, char *arg, struct argp_state *state) else if (argp_program_version) fprintf (state->out_stream, "%s\n", argp_program_version); else - __argp_error (state, _("No version known!?")); + __argp_error (state, _("(PROGRAM ERROR) No version known!?")); if (! (state->flags & ARGP_NO_EXIT)) exit (0); break; @@ -637,8 +638,8 @@ parser_finalize (struct parser *parser, err = EBADKEY; } - /* Okay, we're all done, with either an error or success. We only call the - parsers once more, to indicate which one. */ + /* Okay, we're all done, with either an error or success; call the parsers + to indicate which one. */ if (err) { @@ -654,7 +655,7 @@ parser_finalize (struct parser *parser, group_parse (group, &parser->state, ARGP_KEY_ERROR, 0); } else - /* Do final cleanup, including propagating back values from parsers. */ + /* Notify parsers of success, and propagate back values from parsers. */ { /* We pass over the groups in reverse order so that child groups are given a chance to do there processing before passing back a value to @@ -667,6 +668,10 @@ parser_finalize (struct parser *parser, err = 0; /* Some parser didn't understand. */ } + /* Call parsers once more, to do any final cleanup. Errors are ignored. */ + for (group = parser->egroup - 1; group >= parser->groups; group--) + group_parse (group, &parser->state, ARGP_KEY_FINI, 0); + if (err == EBADKEY) err = EINVAL; @@ -676,28 +681,55 @@ parser_finalize (struct parser *parser, } /* Call the user parsers to parse the non-option argument VAL, at the current - position, returning any error. */ + 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) { - 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. */ + /* Try to parse the argument in each parser. */ for (group = parser->groups ; group < parser->egroup && err == EBADKEY ; group++) - err = group_parse (group, &parser->state, ARGP_KEY_ARG, val); - - if (!err) - if (parser->state.next >= index) - /* Remember that we successfully processed a non-option - argument -- but only if the user hasn't gotten tricky and set - the clock back. */ - (--group)->args_processed++; - else - /* The user wants to reparse some args, give getopt another try. */ - parser->try_getopt = 1; + { + parser->state.next++; /* For ARGP_KEY_ARG, consume the arg. */ + key = ARGP_KEY_ARG; + err = group_parse (group, &parser->state, key, val); + + if (err == EBADKEY) + /* This parser doesn't like ARGP_KEY_ARG; try ARGP_KEY_ARGS instead. */ + { + parser->state.next--; /* For ARGP_KEY_ARGS, put back the arg. */ + key = ARGP_KEY_ARGS; + err = group_parse (group, &parser->state, key, 0); + } + } + + if (! err) + { + if (key == ARGP_KEY_ARGS) + /* The default for ARGP_KEY_ARGS is to assume that if NEXT isn't + changed by the user, *all* arguments should be considered + consumed. */ + parser->state.next = parser->state.argc; + + if (parser->state.next > index) + /* Remember that we successfully processed a non-option + argument -- but only if the user hasn't gotten tricky and set + the clock back. */ + (--group)->args_processed += (parser->state.next - index); + else + /* The user wants to reparse some args, give getopt another try. */ + parser->try_getopt = 1; + } return err; } @@ -710,6 +742,7 @@ parser_parse_opt (struct parser *parser, int opt, char *val) /* 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; if (group_key == 0) /* A short option. By comparing OPT's position in SHORT_OPTS to the @@ -722,16 +755,39 @@ parser_parse_opt (struct parser *parser, int opt, char *val) if (short_index) for (group = parser->groups; group < parser->egroup; group++) if (group->short_end > short_index) - return group_parse (group, &parser->state, opt, optarg); - - return EBADKEY; /* until otherwise asserted */ + { + err = group_parse (group, &parser->state, opt, optarg); + break; + } } else /* A long option. We use shifts instead of masking for extracting the user value in order to preserve the sign. */ - return + 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, _(bad_key_err)); + else + { + 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 : "???", + _(bad_key_err)); + } + } + + return err; } /* Parse the next argument in PARSER (as indicated by PARSER->state.next). @@ -800,20 +856,20 @@ parser_parse_next (struct parser *parser, int *arg_ebadkey) return EBADKEY; } else - /* A non-option arg. */ - err = - parser_parse_arg (parser, parser->state.argv[parser->state.next++]); - else if (opt == KEY_ARG) + /* A non-option arg; simulate what getopt might have done. */ + { + 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); - parser->state.next--; /* Put back the unused argument. */ - } + *arg_ebadkey = (opt == KEY_END || opt == KEY_ARG); return err; } diff --git a/argp/argp.h b/argp/argp.h index 61ed8351e6..2305590a5d 100644 --- a/argp/argp.h +++ b/argp/argp.h @@ -160,6 +160,12 @@ typedef error_t (*argp_parser_t)(int key, char *arg, struct argp_state *state); actually modify the argument (perhaps into an option), and have it processed again. */ #define ARGP_KEY_ARG 0 +/* There are remaining arguments not parsed by any parser, which may be found + starting at (STATE->argv + STATE->next). If success is returned, but + STATE->next left untouched, it's assumed that all arguments were consume, + otherwise, the parser should adjust STATE->next to reflect any arguments + consumed. */ +#define ARGP_KEY_ARGS 0x1000006 /* There are no more command line arguments at all. */ #define ARGP_KEY_END 0x1000001 /* Because it's common to want to do some special processing if there aren't @@ -172,11 +178,12 @@ typedef error_t (*argp_parser_t)(int key, char *arg, struct argp_state *state); element of the CHILD_INPUT field, if any, in the state structure is copied to each child's state to be the initial value of the INPUT field. */ #define ARGP_KEY_INIT 0x1000003 +/* Use after all other keys, including SUCCESS & END. */ +#define ARGP_KEY_FINI 0x1000007 /* Passed in when parsing has successfully been completed (even if there are still arguments remaining). */ #define ARGP_KEY_SUCCESS 0x1000004 -/* Passed in if an error occurs (in which case a call with ARGP_KEY_SUCCESS is - never made, so any cleanup must be done here). */ +/* Passed in if an error occurs. */ #define ARGP_KEY_ERROR 0x1000005 /* An argp structure contains a set of options declarations, a function to |