📄 argp-parse.c
字号:
/* Hierarchial argument parsing, layered over getopt Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader <miles@gnu.ai.mit.edu>. 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. 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. 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. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdlib.h>#include <string.h>#include <unistd.h>#include <limits.h>#include <getopt.h>#ifndef _/* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */#ifdef HAVE_LIBINTL_H# include <libintl.h># define _(msgid) gettext (msgid)#else# define _(msgid) (msgid)# define gettext(msgid) (msgid)#endif#endif#if _LIBC - 0#include <libc-lock.h>#else#ifdef HAVE_CTHREADS_H#include <cthreads.h>#endif#endif /* _LIBC */#include "argp.h"#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. *//* When argp is given the --HANG switch, _ARGP_HANG is set and argp will sleep 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 = 0;#define OPT_PROGNAME -2#define OPT_USAGE -3#define OPT_HANG -4static 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"}, {"HANG", OPT_HANG, "SECS", OPTION_ARG_OPTIONAL | OPTION_HIDDEN, "Hang for SECS seconds (default 3600)"}, {0, 0}};static error_targp_default_parser (int key, char *arg, struct argp_state *state){ switch (key) { case '?': __argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP); break; case OPT_USAGE: __argp_state_help (state, state->out_stream, ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); break; case OPT_PROGNAME: /* Set the program name. */ program_invocation_name = arg; /* [Note that some systems only have PROGRAM_INVOCATION_SHORT_NAME (aka __PROGNAME), in which case, PROGRAM_INVOCATION_NAME is just defined to be that, so we have to be a bit careful here.] */ arg = strrchr (arg, '/'); if (arg) program_invocation_short_name = arg + 1; else program_invocation_short_name = program_invocation_name; /* Update what we use for messages. */ state->name = program_invocation_short_name; if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS)) == ARGP_PARSE_ARGV0) /* Update what getopt uses too. */ state->argv[0] = program_invocation_name; break; case OPT_HANG: _argp_hang = atoi (arg ? arg : "3600"); while (_argp_hang-- > 0) __sleep (1); break; default: return EBADKEY; } return 0;}static const struct argp argp_default_argp = {argp_default_options, &argp_default_parser};static const struct argp_option argp_version_options[] ={ {"version", 'V', 0, 0, "Print program version", -1}, {0, 0}};static error_targp_version_parser (int key, char *arg, struct argp_state *state){ switch (key) { case 'V': if (argp_program_version_hook) (*argp_program_version_hook) (state->out_stream, state); else if (argp_program_version) fprintf (state->out_stream, "%s\n", argp_program_version); else __argp_error (state, _("No version known!?")); if (! (state->flags & ARGP_NO_EXIT)) exit (0); break; default: return EBADKEY; } return 0;}static const struct argp argp_version_argp = {argp_version_options, &argp_version_parser};/* 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 intfind_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;}/* If we can, we regulate access to getopt, which is non-reentrant, with a mutex. Since the case we're trying to guard against is two different threads interfering, and it's possible that someone might want to call argp_parse recursively (they're careful), we use a recursive lock if possible. */#if _LIBC - 0__libc_lock_define_initialized_recursive (static, getopt_lock)#define LOCK_GETOPT __libc_lock_lock_recursive (getopt_lock)#define UNLOCK_GETOPT __libc_lock_unlock_recursive (getopt_lock)#else /* !_LIBC */#ifdef HAVE_CTHREADS_Hstatic struct mutex getopt_lock = MUTEX_INITIALIZER;#define LOCK_GETOPT mutex_lock (&getopt_lock)#define UNLOCK_GETOPT mutex_unlock (&getopt_lock)#else /* !HAVE_CTHREADS_H */#define LOCK_GETOPT (void)0#define UNLOCK_GETOPT (void)0#endif /* HAVE_CTHREADS_H */#endif /* _LIBC *//* This hack to allow programs that know what's going on to call argp recursively. If someday argp is changed not to use the non-reentrant getopt interface, we can get rid of this shit. XXX */void_argp_unlock_xxx (void){ UNLOCK_GETOPT;}/* The state of a `group' during parsing. Each group corresponds to a particular argp structure from the tree of such descending from the top level argp passed to argp_parse. */struct group{ /* This group's parsing function. */ argp_parser_t parser; /* 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; /* This group's parser's parent's group. */ struct group *parent; unsigned parent_index; /* And the our position in the parent. */ /* These fields are swapped into and out of the state structure when calling this group's parser. */ void *input, **child_inputs; void *hook;};/* Call GROUP's parser with KEY and ARG, swapping any group-specific info from STATE before calling, and back into state afterwards. If GROUP has no parser, EBADKEY is returned. */static error_tgroup_parse (struct group *group, struct argp_state *state, int key, char *arg){ if (group->parser) { error_t err; state->hook = group->hook; state->input = group->input; state->child_inputs = group->child_inputs; state->arg_num = group->args_processed; err = (*group->parser)(key, arg, state); group->hook = state->hook; return err; } else return EBADKEY;}struct parser{ const struct argp *argp; /* 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; /* 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;};/* The next usable entries in the various parser tables being filled in by convert_options. */struct parser_convert_state{ struct parser *parser; char *short_end; struct option *long_end; void **child_inputs_end;};/* 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){ /* 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 (real || argp->parser) { 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 | 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.*/ { unsigned num_children = 0; while (children[num_children].argp) num_children++; group->child_inputs = cvt->child_inputs_end; cvt->child_inputs_end += num_children; } parent = group++; } else parent = 0; if (children) { unsigned index = 0; while (children->argp) group = convert_options (children++->argp, parent, index++, group, cvt); } return group;}/* Find the merged set of getopt options, with keys appropiately prefixed. */static voidparser_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! */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -