LCOV - code coverage report
Current view: top level - common - argparse.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 350 617 56.7 %
Date: 2016-09-12 12:29:17 Functions: 14 18 77.8 %

          Line data    Source code
       1             : /* [argparse.c wk 17.06.97] Argument Parser for option handling
       2             :  * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
       3             :  * Copyright (C) 1997-2001, 2006-2008, 2013-2016 Werner Koch
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * GnuPG is free software; you can redistribute it and/or modify it
       8             :  * under the terms of either
       9             :  *
      10             :  *   - the GNU Lesser General Public License as published by the Free
      11             :  *     Software Foundation; either version 3 of the License, or (at
      12             :  *     your option) any later version.
      13             :  *
      14             :  * or
      15             :  *
      16             :  *   - the GNU General Public License as published by the Free
      17             :  *     Software Foundation; either version 2 of the License, or (at
      18             :  *     your option) any later version.
      19             :  *
      20             :  * or both in parallel, as here.
      21             :  *
      22             :  * GnuPG is distributed in the hope that it will be useful, but
      23             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      24             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      25             :  * General Public License for more details.
      26             :  *
      27             :  * You should have received a copies of the GNU General Public License
      28             :  * and the GNU Lesser General Public License along with this program;
      29             :  * if not, see <https://gnu.org/licenses/>.
      30             :  */
      31             : 
      32             : /* This file may be used as part of GnuPG or standalone.  A GnuPG
      33             :    build is detected by the presence of the macro GNUPG_MAJOR_VERSION.
      34             :    Some feature are only availalbe in the GnuPG build mode.
      35             :  */
      36             : 
      37             : #ifdef HAVE_CONFIG_H
      38             : #include <config.h>
      39             : #endif
      40             : 
      41             : #include <stdio.h>
      42             : #include <stdlib.h>
      43             : #include <ctype.h>
      44             : #include <string.h>
      45             : #include <stdarg.h>
      46             : #include <limits.h>
      47             : #include <errno.h>
      48             : 
      49             : #ifdef GNUPG_MAJOR_VERSION
      50             : # include "util.h"
      51             : # include "common-defs.h"
      52             : # include "i18n.h"
      53             : # include "mischelp.h"
      54             : # include "stringhelp.h"
      55             : # include "logging.h"
      56             : # include "utf8conv.h"
      57             : #endif /*GNUPG_MAJOR_VERSION*/
      58             : 
      59             : #include "argparse.h"
      60             : 
      61             : /* GnuPG uses GPLv3+ but a standalone version of this defaults to
      62             :    GPLv2+ because that is the license of this file.  Change this if
      63             :    you include it in a program which uses GPLv3.  If you don't want to
      64             :    set a a copyright string for your usage() you may also hardcode it
      65             :    here.  */
      66             : #ifndef GNUPG_MAJOR_VERSION
      67             : 
      68             : # define ARGPARSE_GPL_VERSION      2
      69             : # define ARGPARSE_CRIGHT_STR "Copyright (C) YEAR NAME"
      70             : 
      71             : #else /* Used by GnuPG  */
      72             : 
      73             : # define ARGPARSE_GPL_VERSION      3
      74             : # define ARGPARSE_CRIGHT_STR "Copyright (C) 2016 Free Software Foundation, Inc."
      75             : 
      76             : #endif /*GNUPG_MAJOR_VERSION*/
      77             : 
      78             : /* Replacements for standalone builds.  */
      79             : #ifndef GNUPG_MAJOR_VERSION
      80             : # ifndef _
      81             : #  define _(a)  (a)
      82             : # endif
      83             : # ifndef DIM
      84             : #  define DIM(v)           (sizeof(v)/sizeof((v)[0]))
      85             : # endif
      86             : # define xtrymalloc(a)    malloc ((a))
      87             : # define xtryrealloc(a,b) realloc ((a), (b))
      88             : # define xtrystrdup(a)    strdup ((a))
      89             : # define xfree(a)         free ((a))
      90             : # define log_error        my_log_error
      91             : # define log_bug          my_log_bug
      92             : # define trim_spaces(a)   my_trim_spaces ((a))
      93             : # define map_static_macro_string(a)  (a)
      94             : #endif /*!GNUPG_MAJOR_VERSION*/
      95             : 
      96             : 
      97             : #define ARGPARSE_STR(v) #v
      98             : #define ARGPARSE_STR2(v) ARGPARSE_STR(v)
      99             : 
     100             : 
     101             : /* Replacements for standalone builds.  */
     102             : #ifndef GNUPG_MAJOR_VERSION
     103             : static void
     104             : my_log_error (const char *fmt, ...)
     105             : {
     106             :   va_list arg_ptr ;
     107             : 
     108             :   va_start (arg_ptr, fmt);
     109             :   fprintf (stderr, "%s: ", strusage (11));
     110             :   vfprintf (stderr, fmt, arg_ptr);
     111             :   va_end (arg_ptr);
     112             : }
     113             : 
     114             : static void
     115             : my_log_bug (const char *fmt, ...)
     116             : {
     117             :   va_list arg_ptr ;
     118             : 
     119             :   va_start (arg_ptr, fmt);
     120             :   fprintf (stderr, "%s: Ohhhh jeeee: ", strusage (11));
     121             :   vfprintf (stderr, fmt, arg_ptr);
     122             :   va_end (arg_ptr);
     123             :   abort ();
     124             : }
     125             : 
     126             : /* Return true if the native charset is utf-8.  */
     127             : static int
     128             : is_native_utf8 (void)
     129             : {
     130             :   return 1;
     131             : }
     132             : 
     133             : static char *
     134             : my_trim_spaces (char *str)
     135             : {
     136             :   char *string, *p, *mark;
     137             : 
     138             :   string = str;
     139             :   /* Find first non space character. */
     140             :   for (p=string; *p && isspace (*(unsigned char*)p) ; p++)
     141             :     ;
     142             :   /* Move characters. */
     143             :   for ((mark = NULL); (*string = *p); string++, p++)
     144             :     if (isspace (*(unsigned char*)p))
     145             :       {
     146             :         if (!mark)
     147             :           mark = string;
     148             :       }
     149             :     else
     150             :       mark = NULL;
     151             :   if (mark)
     152             :     *mark = '\0' ;  /* Remove trailing spaces. */
     153             : 
     154             :   return str ;
     155             : }
     156             : 
     157             : #endif /*!GNUPG_MAJOR_VERSION*/
     158             : 
     159             : 
     160             : 
     161             : /*********************************
     162             :  * @Summary arg_parse
     163             :  *  #include "argparse.h"
     164             :  *
     165             :  *  typedef struct {
     166             :  *      char *argc;               pointer to argc (value subject to change)
     167             :  *      char ***argv;             pointer to argv (value subject to change)
     168             :  *      unsigned flags;           Global flags (DO NOT CHANGE)
     169             :  *      int err;                  print error about last option
     170             :  *                                1 = warning, 2 = abort
     171             :  *      int r_opt;                return option
     172             :  *      int r_type;               type of return value (0 = no argument found)
     173             :  *      union {
     174             :  *          int   ret_int;
     175             :  *          long  ret_long
     176             :  *          ulong ret_ulong;
     177             :  *          char *ret_str;
     178             :  *      } r;                      Return values
     179             :  *      struct {
     180             :  *          int idx;
     181             :  *          const char *last;
     182             :  *          void *aliases;
     183             :  *      } internal;               DO NOT CHANGE
     184             :  *  } ARGPARSE_ARGS;
     185             :  *
     186             :  *  typedef struct {
     187             :  *      int         short_opt;
     188             :  *      const char *long_opt;
     189             :  *      unsigned flags;
     190             :  *  } ARGPARSE_OPTS;
     191             :  *
     192             :  *  int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
     193             :  *
     194             :  * @Description
     195             :  *  This is my replacement for getopt(). See the example for a typical usage.
     196             :  *  Global flags are:
     197             :  *     Bit 0 : Do not remove options form argv
     198             :  *     Bit 1 : Do not stop at last option but return other args
     199             :  *             with r_opt set to -1.
     200             :  *     Bit 2 : Assume options and real args are mixed.
     201             :  *     Bit 3 : Do not use -- to stop option processing.
     202             :  *     Bit 4 : Do not skip the first arg.
     203             :  *     Bit 5 : allow usage of long option with only one dash
     204             :  *     Bit 6 : ignore --version
     205             :  *     all other bits must be set to zero, this value is modified by the
     206             :  *     function, so assume this is write only.
     207             :  *  Local flags (for each option):
     208             :  *     Bit 2-0 : 0 = does not take an argument
     209             :  *               1 = takes int argument
     210             :  *               2 = takes string argument
     211             :  *               3 = takes long argument
     212             :  *               4 = takes ulong argument
     213             :  *     Bit 3 : argument is optional (r_type will the be set to 0)
     214             :  *     Bit 4 : allow 0x etc. prefixed values.
     215             :  *     Bit 6 : Ignore this option
     216             :  *     Bit 7 : This is a command and not an option
     217             :  *  You stop the option processing by setting opts to NULL, the function will
     218             :  *  then return 0.
     219             :  * @Return Value
     220             :  *   Returns the args.r_opt or 0 if ready
     221             :  *   r_opt may be -2/-7 to indicate an unknown option/command.
     222             :  * @See Also
     223             :  *   ArgExpand
     224             :  * @Notes
     225             :  *  You do not need to process the options 'h', '--help' or '--version'
     226             :  *  because this function includes standard help processing; but if you
     227             :  *  specify '-h', '--help' or '--version' you have to do it yourself.
     228             :  *  The option '--' stops argument processing; if bit 1 is set the function
     229             :  *  continues to return normal arguments.
     230             :  *  To process float args or unsigned args you must use a string args and do
     231             :  *  the conversion yourself.
     232             :  * @Example
     233             :  *
     234             :  *     ARGPARSE_OPTS opts[] = {
     235             :  *     { 'v', "verbose",   0 },
     236             :  *     { 'd', "debug",     0 },
     237             :  *     { 'o', "output",    2 },
     238             :  *     { 'c', "cross-ref", 2|8 },
     239             :  *     { 'm', "my-option", 1|8 },
     240             :  *     { 300, "ignored-long-option, ARGPARSE_OP_IGNORE},
     241             :  *     { 500, "have-no-short-option-for-this-long-option", 0 },
     242             :  *     {0} };
     243             :  *     ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
     244             :  *
     245             :  *     while( ArgParse( &pargs, &opts) ) {
     246             :  *         switch( pargs.r_opt ) {
     247             :  *           case 'v': opt.verbose++; break;
     248             :  *           case 'd': opt.debug++; break;
     249             :  *           case 'o': opt.outfile = pargs.r.ret_str; break;
     250             :  *           case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
     251             :  *           case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
     252             :  *           case 500: opt.a_long_one++;  break
     253             :  *           default : pargs.err = 1; break; -- force warning output --
     254             :  *         }
     255             :  *     }
     256             :  *     if( argc > 1 )
     257             :  *         log_fatal( "Too many args");
     258             :  *
     259             :  */
     260             : 
     261             : typedef struct alias_def_s *ALIAS_DEF;
     262             : struct alias_def_s {
     263             :     ALIAS_DEF next;
     264             :     char *name;   /* malloced buffer with name, \0, value */
     265             :     const char *value; /* ptr into name */
     266             : };
     267             : 
     268             : 
     269             : /* Object to store the names for the --ignore-invalid-option option.
     270             :    This is a simple linked list.  */
     271             : typedef struct iio_item_def_s *IIO_ITEM_DEF;
     272             : struct iio_item_def_s
     273             : {
     274             :   IIO_ITEM_DEF next;
     275             :   char name[1];      /* String with the long option name.  */
     276             : };
     277             : 
     278             : static const char *(*strusage_handler)( int ) = NULL;
     279             : static int (*custom_outfnc) (int, const char *);
     280             : 
     281             : static int  set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
     282             : static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
     283             : static void show_version(void);
     284             : static int writestrings (int is_error, const char *string, ...)
     285             : #if __GNUC__ >= 4
     286             :   __attribute__ ((sentinel(0)))
     287             : #endif
     288             :   ;
     289             : 
     290             : 
     291             : void
     292        2340 : argparse_register_outfnc (int (*fnc)(int, const char *))
     293             : {
     294        2340 :   custom_outfnc = fnc;
     295        2340 : }
     296             : 
     297             : 
     298             : /* Write STRING and all following const char * arguments either to
     299             :    stdout or, if IS_ERROR is set, to stderr.  The list of strings must
     300             :    be terminated by a NULL.  */
     301             : static int
     302       47413 : writestrings (int is_error, const char *string, ...)
     303             : {
     304             :   va_list arg_ptr;
     305             :   const char *s;
     306       47413 :   int count = 0;
     307             : 
     308       47413 :   if (string)
     309             :     {
     310       47413 :       s = string;
     311       47413 :       va_start (arg_ptr, string);
     312             :       do
     313             :         {
     314      136654 :           if (custom_outfnc)
     315      136654 :             custom_outfnc (is_error? 2:1, s);
     316             :           else
     317           0 :             fputs (s, is_error? stderr : stdout);
     318      136654 :           count += strlen (s);
     319             :         }
     320      136654 :       while ((s = va_arg (arg_ptr, const char *)));
     321       47413 :       va_end (arg_ptr);
     322             :     }
     323       47413 :   return count;
     324             : }
     325             : 
     326             : 
     327             : static void
     328           9 : flushstrings (int is_error)
     329             : {
     330           9 :   if (custom_outfnc)
     331           9 :     custom_outfnc (is_error? 2:1, NULL);
     332             :   else
     333           0 :     fflush (is_error? stderr : stdout);
     334           9 : }
     335             : 
     336             : 
     337             : static void
     338       37828 : initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
     339             : {
     340       37828 :   if( !(arg->flags & (1<<15)) )
     341             :     {
     342             :       /* Initialize this instance. */
     343        4101 :       arg->internal.idx = 0;
     344        4101 :       arg->internal.last = NULL;
     345        4101 :       arg->internal.inarg = 0;
     346        4101 :       arg->internal.stopped = 0;
     347        4101 :       arg->internal.aliases = NULL;
     348        4101 :       arg->internal.cur_alias = NULL;
     349        4101 :       arg->internal.iio_list = NULL;
     350        4101 :       arg->err = 0;
     351        4101 :       arg->flags |= 1<<15; /* Mark as initialized.  */
     352        4101 :       if ( *arg->argc < 0 )
     353           0 :         log_bug ("invalid argument for arg_parse\n");
     354             :     }
     355             : 
     356             : 
     357       37828 :   if (arg->err)
     358             :     {
     359             :       /* Last option was erroneous.  */
     360             :       const char *s;
     361             : 
     362           0 :       if (filename)
     363             :         {
     364           0 :           if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
     365           0 :             s = _("argument not expected");
     366           0 :           else if ( arg->r_opt == ARGPARSE_READ_ERROR )
     367           0 :             s = _("read error");
     368           0 :           else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG )
     369           0 :             s = _("keyword too long");
     370           0 :           else if ( arg->r_opt == ARGPARSE_MISSING_ARG )
     371           0 :             s = _("missing argument");
     372           0 :           else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
     373           0 :             s = _("invalid argument");
     374           0 :           else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
     375           0 :             s = _("invalid command");
     376           0 :           else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS )
     377           0 :             s = _("invalid alias definition");
     378           0 :           else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
     379           0 :             s = _("out of core");
     380             :           else
     381           0 :             s = _("invalid option");
     382           0 :           log_error ("%s:%u: %s\n", filename, *lineno, s);
     383             :         }
     384             :       else
     385             :         {
     386           0 :           s = arg->internal.last? arg->internal.last:"[??]";
     387             : 
     388           0 :           if ( arg->r_opt == ARGPARSE_MISSING_ARG )
     389           0 :             log_error (_("missing argument for option \"%.50s\"\n"), s);
     390           0 :           else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
     391           0 :             log_error (_("invalid argument for option \"%.50s\"\n"), s);
     392           0 :           else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
     393           0 :             log_error (_("option \"%.50s\" does not expect an argument\n"), s);
     394           0 :           else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
     395           0 :             log_error (_("invalid command \"%.50s\"\n"), s);
     396           0 :           else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )
     397           0 :             log_error (_("option \"%.50s\" is ambiguous\n"), s);
     398           0 :           else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND )
     399           0 :             log_error (_("command \"%.50s\" is ambiguous\n"),s );
     400           0 :           else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
     401           0 :             log_error ("%s\n", _("out of core\n"));
     402             :           else
     403           0 :             log_error (_("invalid option \"%.50s\"\n"), s);
     404             :         }
     405           0 :       if (arg->err != ARGPARSE_PRINT_WARNING)
     406           0 :         exit (2);
     407           0 :       arg->err = 0;
     408             :     }
     409             : 
     410             :   /* Zero out the return value union.  */
     411       37828 :   arg->r.ret_str = NULL;
     412       37828 :   arg->r.ret_long = 0;
     413       37828 : }
     414             : 
     415             : 
     416             : static void
     417           0 : store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
     418             : {
     419             :     /* TODO: replace this dummy function with a rea one
     420             :      * and fix the probelms IRIX has with (ALIAS_DEV)arg..
     421             :      * used as lvalue
     422             :      */
     423             :   (void)arg;
     424             :   (void)name;
     425             :   (void)value;
     426             : #if 0
     427             :     ALIAS_DEF a = xmalloc( sizeof *a );
     428             :     a->name = name;
     429             :     a->value = value;
     430             :     a->next = (ALIAS_DEF)arg->internal.aliases;
     431             :     (ALIAS_DEF)arg->internal.aliases = a;
     432             : #endif
     433           0 : }
     434             : 
     435             : 
     436             : /* Return true if KEYWORD is in the ignore-invalid-option list.  */
     437             : static int
     438           0 : ignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword)
     439             : {
     440           0 :   IIO_ITEM_DEF item = arg->internal.iio_list;
     441             : 
     442           0 :   for (; item; item = item->next)
     443           0 :     if (!strcmp (item->name, keyword))
     444           0 :       return 1;
     445           0 :   return 0;
     446             : }
     447             : 
     448             : 
     449             : /* Add the keywords up to the next LF to the list of to be ignored
     450             :    options.  After returning FP will either be at EOF or the next
     451             :    character read wll be the first of a new line.  The function
     452             :    returns 0 on success or true on malloc failure.  */
     453             : static int
     454           0 : ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp)
     455             : {
     456             :   IIO_ITEM_DEF item;
     457             :   int c;
     458             :   char name[100];
     459           0 :   int namelen = 0;
     460           0 :   int ready = 0;
     461           0 :   enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS;
     462             : 
     463           0 :   while (!ready)
     464             :     {
     465           0 :       c = getc (fp);
     466           0 :       if (c == '\n')
     467           0 :         ready = 1;
     468           0 :       else if (c == EOF)
     469             :         {
     470           0 :           c = '\n';
     471           0 :           ready = 1;
     472             :         }
     473             :     again:
     474           0 :       switch (state)
     475             :         {
     476             :         case skipWS:
     477           0 :           if (!isascii (c) || !isspace(c))
     478             :             {
     479           0 :               namelen = 0;
     480           0 :               state = collectNAME;
     481           0 :               goto again;
     482             :             }
     483           0 :           break;
     484             : 
     485             :         case collectNAME:
     486           0 :           if (isspace (c))
     487             :             {
     488           0 :               state = addNAME;
     489           0 :               goto again;
     490             :             }
     491           0 :           else if (namelen < DIM(name)-1)
     492           0 :             name[namelen++] = c;
     493             :           else /* Too long.  */
     494           0 :             state = skipNAME;
     495           0 :           break;
     496             : 
     497             :         case skipNAME:
     498           0 :           if (isspace (c))
     499             :             {
     500           0 :               state = skipWS;
     501           0 :               goto again;
     502             :             }
     503           0 :           break;
     504             : 
     505             :         case addNAME:
     506           0 :           name[namelen] = 0;
     507           0 :           if (!ignore_invalid_option_p (arg, name))
     508             :             {
     509           0 :               item = xtrymalloc (sizeof *item + namelen);
     510           0 :               if (!item)
     511           0 :                 return 1;
     512           0 :               strcpy (item->name, name);
     513           0 :               item->next = (IIO_ITEM_DEF)arg->internal.iio_list;
     514           0 :               arg->internal.iio_list = item;
     515             :             }
     516           0 :           state = skipWS;
     517           0 :           goto again;
     518             :         }
     519             :     }
     520           0 :   return 0;
     521             : }
     522             : 
     523             : 
     524             : /* Clear the entire ignore-invalid-option list.  */
     525             : static void
     526        1732 : ignore_invalid_option_clear (ARGPARSE_ARGS *arg)
     527             : {
     528             :   IIO_ITEM_DEF item, tmpitem;
     529             : 
     530        1732 :   for (item = arg->internal.iio_list; item; item = tmpitem)
     531             :     {
     532           0 :       tmpitem = item->next;
     533           0 :       xfree (item);
     534             :     }
     535        1732 :   arg->internal.iio_list = NULL;
     536        1732 : }
     537             : 
     538             : 
     539             : 
     540             : /****************
     541             :  * Get options from a file.
     542             :  * Lines starting with '#' are comment lines.
     543             :  * Syntax is simply a keyword and the argument.
     544             :  * Valid keywords are all keywords from the long_opt list without
     545             :  * the leading dashes. The special keywords "help", "warranty" and "version"
     546             :  * are not valid here.
     547             :  * The special keyword "alias" may be used to store alias definitions,
     548             :  * which are later expanded like long options.
     549             :  * The option
     550             :  *   ignore-invalid-option OPTIONNAMEs
     551             :  * is recognized and updates a list of option which should be ignored if they
     552             :  * are not defined.
     553             :  * Caller must free returned strings.
     554             :  * If called with FP set to NULL command line args are parse instead.
     555             :  *
     556             :  * Q: Should we allow the syntax
     557             :  *     keyword = value
     558             :  *    and accept for boolean options a value of 1/0, yes/no or true/false?
     559             :  * Note: Abbreviation of options is here not allowed.
     560             :  */
     561             : int
     562       25959 : optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
     563             :                ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
     564             : {
     565             :   int state, i, c;
     566       25959 :   int idx=0;
     567             :   char keyword[100];
     568       25959 :   char *buffer = NULL;
     569       25959 :   size_t buflen = 0;
     570       25959 :   int in_alias=0;
     571             : 
     572       25959 :   if (!fp) /* Divert to to arg_parse() in this case.  */
     573       11869 :     return arg_parse (arg, opts);
     574             : 
     575       14090 :   initialize (arg, filename, lineno);
     576             : 
     577             :   /* Find the next keyword.  */
     578       14090 :   state = i = 0;
     579             :   for (;;)
     580             :     {
     581      605131 :       c = getc (fp);
     582      605131 :       if (c == '\n' || c== EOF )
     583             :         {
     584       23090 :           if ( c != EOF )
     585       21358 :             ++*lineno;
     586       23090 :           if (state == -1)
     587           0 :             break;
     588       23090 :           else if (state == 2)
     589             :             {
     590        8373 :               keyword[i] = 0;
     591     1796658 :               for (i=0; opts[i].short_opt; i++ )
     592             :                 {
     593     1796658 :                   if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
     594        8373 :                     break;
     595             :                 }
     596        8373 :               idx = i;
     597        8373 :               arg->r_opt = opts[idx].short_opt;
     598        8373 :               if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
     599             :                 {
     600           0 :                   state = i = 0;
     601           0 :                   continue;
     602             :                 }
     603        8373 :               else if (!opts[idx].short_opt )
     604             :                 {
     605           0 :                   if (!strcmp (keyword, "ignore-invalid-option"))
     606             :                     {
     607             :                       /* No argument - ignore this meta option.  */
     608           0 :                       state = i = 0;
     609           0 :                       continue;
     610             :                     }
     611           0 :                   else if (ignore_invalid_option_p (arg, keyword))
     612             :                     {
     613             :                       /* This invalid option is in the iio list.  */
     614           0 :                       state = i = 0;
     615           0 :                       continue;
     616             :                     }
     617           0 :                   arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
     618             :                                 ? ARGPARSE_INVALID_COMMAND
     619           0 :                                 : ARGPARSE_INVALID_OPTION);
     620             :                 }
     621        8373 :               else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
     622        8373 :                 arg->r_type = 0; /* Does not take an arg. */
     623           0 :               else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) )
     624           0 :                 arg->r_type = 0; /* Arg is optional.  */
     625             :               else
     626           0 :                 arg->r_opt = ARGPARSE_MISSING_ARG;
     627             : 
     628        8373 :               break;
     629             :             }
     630       14717 :           else if (state == 3)
     631             :             {
     632             :               /* No argument found.  */
     633           0 :               if (in_alias)
     634           0 :                 arg->r_opt = ARGPARSE_MISSING_ARG;
     635           0 :               else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
     636           0 :                 arg->r_type = 0; /* Does not take an arg. */
     637           0 :               else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
     638           0 :                 arg->r_type = 0; /* No optional argument. */
     639             :               else
     640           0 :                 arg->r_opt = ARGPARSE_MISSING_ARG;
     641             : 
     642           0 :               break;
     643             :             }
     644       14717 :           else if (state == 4)
     645             :             {
     646             :               /* Has an argument. */
     647        3985 :               if (in_alias)
     648             :                 {
     649           0 :                   if (!buffer)
     650           0 :                     arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
     651             :                   else
     652             :                     {
     653             :                       char *p;
     654             : 
     655           0 :                       buffer[i] = 0;
     656           0 :                       p = strpbrk (buffer, " \t");
     657           0 :                       if (p)
     658             :                         {
     659           0 :                           *p++ = 0;
     660           0 :                           trim_spaces (p);
     661             :                         }
     662           0 :                       if (!p || !*p)
     663             :                         {
     664           0 :                           xfree (buffer);
     665           0 :                           arg->r_opt = ARGPARSE_INVALID_ALIAS;
     666             :                         }
     667             :                       else
     668             :                         {
     669           0 :                           store_alias (arg, buffer, p);
     670             :                         }
     671             :                     }
     672             :                 }
     673        3985 :               else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
     674           0 :                 arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
     675             :               else
     676             :                 {
     677             :                   char *p;
     678             : 
     679        3985 :                   if (!buffer)
     680             :                     {
     681        3985 :                       keyword[i] = 0;
     682        3985 :                       buffer = xtrystrdup (keyword);
     683        3985 :                       if (!buffer)
     684           0 :                         arg->r_opt = ARGPARSE_OUT_OF_CORE;
     685             :                     }
     686             :                   else
     687           0 :                     buffer[i] = 0;
     688             : 
     689        3985 :                   if (buffer)
     690             :                     {
     691        3985 :                       trim_spaces (buffer);
     692        3985 :                       p = buffer;
     693        3985 :                       if (*p == '"')
     694             :                         {
     695             :                           /* Remove quotes. */
     696           0 :                           p++;
     697           0 :                           if (*p && p[strlen(p)-1] == '\"' )
     698           0 :                             p[strlen(p)-1] = 0;
     699             :                         }
     700        3985 :                       if (!set_opt_arg (arg, opts[idx].flags, p))
     701           0 :                         xfree (buffer);
     702             :                       else
     703        3985 :                         gpgrt_annotate_leaked_object (buffer);
     704             :                     }
     705             :                 }
     706        3985 :               break;
     707             :             }
     708       10732 :           else if (c == EOF)
     709             :             {
     710        1732 :               ignore_invalid_option_clear (arg);
     711        1732 :               if (ferror (fp))
     712           0 :                 arg->r_opt = ARGPARSE_READ_ERROR;
     713             :               else
     714        1732 :                 arg->r_opt = 0; /* EOF. */
     715        1732 :               break;
     716             :             }
     717        9000 :           state = 0;
     718        9000 :           i = 0;
     719             :         }
     720      582041 :       else if (state == -1)
     721             :         ; /* Skip. */
     722      582041 :       else if (state == 0 && isascii (c) && isspace(c))
     723             :         ; /* Skip leading white space.  */
     724      582041 :       else if (state == 0 && c == '#' )
     725        7125 :         state = 1;      /* Start of a comment.  */
     726      574916 :       else if (state == 1)
     727             :         ; /* Skip comments. */
     728      369791 :       else if (state == 2 && isascii (c) && isspace(c))
     729             :         {
     730             :           /* Check keyword.  */
     731        3985 :           keyword[i] = 0;
     732      948774 :           for (i=0; opts[i].short_opt; i++ )
     733      948774 :             if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
     734        3985 :               break;
     735        3985 :           idx = i;
     736        3985 :           arg->r_opt = opts[idx].short_opt;
     737        7970 :           if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
     738             :             {
     739           0 :               state = 1; /* Process like a comment.  */
     740             :             }
     741        3985 :           else if (!opts[idx].short_opt)
     742             :             {
     743           0 :               if (!strcmp (keyword, "alias"))
     744             :                 {
     745           0 :                   in_alias = 1;
     746           0 :                   state = 3;
     747             :                 }
     748           0 :               else if (!strcmp (keyword, "ignore-invalid-option"))
     749             :                 {
     750           0 :                   if (ignore_invalid_option_add (arg, fp))
     751             :                     {
     752           0 :                       arg->r_opt = ARGPARSE_OUT_OF_CORE;
     753           0 :                       break;
     754             :                     }
     755           0 :                   state = i = 0;
     756           0 :                   ++*lineno;
     757             :                 }
     758           0 :               else if (ignore_invalid_option_p (arg, keyword))
     759           0 :                 state = 1; /* Process like a comment.  */
     760             :               else
     761             :                 {
     762           0 :                   arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
     763             :                                 ? ARGPARSE_INVALID_COMMAND
     764           0 :                                 : ARGPARSE_INVALID_OPTION);
     765           0 :                   state = -1; /* Skip rest of line and leave.  */
     766             :                 }
     767             :             }
     768             :           else
     769        3985 :             state = 3;
     770             :         }
     771      365806 :       else if (state == 3)
     772             :         {
     773             :           /* Skip leading spaces of the argument.  */
     774        4360 :           if (!isascii (c) || !isspace(c))
     775             :             {
     776        3985 :               i = 0;
     777        3985 :               keyword[i++] = c;
     778        3985 :               state = 4;
     779             :             }
     780             :         }
     781      361446 :       else if (state == 4)
     782             :         {
     783             :           /* Collect the argument. */
     784      185275 :           if (buffer)
     785             :             {
     786           0 :               if (i < buflen-1)
     787           0 :                 buffer[i++] = c;
     788             :               else
     789             :                 {
     790             :                   char *tmp;
     791           0 :                   size_t tmplen = buflen + 50;
     792             : 
     793           0 :                   tmp = xtryrealloc (buffer, tmplen);
     794           0 :                   if (tmp)
     795             :                     {
     796           0 :                       buflen = tmplen;
     797           0 :                       buffer = tmp;
     798           0 :                       buffer[i++] = c;
     799             :                     }
     800             :                   else
     801             :                     {
     802           0 :                       xfree (buffer);
     803           0 :                       arg->r_opt = ARGPARSE_OUT_OF_CORE;
     804           0 :                       break;
     805             :                     }
     806             :                 }
     807             :             }
     808      185275 :           else if (i < DIM(keyword)-1)
     809      185275 :             keyword[i++] = c;
     810             :           else
     811             :             {
     812           0 :               size_t tmplen = DIM(keyword) + 50;
     813           0 :               buffer = xtrymalloc (tmplen);
     814           0 :               if (buffer)
     815             :                 {
     816           0 :                   buflen = tmplen;
     817           0 :                   memcpy(buffer, keyword, i);
     818           0 :                   buffer[i++] = c;
     819             :                 }
     820             :               else
     821             :                 {
     822           0 :                   arg->r_opt = ARGPARSE_OUT_OF_CORE;
     823           0 :                   break;
     824             :                 }
     825             :             }
     826             :         }
     827      176171 :       else if (i >= DIM(keyword)-1)
     828             :         {
     829           0 :           arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
     830           0 :           state = -1; /* Skip rest of line and leave.  */
     831             :         }
     832             :       else
     833             :         {
     834      176171 :           keyword[i++] = c;
     835      176171 :           state = 2;
     836             :         }
     837      591041 :     }
     838             : 
     839       14090 :   return arg->r_opt;
     840             : }
     841             : 
     842             : 
     843             : 
     844             : static int
     845       18930 : find_long_option( ARGPARSE_ARGS *arg,
     846             :                   ARGPARSE_OPTS *opts, const char *keyword )
     847             : {
     848             :     int i;
     849             :     size_t n;
     850             : 
     851             :     (void)arg;
     852             : 
     853             :     /* Would be better if we can do a binary search, but it is not
     854             :        possible to reorder our option table because we would mess
     855             :        up our help strings - What we can do is: Build a nice option
     856             :        lookup table when this function is first invoked */
     857       18930 :     if( !*keyword )
     858           0 :         return -1;
     859     2960437 :     for(i=0; opts[i].short_opt; i++ )
     860     2960289 :         if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
     861       18782 :             return i;
     862             : #if 0
     863             :     {
     864             :         ALIAS_DEF a;
     865             :         /* see whether it is an alias */
     866             :         for( a = args->internal.aliases; a; a = a->next ) {
     867             :             if( !strcmp( a->name, keyword) ) {
     868             :                 /* todo: must parse the alias here */
     869             :                 args->internal.cur_alias = a;
     870             :                 return -3; /* alias available */
     871             :             }
     872             :         }
     873             :     }
     874             : #endif
     875             :     /* not found, see whether it is an abbreviation */
     876             :     /* aliases may not be abbreviated */
     877         148 :     n = strlen( keyword );
     878       46986 :     for(i=0; opts[i].short_opt; i++ ) {
     879       46856 :         if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) {
     880             :             int j;
     881        5826 :             for(j=i+1; opts[j].short_opt; j++ ) {
     882        5808 :                 if( opts[j].long_opt
     883        5724 :                     && !strncmp( opts[j].long_opt, keyword, n ) )
     884           0 :                     return -2;  /* abbreviation is ambiguous */
     885             :             }
     886          18 :             return i;
     887             :         }
     888             :     }
     889         130 :     return -1;  /* Not found.  */
     890             : }
     891             : 
     892             : int
     893       23738 : arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
     894             : {
     895             :   int idx;
     896             :   int argc;
     897             :   char **argv;
     898             :   char *s, *s2;
     899             :   int i;
     900             : 
     901       23738 :   initialize( arg, NULL, NULL );
     902       23738 :   argc = *arg->argc;
     903       23738 :   argv = *arg->argv;
     904       23738 :   idx = arg->internal.idx;
     905             : 
     906       23738 :   if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
     907             :     {
     908             :       /* Skip the first argument.  */
     909        4093 :       argc--; argv++; idx++;
     910             :     }
     911             : 
     912             :  next_one:
     913       27443 :   if (!argc)
     914             :     {
     915             :       /* No more args.  */
     916         267 :       arg->r_opt = 0;
     917         267 :       goto leave; /* Ready. */
     918             :     }
     919             : 
     920       27176 :   s = *argv;
     921       27176 :   arg->internal.last = s;
     922             : 
     923       27176 :   if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL))
     924             :     {
     925           0 :       arg->r_opt = ARGPARSE_IS_ARG;  /* Not an option but an argument.  */
     926           0 :       arg->r_type = 2;
     927           0 :       arg->r.ret_str = s;
     928           0 :       argc--; argv++; idx++; /* set to next one */
     929             :     }
     930       27176 :   else if( arg->internal.stopped )
     931             :     {
     932        3705 :       arg->r_opt = 0;
     933        3705 :       goto leave; /* Ready.  */
     934             :     }
     935       23471 :   else if ( *s == '-' && s[1] == '-' )
     936       18801 :     {
     937             :       /* Long option.  */
     938             :       char *argpos;
     939             : 
     940       18930 :       arg->internal.inarg = 0;
     941       18930 :       if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
     942             :         {
     943             :           /* Stop option processing.  */
     944           0 :           arg->internal.stopped = 1;
     945           0 :           arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
     946           0 :           argc--; argv++; idx++;
     947           0 :           goto next_one;
     948             :         }
     949             : 
     950       18930 :       argpos = strchr( s+2, '=' );
     951       18930 :       if ( argpos )
     952        1267 :         *argpos = 0;
     953       18930 :       i = find_long_option ( arg, opts, s+2 );
     954       18930 :       if ( argpos )
     955        1267 :         *argpos = '=';
     956             : 
     957       18930 :       if ( i < 0 && !strcmp ( "help", s+2) )
     958           4 :         show_help (opts, arg->flags);
     959       18926 :       else if ( i < 0 && !strcmp ( "version", s+2) )
     960             :         {
     961           3 :           if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
     962             :             {
     963           1 :               show_version ();
     964           1 :               exit(0);
     965             :             }
     966             :         }
     967       18924 :       else if ( i < 0 && !strcmp( "warranty", s+2))
     968             :         {
     969           0 :           writestrings (0, strusage (16), "\n", NULL);
     970           0 :           exit (0);
     971             :         }
     972       18924 :       else if ( i < 0 && !strcmp( "dump-options", s+2) )
     973             :         {
     974       45384 :           for (i=0; opts[i].short_opt; i++ )
     975             :             {
     976       45260 :               if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
     977       44516 :                 writestrings (0, "--", opts[i].long_opt, "\n", NULL);
     978             :             }
     979         124 :           writestrings (0, "--dump-options\n--help\n--version\n--warranty\n",
     980             :                         NULL);
     981         124 :           exit (0);
     982             :         }
     983             : 
     984       18801 :       if ( i == -2 )
     985           0 :         arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
     986       18801 :       else if ( i == -1 )
     987             :         {
     988           1 :           arg->r_opt = ARGPARSE_INVALID_OPTION;
     989           1 :           arg->r.ret_str = s+2;
     990             :         }
     991             :       else
     992       18800 :         arg->r_opt = opts[i].short_opt;
     993       18801 :       if ( i < 0 )
     994             :         ;
     995       18800 :       else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
     996             :         {
     997        6302 :           if ( argpos )
     998             :             {
     999        1267 :               s2 = argpos+1;
    1000        1267 :               if ( !*s2 )
    1001           0 :                 s2 = NULL;
    1002             :             }
    1003             :           else
    1004        5035 :             s2 = argv[1];
    1005        6302 :           if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
    1006             :             {
    1007           0 :               arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional.  */
    1008             :             }
    1009        6302 :           else if ( !s2 )
    1010             :             {
    1011           0 :               arg->r_opt = ARGPARSE_MISSING_ARG;
    1012             :             }
    1013        6302 :           else if ( !argpos && *s2 == '-'
    1014         206 :                     && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
    1015             :             {
    1016             :               /* The argument is optional and the next seems to be an
    1017             :                  option.  We do not check this possible option but
    1018             :                  assume no argument */
    1019           0 :               arg->r_type = ARGPARSE_TYPE_NONE;
    1020             :             }
    1021             :           else
    1022             :             {
    1023        6302 :               set_opt_arg (arg, opts[i].flags, s2);
    1024        6302 :               if ( !argpos )
    1025             :                 {
    1026        5035 :                   argc--; argv++; idx++; /* Skip one.  */
    1027             :                 }
    1028             :             }
    1029             :         }
    1030             :       else
    1031             :         {
    1032             :           /* Does not take an argument. */
    1033       12498 :           if ( argpos )
    1034           0 :             arg->r_type = ARGPARSE_UNEXPECTED_ARG;
    1035             :           else
    1036       12498 :             arg->r_type = 0;
    1037             :         }
    1038       18801 :       argc--; argv++; idx++; /* Set to next one.  */
    1039             :     }
    1040        4541 :     else if ( (*s == '-' && s[1]) || arg->internal.inarg )
    1041         836 :       {
    1042             :         /* Short option.  */
    1043         836 :         int dash_kludge = 0;
    1044             : 
    1045         836 :         i = 0;
    1046         836 :         if ( !arg->internal.inarg )
    1047             :           {
    1048         654 :             arg->internal.inarg++;
    1049         654 :             if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
    1050             :               {
    1051           0 :                 for (i=0; opts[i].short_opt; i++ )
    1052           0 :                   if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1))
    1053             :                     {
    1054           0 :                       dash_kludge = 1;
    1055           0 :                       break;
    1056             :                     }
    1057             :               }
    1058             :           }
    1059         836 :         s += arg->internal.inarg;
    1060             : 
    1061         836 :         if (!dash_kludge )
    1062             :           {
    1063       14818 :             for (i=0; opts[i].short_opt; i++ )
    1064       14818 :               if ( opts[i].short_opt == *s )
    1065         836 :                 break;
    1066             :           }
    1067             : 
    1068         836 :         if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
    1069           0 :           show_help (opts, arg->flags);
    1070             : 
    1071         836 :         arg->r_opt = opts[i].short_opt;
    1072         836 :         if (!opts[i].short_opt )
    1073             :           {
    1074           0 :             arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
    1075           0 :               ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
    1076           0 :             arg->internal.inarg++; /* Point to the next arg.  */
    1077           0 :             arg->r.ret_str = s;
    1078             :           }
    1079         836 :         else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
    1080             :           {
    1081          50 :             if ( s[1] && !dash_kludge )
    1082             :               {
    1083           0 :                 s2 = s+1;
    1084           0 :                 set_opt_arg (arg, opts[i].flags, s2);
    1085             :               }
    1086             :             else
    1087             :               {
    1088          50 :                 s2 = argv[1];
    1089          50 :                 if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
    1090             :                   {
    1091           0 :                     arg->r_type = ARGPARSE_TYPE_NONE;
    1092             :                   }
    1093          50 :                 else if ( !s2 )
    1094             :                   {
    1095           0 :                     arg->r_opt = ARGPARSE_MISSING_ARG;
    1096             :                   }
    1097          50 :                 else if ( *s2 == '-' && s2[1]
    1098           0 :                           && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
    1099             :                   {
    1100             :                     /* The argument is optional and the next seems to
    1101             :                        be an option.  We do not check this possible
    1102             :                        option but assume no argument.  */
    1103           0 :                     arg->r_type = ARGPARSE_TYPE_NONE;
    1104             :                   }
    1105             :                 else
    1106             :                   {
    1107          50 :                     set_opt_arg (arg, opts[i].flags, s2);
    1108          50 :                     argc--; argv++; idx++; /* Skip one.  */
    1109             :                   }
    1110             :               }
    1111          50 :             s = "x"; /* This is so that !s[1] yields false.  */
    1112             :           }
    1113             :         else
    1114             :           {
    1115             :             /* Does not take an argument.  */
    1116         786 :             arg->r_type = ARGPARSE_TYPE_NONE;
    1117         786 :             arg->internal.inarg++; /* Point to the next arg.  */
    1118             :           }
    1119         836 :         if ( !s[1] || dash_kludge )
    1120             :           {
    1121             :             /* No more concatenated short options.  */
    1122         654 :             arg->internal.inarg = 0;
    1123         654 :             argc--; argv++; idx++;
    1124             :           }
    1125             :       }
    1126        3705 :   else if ( arg->flags & ARGPARSE_FLAG_MIXED )
    1127             :     {
    1128           0 :       arg->r_opt = ARGPARSE_IS_ARG;
    1129           0 :       arg->r_type = 2;
    1130           0 :       arg->r.ret_str = s;
    1131           0 :       argc--; argv++; idx++; /* Set to next one.  */
    1132             :     }
    1133             :   else
    1134             :     {
    1135        3705 :       arg->internal.stopped = 1; /* Stop option processing.  */
    1136        3705 :       goto next_one;
    1137             :     }
    1138             : 
    1139             :  leave:
    1140       23609 :   *arg->argc = argc;
    1141       23609 :   *arg->argv = argv;
    1142       23609 :   arg->internal.idx = idx;
    1143       23609 :   return arg->r_opt;
    1144             : }
    1145             : 
    1146             : 
    1147             : /* Returns: -1 on error, 0 for an integer type and 1 for a non integer
    1148             :    type argument.  */
    1149             : static int
    1150       10337 : set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s)
    1151             : {
    1152       10337 :   int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
    1153             :   long l;
    1154             : 
    1155       10337 :   switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
    1156             :     {
    1157             :     case ARGPARSE_TYPE_LONG:
    1158             :     case ARGPARSE_TYPE_INT:
    1159        1918 :       errno = 0;
    1160        1918 :       l = strtol (s, NULL, base);
    1161        1918 :       if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)
    1162             :         {
    1163           0 :           arg->r_opt = ARGPARSE_INVALID_ARG;
    1164           0 :           return -1;
    1165             :         }
    1166        1918 :       if (arg->r_type == ARGPARSE_TYPE_LONG)
    1167           0 :         arg->r.ret_long = l;
    1168        1918 :       else if ( (l < 0 && l < INT_MIN) || l > INT_MAX )
    1169             :         {
    1170           0 :           arg->r_opt = ARGPARSE_INVALID_ARG;
    1171           0 :           return -1;
    1172             :         }
    1173             :       else
    1174        1918 :         arg->r.ret_int = (int)l;
    1175        1918 :       return 0;
    1176             : 
    1177             :     case ARGPARSE_TYPE_ULONG:
    1178           0 :       while (isascii (*s) && isspace(*s))
    1179           0 :         s++;
    1180           0 :       if (*s == '-')
    1181             :         {
    1182           0 :           arg->r.ret_ulong = 0;
    1183           0 :           arg->r_opt = ARGPARSE_INVALID_ARG;
    1184           0 :           return -1;
    1185             :         }
    1186           0 :       errno = 0;
    1187           0 :       arg->r.ret_ulong = strtoul (s, NULL, base);
    1188           0 :       if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE)
    1189             :         {
    1190           0 :           arg->r_opt = ARGPARSE_INVALID_ARG;
    1191           0 :           return -1;
    1192             :         }
    1193           0 :       return 0;
    1194             : 
    1195             :     case ARGPARSE_TYPE_STRING:
    1196             :     default:
    1197        8419 :       arg->r.ret_str = s;
    1198        8419 :       return 1;
    1199             :     }
    1200             : }
    1201             : 
    1202             : 
    1203             : static size_t
    1204          68 : long_opt_strlen( ARGPARSE_OPTS *o )
    1205             : {
    1206          68 :   size_t n = strlen (o->long_opt);
    1207             : 
    1208          68 :   if ( o->description && *o->description == '|' )
    1209             :     {
    1210             :       const char *s;
    1211          20 :       int is_utf8 = is_native_utf8 ();
    1212             : 
    1213          20 :       s=o->description+1;
    1214          20 :       if ( *s != '=' )
    1215          20 :         n++;
    1216             :       /* For a (mostly) correct length calculation we exclude
    1217             :          continuation bytes (10xxxxxx) if we are on a native utf8
    1218             :          terminal. */
    1219         144 :       for (; *s && *s != '|'; s++ )
    1220         124 :         if ( is_utf8 && (*s&0xc0) != 0x80 )
    1221           0 :           n++;
    1222             :     }
    1223          68 :   return n;
    1224             : }
    1225             : 
    1226             : 
    1227             : /****************
    1228             :  * Print formatted help. The description string has some special
    1229             :  * meanings:
    1230             :  *  - A description string which is "@" suppresses help output for
    1231             :  *    this option
    1232             :  *  - a description,ine which starts with a '@' and is followed by
    1233             :  *    any other characters is printed as is; this may be used for examples
    1234             :  *    ans such.
    1235             :  *  - A description which starts with a '|' outputs the string between this
    1236             :  *    bar and the next one as arguments of the long option.
    1237             :  */
    1238             : static void
    1239           4 : show_help (ARGPARSE_OPTS *opts, unsigned int flags)
    1240             : {
    1241             :   const char *s;
    1242             :   char tmp[2];
    1243             : 
    1244           4 :   show_version ();
    1245           4 :   writestrings (0, "\n", NULL);
    1246           4 :   s = strusage (42);
    1247           4 :   if (s && *s == '1')
    1248             :     {
    1249           0 :       s = strusage (40);
    1250           0 :       writestrings (1, s, NULL);
    1251           0 :       if (*s && s[strlen(s)] != '\n')
    1252           0 :         writestrings (1, "\n", NULL);
    1253             :     }
    1254           4 :   s = strusage(41);
    1255           4 :   writestrings (0, s, "\n", NULL);
    1256           4 :   if ( opts[0].description )
    1257             :     {
    1258             :       /* Auto format the option description.  */
    1259             :       int i,j, indent;
    1260             : 
    1261             :       /* Get max. length of long options.  */
    1262         108 :       for (i=indent=0; opts[i].short_opt; i++ )
    1263             :         {
    1264         104 :           if ( opts[i].long_opt )
    1265          92 :             if ( !opts[i].description || *opts[i].description != '@' )
    1266          68 :               if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
    1267          12 :                 indent = j;
    1268             :         }
    1269             : 
    1270             :       /* Example: " -v, --verbose   Viele Sachen ausgeben" */
    1271           4 :       indent += 10;
    1272           4 :       if ( *opts[0].description != '@' )
    1273           0 :         writestrings (0, "Options:", "\n", NULL);
    1274         108 :       for (i=0; opts[i].short_opt; i++ )
    1275             :         {
    1276         104 :           s = map_static_macro_string (_( opts[i].description ));
    1277         104 :           if ( s && *s== '@' && !s[1] ) /* Hide this line.  */
    1278          24 :             continue;
    1279          80 :           if ( s && *s == '@' )  /* Unindented comment only line.  */
    1280             :             {
    1281         160 :               for (s++; *s; s++ )
    1282             :                 {
    1283         148 :                   if ( *s == '\n' )
    1284             :                     {
    1285          20 :                       if( s[1] )
    1286          20 :                         writestrings (0, "\n", NULL);
    1287             :                     }
    1288             :                   else
    1289             :                     {
    1290         128 :                       tmp[0] = *s;
    1291         128 :                       tmp[1] = 0;
    1292         128 :                       writestrings (0, tmp, NULL);
    1293             :                     }
    1294             :                 }
    1295          12 :               writestrings (0, "\n", NULL);
    1296          12 :               continue;
    1297             :             }
    1298             : 
    1299          68 :           j = 3;
    1300          68 :           if ( opts[i].short_opt < 256 )
    1301             :             {
    1302          48 :               tmp[0] = opts[i].short_opt;
    1303          48 :               tmp[1] = 0;
    1304          48 :               writestrings (0, " -", tmp, NULL );
    1305          48 :               if ( !opts[i].long_opt )
    1306             :                 {
    1307           0 :                   if (s && *s == '|' )
    1308             :                     {
    1309           0 :                       writestrings (0, " ", NULL); j++;
    1310           0 :                       for (s++ ; *s && *s != '|'; s++, j++ )
    1311             :                         {
    1312           0 :                           tmp[0] = *s;
    1313           0 :                           tmp[1] = 0;
    1314           0 :                           writestrings (0, tmp, NULL);
    1315             :                         }
    1316           0 :                       if ( *s )
    1317           0 :                         s++;
    1318             :                     }
    1319             :                 }
    1320             :             }
    1321             :           else
    1322          20 :             writestrings (0, "   ", NULL);
    1323          68 :           if ( opts[i].long_opt )
    1324             :             {
    1325          68 :               tmp[0] = opts[i].short_opt < 256?',':' ';
    1326          68 :               tmp[1] = 0;
    1327          68 :               j += writestrings (0, tmp, " --", opts[i].long_opt, NULL);
    1328          68 :               if (s && *s == '|' )
    1329             :                 {
    1330          20 :                   if ( *++s != '=' )
    1331             :                     {
    1332          20 :                       writestrings (0, " ", NULL);
    1333          20 :                       j++;
    1334             :                     }
    1335         144 :                   for ( ; *s && *s != '|'; s++, j++ )
    1336             :                     {
    1337         124 :                       tmp[0] = *s;
    1338         124 :                       tmp[1] = 0;
    1339         124 :                       writestrings (0, tmp, NULL);
    1340             :                     }
    1341          20 :                   if ( *s )
    1342          20 :                     s++;
    1343             :                 }
    1344          68 :               writestrings (0, "   ", NULL);
    1345          68 :               j += 3;
    1346             :             }
    1347         304 :           for (;j < indent; j++ )
    1348         236 :             writestrings (0, " ", NULL);
    1349          68 :           if ( s )
    1350             :             {
    1351          68 :               if ( *s && j > indent )
    1352             :                 {
    1353          16 :                   writestrings (0, "\n", NULL);
    1354         368 :                   for (j=0;j < indent; j++ )
    1355         352 :                     writestrings (0, " ", NULL);
    1356             :                 }
    1357        1612 :               for (; *s; s++ )
    1358             :                 {
    1359        1544 :                   if ( *s == '\n' )
    1360             :                     {
    1361           0 :                       if ( s[1] )
    1362             :                         {
    1363           0 :                           writestrings (0, "\n", NULL);
    1364           0 :                           for (j=0; j < indent; j++ )
    1365           0 :                             writestrings (0, " ", NULL);
    1366             :                         }
    1367             :                     }
    1368             :                   else
    1369             :                     {
    1370        1544 :                       tmp[0] = *s;
    1371        1544 :                       tmp[1] = 0;
    1372        1544 :                       writestrings (0, tmp, NULL);
    1373             :                     }
    1374             :                 }
    1375             :             }
    1376          68 :           writestrings (0, "\n", NULL);
    1377             :         }
    1378           4 :         if ( (flags & ARGPARSE_FLAG_ONEDASH) )
    1379           0 :           writestrings (0, "\n(A single dash may be used "
    1380             :                         "instead of the double ones)\n", NULL);
    1381             :     }
    1382           4 :   if ( (s=strusage(19)) )
    1383             :     {
    1384           4 :       writestrings (0, "\n", NULL);
    1385           4 :       writestrings (0, s, NULL);
    1386             :     }
    1387           4 :   flushstrings (0);
    1388           4 :   exit(0);
    1389             : }
    1390             : 
    1391             : static void
    1392           5 : show_version ()
    1393             : {
    1394             :   const char *s;
    1395             :   int i;
    1396             : 
    1397             :   /* Version line.  */
    1398           5 :   writestrings (0, strusage (11), NULL);
    1399           5 :   if ((s=strusage (12)))
    1400           0 :     writestrings (0, " (", s, ")", NULL);
    1401           5 :   writestrings (0, " ", strusage (13), "\n", NULL);
    1402             :   /* Additional version lines. */
    1403          55 :   for (i=20; i < 30; i++)
    1404          50 :     if ((s=strusage (i)))
    1405           1 :       writestrings (0, s, "\n", NULL);
    1406             :   /* Copyright string.  */
    1407           5 :   if ((s=strusage (14)))
    1408           5 :     writestrings (0, s, "\n", NULL);
    1409             :   /* Licence string.  */
    1410           5 :   if( (s=strusage (10)) )
    1411           5 :     writestrings (0, s, "\n", NULL);
    1412             :   /* Copying conditions. */
    1413           5 :   if ( (s=strusage(15)) )
    1414           5 :     writestrings (0, s, NULL);
    1415             :   /* Thanks. */
    1416           5 :   if ((s=strusage(18)))
    1417           0 :     writestrings (0, s, NULL);
    1418             :   /* Additional program info. */
    1419          55 :   for (i=30; i < 40; i++ )
    1420          50 :     if ( (s=strusage (i)) )
    1421           7 :       writestrings (0, s, NULL);
    1422           5 :   flushstrings (0);
    1423           5 : }
    1424             : 
    1425             : 
    1426             : void
    1427           0 : usage (int level)
    1428             : {
    1429             :   const char *p;
    1430             : 
    1431           0 :   if (!level)
    1432             :     {
    1433           0 :       writestrings (1, strusage(11), " ", strusage(13), "; ",
    1434             :                     strusage (14), "\n", NULL);
    1435           0 :       flushstrings (1);
    1436             :     }
    1437           0 :   else if (level == 1)
    1438             :     {
    1439           0 :       p = strusage (40);
    1440           0 :       writestrings (1, p, NULL);
    1441           0 :       if (*p && p[strlen(p)] != '\n')
    1442           0 :         writestrings (1, "\n", NULL);
    1443           0 :       exit (2);
    1444             :     }
    1445           0 :   else if (level == 2)
    1446             :     {
    1447           0 :       p = strusage (42);
    1448           0 :       if (p && *p == '1')
    1449             :         {
    1450           0 :           p = strusage (40);
    1451           0 :           writestrings (1, p, NULL);
    1452           0 :           if (*p && p[strlen(p)] != '\n')
    1453           0 :             writestrings (1, "\n", NULL);
    1454             :         }
    1455           0 :       writestrings (0, strusage(41), "\n", NULL);
    1456           0 :       exit (0);
    1457             :     }
    1458           0 : }
    1459             : 
    1460             : /* Level
    1461             :  *     0: Print copyright string to stderr
    1462             :  *     1: Print a short usage hint to stderr and terminate
    1463             :  *     2: Print a long usage hint to stdout and terminate
    1464             :  *    10: Return license info string
    1465             :  *    11: Return the name of the program
    1466             :  *    12: Return optional name of package which includes this program.
    1467             :  *    13: version  string
    1468             :  *    14: copyright string
    1469             :  *    15: Short copying conditions (with LFs)
    1470             :  *    16: Long copying conditions (with LFs)
    1471             :  *    17: Optional printable OS name
    1472             :  *    18: Optional thanks list (with LFs)
    1473             :  *    19: Bug report info
    1474             :  *20..29: Additional lib version strings.
    1475             :  *30..39: Additional program info (with LFs)
    1476             :  *    40: short usage note (with LF)
    1477             :  *    41: long usage note (with LF)
    1478             :  *    42: Flag string:
    1479             :  *          First char is '1':
    1480             :  *             The short usage notes needs to be printed
    1481             :  *             before the long usage note.
    1482             :  */
    1483             : const char *
    1484         686 : strusage( int level )
    1485             : {
    1486         686 :   const char *p = strusage_handler? strusage_handler(level) : NULL;
    1487             : 
    1488         686 :   if ( p )
    1489         565 :     return map_static_macro_string (p);
    1490             : 
    1491         121 :   switch ( level )
    1492             :     {
    1493             : 
    1494             :     case 10:
    1495             : #if ARGPARSE_GPL_VERSION == 3
    1496           5 :       p = ("License GPLv3+: GNU GPL version 3 or later "
    1497             :            "<https://gnu.org/licenses/gpl.html>");
    1498             : #else
    1499             :       p = ("License GPLv2+: GNU GPL version 2 or later "
    1500             :            "<https://gnu.org/licenses/>");
    1501             : #endif
    1502           5 :       break;
    1503           0 :     case 11: p = "foo"; break;
    1504           0 :     case 13: p = "0.0"; break;
    1505           5 :     case 14: p = ARGPARSE_CRIGHT_STR; break;
    1506           5 :     case 15: p =
    1507             : "This is free software: you are free to change and redistribute it.\n"
    1508             : "There is NO WARRANTY, to the extent permitted by law.\n";
    1509           5 :       break;
    1510           0 :     case 16: p =
    1511             : "This is free software; you can redistribute it and/or modify\n"
    1512             : "it under the terms of the GNU General Public License as published by\n"
    1513             : "the Free Software Foundation; either version "
    1514             : ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
    1515             : " of the License, or\n"
    1516             : "(at your option) any later version.\n\n"
    1517             : "It is distributed in the hope that it will be useful,\n"
    1518             : "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    1519             : "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
    1520             : "GNU General Public License for more details.\n\n"
    1521             : "You should have received a copy of the GNU General Public License\n"
    1522             : "along with this software.  If not, see <https://gnu.org/licenses/>.\n";
    1523           0 :       break;
    1524             :     case 40: /* short and long usage */
    1525           0 :     case 41: p = ""; break;
    1526             :     }
    1527             : 
    1528         121 :   return p;
    1529             : }
    1530             : 
    1531             : 
    1532             : /* Set the usage handler.  This function is basically a constructor.  */
    1533             : void
    1534        2339 : set_strusage ( const char *(*f)( int ) )
    1535             : {
    1536        2339 :   strusage_handler = f;
    1537        2339 : }
    1538             : 
    1539             : 
    1540             : #ifdef TEST
    1541             : static struct {
    1542             :     int verbose;
    1543             :     int debug;
    1544             :     char *outfile;
    1545             :     char *crf;
    1546             :     int myopt;
    1547             :     int echo;
    1548             :     int a_long_one;
    1549             : } opt;
    1550             : 
    1551             : int
    1552             : main(int argc, char **argv)
    1553             : {
    1554             :   ARGPARSE_OPTS opts[] = {
    1555             :     ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"),
    1556             :     ARGPARSE_s_n('e', "echo"   , ("Zeile ausgeben, damit wir sehen, "
    1557             :                                   "was wir eingegeben haben")),
    1558             :     ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
    1559             :     ARGPARSE_s_s('o', "output", 0 ),
    1560             :     ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ),
    1561             :     /* Note that on a non-utf8 terminal the ß might garble the output. */
    1562             :     ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
    1563             :     ARGPARSE_o_i('m', "my-option", 0),
    1564             :     ARGPARSE_s_n(500, "a-long-option", 0 ),
    1565             :     ARGPARSE_end()
    1566             :   };
    1567             :   ARGPARSE_ARGS pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL
    1568             :                                          | ARGPARSE_FLAG_MIXED
    1569             :                                          | ARGPARSE_FLAG_ONEDASH) };
    1570             :   int i;
    1571             : 
    1572             :   while (arg_parse  (&pargs, opts))
    1573             :     {
    1574             :       switch (pargs.r_opt)
    1575             :         {
    1576             :         case ARGPARSE_IS_ARG :
    1577             :           printf ("arg='%s'\n", pargs.r.ret_str);
    1578             :           break;
    1579             :         case 'v': opt.verbose++; break;
    1580             :         case 'e': opt.echo++; break;
    1581             :         case 'd': opt.debug++; break;
    1582             :         case 'o': opt.outfile = pargs.r.ret_str; break;
    1583             :         case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
    1584             :         case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
    1585             :         case 500: opt.a_long_one++;  break;
    1586             :         default : pargs.err = ARGPARSE_PRINT_WARNING; break;
    1587             :         }
    1588             :     }
    1589             :   for (i=0; i < argc; i++ )
    1590             :     printf ("%3d -> (%s)\n", i, argv[i] );
    1591             :   puts ("Options:");
    1592             :   if (opt.verbose)
    1593             :     printf ("  verbose=%d\n", opt.verbose );
    1594             :   if (opt.debug)
    1595             :     printf ("  debug=%d\n", opt.debug );
    1596             :   if (opt.outfile)
    1597             :     printf ("  outfile='%s'\n", opt.outfile );
    1598             :   if (opt.crf)
    1599             :     printf ("  crffile='%s'\n", opt.crf );
    1600             :   if (opt.myopt)
    1601             :     printf ("  myopt=%d\n", opt.myopt );
    1602             :   if (opt.a_long_one)
    1603             :     printf ("  a-long-one=%d\n", opt.a_long_one );
    1604             :   if (opt.echo)
    1605             :     printf ("  echo=%d\n", opt.echo );
    1606             : 
    1607             :   return 0;
    1608             : }
    1609             : #endif /*TEST*/
    1610             : 
    1611             : /**** bottom of file ****/

Generated by: LCOV version 1.11