aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'argp/argp-parse.c')
-rw-r--r--argp/argp-parse.c126
1 files changed, 91 insertions, 35 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;
}