1607 lines · 44.8 KB · C
RawDownload
/* [argparse.c wk 17.06.97] Argument Parser for option handling * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc. * Copyright (C) 1997-2001, 2006-2008, 2013-2015 Werner Koch * * This file is part of JNLIB, which is a subsystem of GnuPG. * * JNLIB is free software; you can redistribute it and/or modify it * under the terms of either * *   - the GNU Lesser General Public License as published by the Free *     Software Foundation; either version 3 of the License, or (at *     your option) any later version. * * or * *   - the GNU General Public License as published by the Free *     Software Foundation; either version 2 of the License, or (at *     your option) any later version. * * or both in parallel, as here. * * JNLIB 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 copies of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, see <http://www.gnu.org/licenses/>. */ /* This file may be used as part of GnuPG or standalone.  A GnuPG   build is detected by the presence of the macro GNUPG_MAJOR_VERSION.   Some feature are only availalbe in the GnuPG build mode. */ #ifdef HAVE_CONFIG_H#include <config.h>#endif #include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <string.h>#include <stdarg.h>#include <limits.h>#include <errno.h> #ifdef GNUPG_MAJOR_VERSION# include "libjnlib-config.h"# include "mischelp.h"# include "stringhelp.h"# include "logging.h"# ifdef JNLIB_NEED_UTF8CONV#  include "utf8conv.h"# endif#endif /*GNUPG_MAJOR_VERSION*/ #include "argparse.h" /* GnuPG uses GPLv3+ but a standalone version of this defaults to   GPLv2+ because that is the license of this file.  Change this if   you include it in a program which uses GPLv3.  If you don't want to   set a a copyright string for your usage() you may also hardcode it   here.  */#ifndef GNUPG_MAJOR_VERSION # define ARGPARSE_GPL_VERSION      2# define ARGPARSE_CRIGHT_STR "Copyright (C) YEAR NAME" #else /* Used by GnuPG  */ # define ARGPARSE_GPL_VERSION      3# define ARGPARSE_CRIGHT_STR "Copyright (C) 2015 Free Software Foundation, Inc." #endif /*GNUPG_MAJOR_VERSION*/ /* Replacements for standalone builds.  */#ifndef GNUPG_MAJOR_VERSION# ifndef _#  define _(a)  (a)# endif# ifndef DIM#  define DIM(v)           (sizeof(v)/sizeof((v)[0]))# endif# define jnlib_malloc(a)    malloc ((a))# define jnlib_realloc(a,b) realloc ((a), (b))# define jnlib_strdup(a)    strdup ((a))# define jnlib_free(a)      free ((a))# define jnlib_log_error    my_log_error# define jnlib_log_bug	    my_log_bug# define trim_spaces(a)     my_trim_spaces ((a))# define map_static_macro_string(a)  (a)#endif /*!GNUPG_MAJOR_VERSION*/  #define ARGPARSE_STR(v) #v#define ARGPARSE_STR2(v) ARGPARSE_STR(v)  /* Replacements for standalone builds.  */#ifndef GNUPG_MAJOR_VERSIONstatic voidmy_log_error (const char *fmt, ...){  va_list arg_ptr ;   va_start (arg_ptr, fmt);  fprintf (stderr, "%s: ", strusage (11));  vfprintf (stderr, fmt, arg_ptr);  va_end (arg_ptr);} static voidmy_log_bug (const char *fmt, ...){  va_list arg_ptr ;   va_start (arg_ptr, fmt);  fprintf (stderr, "%s: Ohhhh jeeee: ", strusage (11));  vfprintf (stderr, fmt, arg_ptr);  va_end (arg_ptr);  abort ();} static char *my_trim_spaces (char *str){  char *string, *p, *mark;   string = str;  /* Find first non space character. */  for (p=string; *p && isspace (*(unsigned char*)p) ; p++)    ;  /* Move characters. */  for ((mark = NULL); (*string = *p); string++, p++)    if (isspace (*(unsigned char*)p))      {        if (!mark)          mark = string;      }    else      mark = NULL;  if (mark)    *mark = '\0' ;  /* Remove trailing spaces. */   return str ;} #endif /*!GNUPG_MAJOR_VERSION*/   /********************************* * @Summary arg_parse *  #include "argparse.h" * *  typedef struct { *	char *argc;		  pointer to argc (value subject to change) *	char ***argv;		  pointer to argv (value subject to change) *	unsigned flags; 	  Global flags (DO NOT CHANGE) *	int err;		  print error about last option *				  1 = warning, 2 = abort *	int r_opt;		  return option *	int r_type;		  type of return value (0 = no argument found) *	union { *	    int   ret_int; *	    long  ret_long *	    ulong ret_ulong; *	    char *ret_str; *	} r;			  Return values *	struct { *	    int idx; *	    const char *last; *	    void *aliases; *	} internal;		  DO NOT CHANGE *  } ARGPARSE_ARGS; * *  typedef struct { *	int	    short_opt; *	const char *long_opt; *	unsigned flags; *  } ARGPARSE_OPTS; * *  int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts ); * * @Description *  This is my replacement for getopt(). See the example for a typical usage. *  Global flags are: *     Bit 0 : Do not remove options form argv *     Bit 1 : Do not stop at last option but return other args *	       with r_opt set to -1. *     Bit 2 : Assume options and real args are mixed. *     Bit 3 : Do not use -- to stop option processing. *     Bit 4 : Do not skip the first arg. *     Bit 5 : allow usage of long option with only one dash *     Bit 6 : ignore --version *     all other bits must be set to zero, this value is modified by the *     function, so assume this is write only. *  Local flags (for each option): *     Bit 2-0 : 0 = does not take an argument *		 1 = takes int argument *		 2 = takes string argument *		 3 = takes long argument *		 4 = takes ulong argument *     Bit 3 : argument is optional (r_type will the be set to 0) *     Bit 4 : allow 0x etc. prefixed values. *     Bit 6 : Ignore this option *     Bit 7 : This is a command and not an option *  You stop the option processing by setting opts to NULL, the function will *  then return 0. * @Return Value *   Returns the args.r_opt or 0 if ready *   r_opt may be -2/-7 to indicate an unknown option/command. * @See Also *   ArgExpand * @Notes *  You do not need to process the options 'h', '--help' or '--version' *  because this function includes standard help processing; but if you *  specify '-h', '--help' or '--version' you have to do it yourself. *  The option '--' stops argument processing; if bit 1 is set the function *  continues to return normal arguments. *  To process float args or unsigned args you must use a string args and do *  the conversion yourself. * @Example * *     ARGPARSE_OPTS opts[] = { *     { 'v', "verbose",   0 }, *     { 'd', "debug",     0 }, *     { 'o', "output",    2 }, *     { 'c', "cross-ref", 2|8 }, *     { 'm', "my-option", 1|8 }, *     { 300, "ignored-long-option, ARGPARSE_OP_IGNORE}, *     { 500, "have-no-short-option-for-this-long-option", 0 }, *     {0} }; *     ARGPARSE_ARGS pargs = { &argc, &argv, 0 } * *     while( ArgParse( &pargs, &opts) ) { *	   switch( pargs.r_opt ) { *	     case 'v': opt.verbose++; break; *	     case 'd': opt.debug++; break; *	     case 'o': opt.outfile = pargs.r.ret_str; break; *	     case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; *	     case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; *	     case 500: opt.a_long_one++;  break *	     default : pargs.err = 1; break; -- force warning output -- *	   } *     } *     if( argc > 1 ) *	   log_fatal( "Too many args"); * */ typedef struct alias_def_s *ALIAS_DEF;struct alias_def_s {    ALIAS_DEF next;    char *name;   /* malloced buffer with name, \0, value */    const char *value; /* ptr into name */};  /* Object to store the names for the --ignore-invalid-option option.   This is a simple linked list.  */typedef struct iio_item_def_s *IIO_ITEM_DEF;struct iio_item_def_s{  IIO_ITEM_DEF next;  char name[1];      /* String with the long option name.  */}; static const char *(*strusage_handler)( int ) = NULL;static int (*custom_outfnc) (int, const char *); static int  set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);static void show_help(ARGPARSE_OPTS *opts, unsigned flags);static void show_version(void);static int writestrings (int is_error, const char *string, ...)#if __GNUC__ >= 4  __attribute__ ((sentinel(0)))#endif  ;  voidargparse_register_outfnc (int (*fnc)(int, const char *)){  custom_outfnc = fnc;}  /* Write STRING and all following const char * arguments either to   stdout or, if IS_ERROR is set, to stderr.  The list of strings must   be terminated by a NULL.  */static intwritestrings (int is_error, const char *string, ...){  va_list arg_ptr;  const char *s;  int count = 0;   if (string)    {      s = string;      va_start (arg_ptr, string);      do        {          if (custom_outfnc)            custom_outfnc (is_error? 2:1, s);          else            fputs (s, is_error? stderr : stdout);          count += strlen (s);        }      while ((s = va_arg (arg_ptr, const char *)));      va_end (arg_ptr);    }  return count;}  static voidflushstrings (int is_error){  if (custom_outfnc)    custom_outfnc (is_error? 2:1, NULL);  else    fflush (is_error? stderr : stdout);}  static voidinitialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno ){  if( !(arg->flags & (1<<15)) )    {      /* Initialize this instance. */      arg->internal.idx = 0;      arg->internal.last = NULL;      arg->internal.inarg = 0;      arg->internal.stopped = 0;      arg->internal.aliases = NULL;      arg->internal.cur_alias = NULL;      arg->internal.iio_list = NULL;      arg->err = 0;      arg->flags |= 1<<15; /* Mark as initialized.  */      if ( *arg->argc < 0 )        jnlib_log_bug ("invalid argument for arg_parse\n");    }    if (arg->err)    {      /* Last option was erroneous.  */      const char *s;       if (filename)        {          if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )            s = _("argument not expected");          else if ( arg->r_opt == ARGPARSE_READ_ERROR )            s = _("read error");          else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG )            s = _("keyword too long");          else if ( arg->r_opt == ARGPARSE_MISSING_ARG )            s = _("missing argument");          else if ( arg->r_opt == ARGPARSE_INVALID_ARG )            s = _("invalid argument");          else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )            s = _("invalid command");          else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS )            s = _("invalid alias definition");          else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )            s = _("out of core");          else            s = _("invalid option");          jnlib_log_error ("%s:%u: %s\n", filename, *lineno, s);	}      else        {          s = arg->internal.last? arg->internal.last:"[??]";           if ( arg->r_opt == ARGPARSE_MISSING_ARG )            jnlib_log_error (_("missing argument for option \"%.50s\"\n"), s);          else if ( arg->r_opt == ARGPARSE_INVALID_ARG )            jnlib_log_error (_("invalid argument for option \"%.50s\"\n"), s);          else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )            jnlib_log_error (_("option \"%.50s\" does not expect an "                               "argument\n"), s );          else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )            jnlib_log_error (_("invalid command \"%.50s\"\n"), s);          else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )            jnlib_log_error (_("option \"%.50s\" is ambiguous\n"), s);          else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND )            jnlib_log_error (_("command \"%.50s\" is ambiguous\n"),s );          else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )            jnlib_log_error ("%s\n", _("out of core\n"));          else            jnlib_log_error (_("invalid option \"%.50s\"\n"), s);	}      if (arg->err != ARGPARSE_PRINT_WARNING)        exit (2);      arg->err = 0;    }   /* Zero out the return value union.  */  arg->r.ret_str = NULL;  arg->r.ret_long = 0;}  static voidstore_alias( ARGPARSE_ARGS *arg, char *name, char *value ){    /* TODO: replace this dummy function with a rea one     * and fix the probelms IRIX has with (ALIAS_DEV)arg..     * used as lvalue     */  (void)arg;  (void)name;  (void)value;#if 0    ALIAS_DEF a = jnlib_xmalloc( sizeof *a );    a->name = name;    a->value = value;    a->next = (ALIAS_DEF)arg->internal.aliases;    (ALIAS_DEF)arg->internal.aliases = a;#endif}  /* Return true if KEYWORD is in the ignore-invalid-option list.  */static intignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword){  IIO_ITEM_DEF item = arg->internal.iio_list;   for (; item; item = item->next)    if (!strcmp (item->name, keyword))      return 1;  return 0;}  /* Add the keywords up to the next LF to the list of to be ignored   options.  After returning FP will either be at EOF or the next   character read wll be the first of a new line.  The function   returns 0 on success or true on malloc failure.  */static intignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp){  IIO_ITEM_DEF item;  int c;  char name[100];  int namelen = 0;  int ready = 0;  enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS;   while (!ready)    {      c = getc (fp);      if (c == '\n')        ready = 1;      else if (c == EOF)        {          c = '\n';          ready = 1;        }    again:      switch (state)        {        case skipWS:          if (!isascii (c) || !isspace(c))            {              namelen = 0;              state = collectNAME;              goto again;            }          break;         case collectNAME:          if (isspace (c))            {              state = addNAME;              goto again;            }          else if (namelen < DIM(name)-1)            name[namelen++] = c;          else /* Too long.  */            state = skipNAME;          break;         case skipNAME:          if (isspace (c))            {              state = skipWS;              goto again;            }          break;         case addNAME:          name[namelen] = 0;

Lines 1–500 of 1607.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t