⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 argp-parse.c

📁 gnu tar 源码包。 tar 软件是 Unix 系统下的一个打包软件
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Hierarchial argument parsing, layered over getopt   Copyright (C) 1995-2000, 2002, 2003, 2004 Free Software Foundation, Inc.   This file is part of the GNU C Library.   Written by Miles Bader <miles@gnu.ai.mit.edu>.   This program is free software: you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3 of the License, or   (at your option) any later version.   This program 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 General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <alloca.h>#include <stddef.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <limits.h>#include <getopt.h>#include <getopt_int.h>#ifdef _LIBC# include <libintl.h># undef dgettext# define dgettext(domain, msgid) \   INTUSE(__dcgettext) (domain, msgid, LC_MESSAGES)#else# include "gettext.h"#endif#define N_(msgid) msgid#include "argp.h"#include "argp-namefrob.h"#define alignof(type) offsetof (struct { char c; type x; }, x)#define alignto(n, d) ((((n) + (d) - 1) / (d)) * (d))/* 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.  */static volatile int _argp_hang;#define OPT_PROGNAME	-2#define OPT_USAGE	-3#define OPT_HANG	-4static 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,N_("NAME"), OPTION_HIDDEN, N_("set the program name"), 0},  {"HANG",	  OPT_HANG,    N_("SECS"), OPTION_ARG_OPTIONAL | OPTION_HIDDEN,     N_("hang for SECS seconds (default 3600)"), 0},  {NULL, 0, 0, 0, NULL, 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.  */#if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_NAME      program_invocation_name = arg;#endif      /* [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.]  */      /* Update what we use for messages.  */      state->name = __argp_base_name (arg);#if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME      program_invocation_short_name = state->name;#endif      if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS))	  == ARGP_PARSE_ARGV0)	/* Update what getopt uses too.  */	state->argv[0] = arg;      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, NULL, NULL, NULL, NULL, "libc"};static const struct argp_option argp_version_options[] ={  {"version",	  'V',    	0, 0,  N_("print program version"), -1},  {NULL, 0, 0, 0, NULL, 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, dgettext (state->root_argp->argp_domain,				       "(PROGRAM ERROR) 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, 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 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;}/* 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;  /* OPT_DATA is the getopt data used for the re-entrant getopt.  */  struct _getopt_data opt_data;  /* 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! */}/* 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;  struct _getopt_data opt_data = _GETOPT_DATA_INITIALIZER;  char *storage;  size_t glen, gsum;  size_t clen, csum;  size_t llen, lsum;  size_t slen, ssum;  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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -