📄 argp-parse.c
字号:
}/* Lengths of various parser fields which we will allocated. */struct parser_sizes{ 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 & LONG_LEN fields by the maximum lengths of the resulting merged getopt short options string and long-options array, respectively. */static voidcalc_sizes (const struct argp *argp, struct parser_sizes *szs){ const struct argp_child *child = argp->children; const struct argp_option *opt = argp->options; if (opt || argp->parser) { szs->num_groups++; if (opt) { 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; } } if (child) while (child->argp) { calc_sizes ((child++)->argp, szs); szs->num_child_inputs++; }}/* Initializes PARSER to parse ARGP in a manner described by FLAGS. */static error_tparser_init (struct parser *parser, const struct argp *argp, int argc, char **argv, int flags, void *input){ error_t err = 0; struct group *group; struct parser_sizes szs; 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); /* 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) 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; memset (parser->child_inputs, 0, szs.num_child_inputs * sizeof (void *)); parser_convert (parser, argp, flags); memset (&parser->state, 0, sizeof (struct argp_state)); parser->state.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->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) parser->groups->input = input; for (group = parser->groups; group < parser->egroup && (!err || err == EBADKEY); group++) { if (group->parent) /* If a child parser, get the initial input value from the parent. */ group->input = group->parent->child_inputs[group->parent_index]; err = group_parse (group, &parser->state, ARGP_KEY_INIT, 0); } if (err == EBADKEY) err = 0; /* Some parser didn't understand. */ if (err) return err; /* Getopt is (currently) non-reentrant. */ LOCK_GETOPT; if (parser->state.flags & ARGP_NO_ERRS) { 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 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 = program_invocation_short_name; return 0;}/* Free any storage consumed by PARSER (but not PARSER itself). */static error_tparser_finalize (struct parser *parser, error_t err, int arg_ebadkey, int *end_index){ struct group *group; UNLOCK_GETOPT; if (err == EBADKEY && arg_ebadkey) /* Suppress errors generated by unparsed arguments. */ err = 0; if (! err) if (parser->state.next == parser->state.argc) /* We successfully parsed all arguments! Call all the parsers again, just a few more times... */ { for (group = parser->groups; group < parser->egroup && (!err || err==EBADKEY); group++) if (group->args_processed == 0) err = group_parse (group, &parser->state, ARGP_KEY_NO_ARGS, 0); for (group = parser->groups; group < parser->egroup && (!err || err==EBADKEY); group++) err = group_parse (group, &parser->state, ARGP_KEY_END, 0); if (err == EBADKEY) err = 0; /* Some parser didn't understand. */ } else if (end_index) /* Return any remaining arguments to the user. */ *end_index = parser->state.next; else /* No way to return the remaining arguments, they must be bogus. */ { if (!(parser->state.flags & ARGP_NO_ERRS) && parser->state.err_stream) fprintf (parser->state.err_stream, _("%s: Too many arguments\n"), parser->state.name); err = EBADKEY; } /* Okay, we're all done, with either an error or success. We only call the parsers once more, to indicate which one. */ if (err) { /* Maybe print an error message. */ if (err == EBADKEY) /* An appropriate message describing what the error was should have been printed earlier. */ __argp_state_help (&parser->state, parser->state.err_stream, ARGP_HELP_STD_ERR); /* Since we didn't exit, give each parser an error indication. */ for (group = parser->groups; group < parser->egroup; group++) group_parse (group, &parser->state, ARGP_KEY_ERROR, 0); } else /* Do final cleanup, including propagating 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 the parent. */ for (group = parser->egroup - 1 ; group >= parser->groups && (!err || err == EBADKEY) ; group--) err = group_parse (group, &parser->state, ARGP_KEY_SUCCESS, 0); if (err == EBADKEY) err = 0; /* Some parser didn't understand. */ } if (err == EBADKEY) err = EINVAL; free (parser->storage); return err;}/* Call the user parsers to parse the non-option argument VAL, at the current position, returning any error. */static error_tparser_parse_arg (struct parser *parser, char *val){ int index = parser->state.next; error_t err = EBADKEY; struct group *group; 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; return err;}/* Call the user parsers to parse the option OPT, with argument VAL, at the current position, returning any error. */static error_tparser_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; 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. */ { struct group *group; char *short_index = strchr (parser->short_opts, opt); 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 */ } else /* A long option. We use shifts instead of masking for extracting the user value in order to preserve the sign. */ return group_parse (&parser->groups[group_key - 1], &parser->state, (opt << GROUP_BITS) >> GROUP_BITS, optarg);}/* 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 generally not fatal). */static error_tparser_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 give getopt another chance. If the user hasn't removed it, getopt will just process it again. */ parser->state.quoted = 0; if (parser->try_getopt && !parser->state.quoted) /* Give getopt a chance to parse this. */ { optind = parser->state.next; /* Put it back in OPTIND for getopt. */ optopt = KEY_END; /* Distinguish KEY_ERR from a real option. */ 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); parser->state.next = optind; /* And see what getopt did. */ 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. */ { *arg_ebadkey = 0; return EBADKEY; } } else opt = KEY_END; 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 /* A non-option arg. */ err = parser_parse_arg (parser, parser->state.argv[parser->state.next++]); else 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. */ } return err;}/* Parse the options strings in ARGC & ARGV according to the argp in ARGP. FLAGS is one of the ARGP_ flags above. If END_INDEX is non-NULL, the index in ARGV of the first unparsed option is returned in it. If an unknown option is present, EINVAL is returned; if some parser routine returned a non-zero value, it is returned; otherwise 0 is returned. */error_t__argp_parse (const struct argp *argp, int argc, char **argv, unsigned flags, int *end_index, void *input){ error_t err; struct parser parser; /* If true, then err == EBADKEY is a result of a non-option argument failing to be parsed (which in some cases isn't actually an error). */ int arg_ebadkey = 0;#if !HAVE_PROGRAM_INVOCATION_NAME /* Set the PROGRAM_INVOCATION_NAME and PROGRAM_INVOCATION_SHORT_NAME if this system doesn't automatically do that. */ { char *s; program_invocation_name = argv[0]; s = strrchr (program_invocation_name, '/'); if (s) program_invocation_short_name = s + 1; else program_invocation_short_name = program_invocation_name; }#endif if (! (flags & ARGP_NO_HELP)) /* Add our own options. */ { struct argp_child *child = alloca (4 * sizeof (struct argp_child)); struct argp *top_argp = alloca (sizeof (struct argp)); /* TOP_ARGP has no options, it just serves to group the user & default argps. */ memset (top_argp, 0, sizeof (*top_argp)); top_argp->children = child; memset (child, 0, 4 * sizeof (struct argp_child)); if (argp) (child++)->argp = argp; (child++)->argp = &argp_default_argp; if (argp_program_version || argp_program_version_hook) (child++)->argp = &argp_version_argp; child->argp = 0; argp = top_argp; } /* Construct a parser for these arguments. */ err = parser_init (&parser, argp, argc, argv, flags, input); if (! err) /* Parse! */ { while (! err) err = parser_parse_next (&parser, &arg_ebadkey); err = parser_finalize (&parser, err, arg_ebadkey, end_index); } return err;}#ifdef weak_aliasweak_alias (__argp_parse, argp_parse)#endif/* Return the input field for ARGP in the parser corresponding to STATE; used by the help routines. */void *__argp_input (const struct argp *argp, const struct argp_state *state){ if (state) { struct group *group; struct parser *parser = state->pstate; for (group = parser->groups; group < parser->egroup; group++) if (group->argp == argp) return group->input; } return 0;}#ifdef weak_aliasweak_alias (__argp_input, _argp_input)#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -