LCOV - code coverage report
Current view: top level - src - argparse.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 642 0.0 %
Date: 2016-11-29 15:07:43 Functions: 0 22 0.0 %

          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-2015 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://www.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) 2015 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           0 : my_log_error (const char *fmt, ...)
     105             : {
     106             :   va_list arg_ptr ;
     107             : 
     108           0 :   va_start (arg_ptr, fmt);
     109           0 :   fprintf (stderr, "%s: ", strusage (11));
     110           0 :   vfprintf (stderr, fmt, arg_ptr);
     111           0 :   va_end (arg_ptr);
     112           0 : }
     113             : 
     114             : static void
     115           0 : my_log_bug (const char *fmt, ...)
     116             : {
     117             :   va_list arg_ptr ;
     118             : 
     119           0 :   va_start (arg_ptr, fmt);
     120           0 :   fprintf (stderr, "%s: Ohhhh jeeee: ", strusage (11));
     121           0 :   vfprintf (stderr, fmt, arg_ptr);
     122           0 :   va_end (arg_ptr);
     123           0 :   abort ();
     124             : }
     125             : 
     126             : /* Return true if the native charset is utf-8.  */
     127             : static int
     128           0 : is_native_utf8 (void)
     129             : {
     130           0 :   return 1;
     131             : }
     132             : 
     133             : static char *
     134           0 : my_trim_spaces (char *str)
     135             : {
     136             :   char *string, *p, *mark;
     137             : 
     138           0 :   string = str;
     139             :   /* Find first non space character. */
     140           0 :   for (p=string; *p && isspace (*(unsigned char*)p) ; p++)
     141             :     ;
     142             :   /* Move characters. */
     143           0 :   for ((mark = NULL); (*string = *p); string++, p++)
     144           0 :     if (isspace (*(unsigned char*)p))
     145             :       {
     146           0 :         if (!mark)
     147           0 :           mark = string;
     148             :       }
     149             :     else
     150           0 :       mark = NULL;
     151           0 :   if (mark)
     152           0 :     *mark = '\0' ;  /* Remove trailing spaces. */
     153             : 
     154           0 :   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           0 : argparse_register_outfnc (int (*fnc)(int, const char *))
     293             : {
     294           0 :   custom_outfnc = fnc;
     295           0 : }
     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           0 : writestrings (int is_error, const char *string, ...)
     303             : {
     304             :   va_list arg_ptr;
     305             :   const char *s;
     306           0 :   int count = 0;
     307             : 
     308           0 :   if (string)
     309             :     {
     310           0 :       s = string;
     311           0 :       va_start (arg_ptr, string);
     312             :       do
     313             :         {
     314           0 :           if (custom_outfnc)
     315           0 :             custom_outfnc (is_error? 2:1, s);
     316             :           else
     317           0 :             fputs (s, is_error? stderr : stdout);
     318           0 :           count += strlen (s);
     319             :         }
     320           0 :       while ((s = va_arg (arg_ptr, const char *)));
     321           0 :       va_end (arg_ptr);
     322             :     }
     323           0 :   return count;
     324             : }
     325             : 
     326             : 
     327             : static void
     328           0 : flushstrings (int is_error)
     329             : {
     330           0 :   if (custom_outfnc)
     331           0 :     custom_outfnc (is_error? 2:1, NULL);
     332             :   else
     333           0 :     fflush (is_error? stderr : stdout);
     334           0 : }
     335             : 
     336             : 
     337             : static void
     338           0 : initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
     339             : {
     340           0 :   if( !(arg->flags & (1<<15)) )
     341             :     {
     342             :       /* Initialize this instance. */
     343           0 :       arg->internal.idx = 0;
     344           0 :       arg->internal.last = NULL;
     345           0 :       arg->internal.inarg = 0;
     346           0 :       arg->internal.stopped = 0;
     347           0 :       arg->internal.aliases = NULL;
     348           0 :       arg->internal.cur_alias = NULL;
     349           0 :       arg->internal.iio_list = NULL;
     350           0 :       arg->err = 0;
     351           0 :       arg->flags |= 1<<15; /* Mark as initialized.  */
     352           0 :       if ( *arg->argc < 0 )
     353           0 :         log_bug ("invalid argument for arg_parse\n");
     354             :     }
     355             : 
     356             : 
     357           0 :   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           0 :   arg->r.ret_str = NULL;
     412           0 :   arg->r.ret_long = 0;
     413           0 : }
     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           0 : ignore_invalid_option_clear (ARGPARSE_ARGS *arg)
     527             : {
     528             :   IIO_ITEM_DEF item, tmpitem;
     529             : 
     530           0 :   for (item = arg->internal.iio_list; item; item = tmpitem)
     531             :     {
     532           0 :       tmpitem = item->next;
     533           0 :       xfree (item);
     534             :     }
     535           0 :   arg->internal.iio_list = NULL;
     536           0 : }
     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           0 : optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
     563             :                ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
     564             : {
     565             :   int state, i, c;
     566           0 :   int idx=0;
     567             :   char keyword[100];
     568           0 :   char *buffer = NULL;
     569           0 :   size_t buflen = 0;
     570           0 :   int in_alias=0;
     571             : 
     572           0 :   if (!fp) /* Divert to to arg_parse() in this case.  */
     573           0 :     return arg_parse (arg, opts);
     574             : 
     575           0 :   initialize (arg, filename, lineno);
     576             : 
     577             :   /* Find the next keyword.  */
     578           0 :   state = i = 0;
     579             :   for (;;)
     580             :     {
     581           0 :       c = getc (fp);
     582           0 :       if (c == '\n' || c== EOF )
     583             :         {
     584           0 :           if ( c != EOF )
     585           0 :             ++*lineno;
     586           0 :           if (state == -1)
     587           0 :             break;
     588           0 :           else if (state == 2)
     589             :             {
     590           0 :               keyword[i] = 0;
     591           0 :               for (i=0; opts[i].short_opt; i++ )
     592             :                 {
     593           0 :                   if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
     594           0 :                     break;
     595             :                 }
     596           0 :               idx = i;
     597           0 :               arg->r_opt = opts[idx].short_opt;
     598           0 :               if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
     599             :                 {
     600           0 :                   state = i = 0;
     601           0 :                   continue;
     602             :                 }
     603           0 :               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           0 :               else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
     622           0 :                 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           0 :               break;
     629             :             }
     630           0 :           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           0 :           else if (state == 4)
     645             :             {
     646             :               /* Has an argument. */
     647           0 :               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           0 :               else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
     674           0 :                 arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
     675             :               else
     676             :                 {
     677             :                   char *p;
     678             : 
     679           0 :                   if (!buffer)
     680             :                     {
     681           0 :                       keyword[i] = 0;
     682           0 :                       buffer = xtrystrdup (keyword);
     683           0 :                       if (!buffer)
     684           0 :                         arg->r_opt = ARGPARSE_OUT_OF_CORE;
     685             :                     }
     686             :                   else
     687           0 :                     buffer[i] = 0;
     688             : 
     689           0 :                   if (buffer)
     690             :                     {
     691           0 :                       trim_spaces (buffer);
     692           0 :                       p = buffer;
     693           0 :                       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           0 :                       if (!set_opt_arg (arg, opts[idx].flags, p))
     701           0 :                         xfree (buffer);
     702             :                     }
     703             :                 }
     704           0 :               break;
     705             :             }
     706           0 :           else if (c == EOF)
     707             :             {
     708           0 :               ignore_invalid_option_clear (arg);
     709           0 :               if (ferror (fp))
     710           0 :                 arg->r_opt = ARGPARSE_READ_ERROR;
     711             :               else
     712           0 :                 arg->r_opt = 0; /* EOF. */
     713           0 :               break;
     714             :             }
     715           0 :           state = 0;
     716           0 :           i = 0;
     717             :         }
     718           0 :       else if (state == -1)
     719             :         ; /* Skip. */
     720           0 :       else if (state == 0 && isascii (c) && isspace(c))
     721             :         ; /* Skip leading white space.  */
     722           0 :       else if (state == 0 && c == '#' )
     723           0 :         state = 1;      /* Start of a comment.  */
     724           0 :       else if (state == 1)
     725             :         ; /* Skip comments. */
     726           0 :       else if (state == 2 && isascii (c) && isspace(c))
     727             :         {
     728             :           /* Check keyword.  */
     729           0 :           keyword[i] = 0;
     730           0 :           for (i=0; opts[i].short_opt; i++ )
     731           0 :             if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
     732           0 :               break;
     733           0 :           idx = i;
     734           0 :           arg->r_opt = opts[idx].short_opt;
     735           0 :           if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
     736             :             {
     737           0 :               state = 1; /* Process like a comment.  */
     738             :             }
     739           0 :           else if (!opts[idx].short_opt)
     740             :             {
     741           0 :               if (!strcmp (keyword, "alias"))
     742             :                 {
     743           0 :                   in_alias = 1;
     744           0 :                   state = 3;
     745             :                 }
     746           0 :               else if (!strcmp (keyword, "ignore-invalid-option"))
     747             :                 {
     748           0 :                   if (ignore_invalid_option_add (arg, fp))
     749             :                     {
     750           0 :                       arg->r_opt = ARGPARSE_OUT_OF_CORE;
     751           0 :                       break;
     752             :                     }
     753           0 :                   state = i = 0;
     754           0 :                   ++*lineno;
     755             :                 }
     756           0 :               else if (ignore_invalid_option_p (arg, keyword))
     757           0 :                 state = 1; /* Process like a comment.  */
     758             :               else
     759             :                 {
     760           0 :                   arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
     761             :                                 ? ARGPARSE_INVALID_COMMAND
     762           0 :                                 : ARGPARSE_INVALID_OPTION);
     763           0 :                   state = -1; /* Skip rest of line and leave.  */
     764             :                 }
     765             :             }
     766             :           else
     767           0 :             state = 3;
     768             :         }
     769           0 :       else if (state == 3)
     770             :         {
     771             :           /* Skip leading spaces of the argument.  */
     772           0 :           if (!isascii (c) || !isspace(c))
     773             :             {
     774           0 :               i = 0;
     775           0 :               keyword[i++] = c;
     776           0 :               state = 4;
     777             :             }
     778             :         }
     779           0 :       else if (state == 4)
     780             :         {
     781             :           /* Collect the argument. */
     782           0 :           if (buffer)
     783             :             {
     784           0 :               if (i < buflen-1)
     785           0 :                 buffer[i++] = c;
     786             :               else
     787             :                 {
     788             :                   char *tmp;
     789           0 :                   size_t tmplen = buflen + 50;
     790             : 
     791           0 :                   tmp = xtryrealloc (buffer, tmplen);
     792           0 :                   if (tmp)
     793             :                     {
     794           0 :                       buflen = tmplen;
     795           0 :                       buffer = tmp;
     796           0 :                       buffer[i++] = c;
     797             :                     }
     798             :                   else
     799             :                     {
     800           0 :                       xfree (buffer);
     801           0 :                       arg->r_opt = ARGPARSE_OUT_OF_CORE;
     802           0 :                       break;
     803             :                     }
     804             :                 }
     805             :             }
     806           0 :           else if (i < DIM(keyword)-1)
     807           0 :             keyword[i++] = c;
     808             :           else
     809             :             {
     810           0 :               size_t tmplen = DIM(keyword) + 50;
     811           0 :               buffer = xtrymalloc (tmplen);
     812           0 :               if (buffer)
     813             :                 {
     814           0 :                   buflen = tmplen;
     815           0 :                   memcpy(buffer, keyword, i);
     816           0 :                   buffer[i++] = c;
     817             :                 }
     818             :               else
     819             :                 {
     820           0 :                   arg->r_opt = ARGPARSE_OUT_OF_CORE;
     821           0 :                   break;
     822             :                 }
     823             :             }
     824             :         }
     825           0 :       else if (i >= DIM(keyword)-1)
     826             :         {
     827           0 :           arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
     828           0 :           state = -1; /* Skip rest of line and leave.  */
     829             :         }
     830             :       else
     831             :         {
     832           0 :           keyword[i++] = c;
     833           0 :           state = 2;
     834             :         }
     835           0 :     }
     836             : 
     837           0 :   return arg->r_opt;
     838             : }
     839             : 
     840             : 
     841             : 
     842             : static int
     843           0 : find_long_option( ARGPARSE_ARGS *arg,
     844             :                   ARGPARSE_OPTS *opts, const char *keyword )
     845             : {
     846             :     int i;
     847             :     size_t n;
     848             : 
     849             :     (void)arg;
     850             : 
     851             :     /* Would be better if we can do a binary search, but it is not
     852             :        possible to reorder our option table because we would mess
     853             :        up our help strings - What we can do is: Build a nice option
     854             :        lookup table when this function is first invoked */
     855           0 :     if( !*keyword )
     856           0 :         return -1;
     857           0 :     for(i=0; opts[i].short_opt; i++ )
     858           0 :         if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
     859           0 :             return i;
     860             : #if 0
     861             :     {
     862             :         ALIAS_DEF a;
     863             :         /* see whether it is an alias */
     864             :         for( a = args->internal.aliases; a; a = a->next ) {
     865             :             if( !strcmp( a->name, keyword) ) {
     866             :                 /* todo: must parse the alias here */
     867             :                 args->internal.cur_alias = a;
     868             :                 return -3; /* alias available */
     869             :             }
     870             :         }
     871             :     }
     872             : #endif
     873             :     /* not found, see whether it is an abbreviation */
     874             :     /* aliases may not be abbreviated */
     875           0 :     n = strlen( keyword );
     876           0 :     for(i=0; opts[i].short_opt; i++ ) {
     877           0 :         if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) {
     878             :             int j;
     879           0 :             for(j=i+1; opts[j].short_opt; j++ ) {
     880           0 :                 if( opts[j].long_opt
     881           0 :                     && !strncmp( opts[j].long_opt, keyword, n ) )
     882           0 :                     return -2;  /* abbreviation is ambiguous */
     883             :             }
     884           0 :             return i;
     885             :         }
     886             :     }
     887           0 :     return -1;  /* Not found.  */
     888             : }
     889             : 
     890             : int
     891           0 : arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
     892             : {
     893             :   int idx;
     894             :   int argc;
     895             :   char **argv;
     896             :   char *s, *s2;
     897             :   int i;
     898           0 :   char string_with_x[] = "x";
     899             : 
     900           0 :   initialize( arg, NULL, NULL );
     901           0 :   argc = *arg->argc;
     902           0 :   argv = *arg->argv;
     903           0 :   idx = arg->internal.idx;
     904             : 
     905           0 :   if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
     906             :     {
     907             :       /* Skip the first argument.  */
     908           0 :       argc--; argv++; idx++;
     909             :     }
     910             : 
     911             :  next_one:
     912           0 :   if (!argc)
     913             :     {
     914             :       /* No more args.  */
     915           0 :       arg->r_opt = 0;
     916           0 :       goto leave; /* Ready. */
     917             :     }
     918             : 
     919           0 :   s = *argv;
     920           0 :   arg->internal.last = s;
     921             : 
     922           0 :   if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL))
     923             :     {
     924           0 :       arg->r_opt = ARGPARSE_IS_ARG;  /* Not an option but an argument.  */
     925           0 :       arg->r_type = 2;
     926           0 :       arg->r.ret_str = s;
     927           0 :       argc--; argv++; idx++; /* set to next one */
     928             :     }
     929           0 :   else if( arg->internal.stopped )
     930             :     {
     931           0 :       arg->r_opt = 0;
     932           0 :       goto leave; /* Ready.  */
     933             :     }
     934           0 :   else if ( *s == '-' && s[1] == '-' )
     935           0 :     {
     936             :       /* Long option.  */
     937             :       char *argpos;
     938             : 
     939           0 :       arg->internal.inarg = 0;
     940           0 :       if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
     941             :         {
     942             :           /* Stop option processing.  */
     943           0 :           arg->internal.stopped = 1;
     944           0 :           arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
     945           0 :           argc--; argv++; idx++;
     946           0 :           goto next_one;
     947             :         }
     948             : 
     949           0 :       argpos = strchr( s+2, '=' );
     950           0 :       if ( argpos )
     951           0 :         *argpos = 0;
     952           0 :       i = find_long_option ( arg, opts, s+2 );
     953           0 :       if ( argpos )
     954           0 :         *argpos = '=';
     955             : 
     956           0 :       if ( i < 0 && !strcmp ( "help", s+2) )
     957           0 :         show_help (opts, arg->flags);
     958           0 :       else if ( i < 0 && !strcmp ( "version", s+2) )
     959             :         {
     960           0 :           if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
     961             :             {
     962           0 :               show_version ();
     963           0 :               exit(0);
     964             :             }
     965             :         }
     966           0 :       else if ( i < 0 && !strcmp( "warranty", s+2))
     967             :         {
     968           0 :           writestrings (0, strusage (16), "\n", NULL);
     969           0 :           exit (0);
     970             :         }
     971           0 :       else if ( i < 0 && !strcmp( "dump-options", s+2) )
     972             :         {
     973           0 :           for (i=0; opts[i].short_opt; i++ )
     974             :             {
     975           0 :               if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
     976           0 :                 writestrings (0, "--", opts[i].long_opt, "\n", NULL);
     977             :             }
     978           0 :           writestrings (0, "--dump-options\n--help\n--version\n--warranty\n",
     979             :                         NULL);
     980           0 :           exit (0);
     981             :         }
     982             : 
     983           0 :       if ( i == -2 )
     984           0 :         arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
     985           0 :       else if ( i == -1 )
     986             :         {
     987           0 :           arg->r_opt = ARGPARSE_INVALID_OPTION;
     988           0 :           arg->r.ret_str = s+2;
     989             :         }
     990             :       else
     991           0 :         arg->r_opt = opts[i].short_opt;
     992           0 :       if ( i < 0 )
     993             :         ;
     994           0 :       else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
     995             :         {
     996           0 :           if ( argpos )
     997             :             {
     998           0 :               s2 = argpos+1;
     999           0 :               if ( !*s2 )
    1000           0 :                 s2 = NULL;
    1001             :             }
    1002             :           else
    1003           0 :             s2 = argv[1];
    1004           0 :           if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
    1005             :             {
    1006           0 :               arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional.  */
    1007             :             }
    1008           0 :           else if ( !s2 )
    1009             :             {
    1010           0 :               arg->r_opt = ARGPARSE_MISSING_ARG;
    1011             :             }
    1012           0 :           else if ( !argpos && *s2 == '-'
    1013           0 :                     && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
    1014             :             {
    1015             :               /* The argument is optional and the next seems to be an
    1016             :                  option.  We do not check this possible option but
    1017             :                  assume no argument */
    1018           0 :               arg->r_type = ARGPARSE_TYPE_NONE;
    1019             :             }
    1020             :           else
    1021             :             {
    1022           0 :               set_opt_arg (arg, opts[i].flags, s2);
    1023           0 :               if ( !argpos )
    1024             :                 {
    1025           0 :                   argc--; argv++; idx++; /* Skip one.  */
    1026             :                 }
    1027             :             }
    1028             :         }
    1029             :       else
    1030             :         {
    1031             :           /* Does not take an argument. */
    1032           0 :           if ( argpos )
    1033           0 :             arg->r_type = ARGPARSE_UNEXPECTED_ARG;
    1034             :           else
    1035           0 :             arg->r_type = 0;
    1036             :         }
    1037           0 :       argc--; argv++; idx++; /* Set to next one.  */
    1038             :     }
    1039           0 :     else if ( (*s == '-' && s[1]) || arg->internal.inarg )
    1040           0 :       {
    1041             :         /* Short option.  */
    1042           0 :         int dash_kludge = 0;
    1043             : 
    1044           0 :         i = 0;
    1045           0 :         if ( !arg->internal.inarg )
    1046             :           {
    1047           0 :             arg->internal.inarg++;
    1048           0 :             if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
    1049             :               {
    1050           0 :                 for (i=0; opts[i].short_opt; i++ )
    1051           0 :                   if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1))
    1052             :                     {
    1053           0 :                       dash_kludge = 1;
    1054           0 :                       break;
    1055             :                     }
    1056             :               }
    1057             :           }
    1058           0 :         s += arg->internal.inarg;
    1059             : 
    1060           0 :         if (!dash_kludge )
    1061             :           {
    1062           0 :             for (i=0; opts[i].short_opt; i++ )
    1063           0 :               if ( opts[i].short_opt == *s )
    1064           0 :                 break;
    1065             :           }
    1066             : 
    1067           0 :         if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
    1068           0 :           show_help (opts, arg->flags);
    1069             : 
    1070           0 :         arg->r_opt = opts[i].short_opt;
    1071           0 :         if (!opts[i].short_opt )
    1072             :           {
    1073           0 :             arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
    1074           0 :               ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
    1075           0 :             arg->internal.inarg++; /* Point to the next arg.  */
    1076           0 :             arg->r.ret_str = s;
    1077             :           }
    1078           0 :         else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
    1079             :           {
    1080           0 :             if ( s[1] && !dash_kludge )
    1081             :               {
    1082           0 :                 s2 = s+1;
    1083           0 :                 set_opt_arg (arg, opts[i].flags, s2);
    1084             :               }
    1085             :             else
    1086             :               {
    1087           0 :                 s2 = argv[1];
    1088           0 :                 if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
    1089             :                   {
    1090           0 :                     arg->r_type = ARGPARSE_TYPE_NONE;
    1091             :                   }
    1092           0 :                 else if ( !s2 )
    1093             :                   {
    1094           0 :                     arg->r_opt = ARGPARSE_MISSING_ARG;
    1095             :                   }
    1096           0 :                 else if ( *s2 == '-' && s2[1]
    1097           0 :                           && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
    1098             :                   {
    1099             :                     /* The argument is optional and the next seems to
    1100             :                        be an option.  We do not check this possible
    1101             :                        option but assume no argument.  */
    1102           0 :                     arg->r_type = ARGPARSE_TYPE_NONE;
    1103             :                   }
    1104             :                 else
    1105             :                   {
    1106           0 :                     set_opt_arg (arg, opts[i].flags, s2);
    1107           0 :                     argc--; argv++; idx++; /* Skip one.  */
    1108             :                   }
    1109             :               }
    1110           0 :             s = string_with_x; /* This is so that !s[1] yields false.  */
    1111             :           }
    1112             :         else
    1113             :           {
    1114             :             /* Does not take an argument.  */
    1115           0 :             arg->r_type = ARGPARSE_TYPE_NONE;
    1116           0 :             arg->internal.inarg++; /* Point to the next arg.  */
    1117             :           }
    1118           0 :         if ( !s[1] || dash_kludge )
    1119             :           {
    1120             :             /* No more concatenated short options.  */
    1121           0 :             arg->internal.inarg = 0;
    1122           0 :             argc--; argv++; idx++;
    1123             :           }
    1124             :       }
    1125           0 :   else if ( arg->flags & ARGPARSE_FLAG_MIXED )
    1126             :     {
    1127           0 :       arg->r_opt = ARGPARSE_IS_ARG;
    1128           0 :       arg->r_type = 2;
    1129           0 :       arg->r.ret_str = s;
    1130           0 :       argc--; argv++; idx++; /* Set to next one.  */
    1131             :     }
    1132             :   else
    1133             :     {
    1134           0 :       arg->internal.stopped = 1; /* Stop option processing.  */
    1135           0 :       goto next_one;
    1136             :     }
    1137             : 
    1138             :  leave:
    1139           0 :   *arg->argc = argc;
    1140           0 :   *arg->argv = argv;
    1141           0 :   arg->internal.idx = idx;
    1142           0 :   return arg->r_opt;
    1143             : }
    1144             : 
    1145             : 
    1146             : /* Returns: -1 on error, 0 for an integer type and 1 for a non integer
    1147             :    type argument.  */
    1148             : static int
    1149           0 : set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s)
    1150             : {
    1151           0 :   int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
    1152             :   long l;
    1153             : 
    1154           0 :   switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
    1155             :     {
    1156             :     case ARGPARSE_TYPE_LONG:
    1157             :     case ARGPARSE_TYPE_INT:
    1158           0 :       errno = 0;
    1159           0 :       l = strtol (s, NULL, base);
    1160           0 :       if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)
    1161             :         {
    1162           0 :           arg->r_opt = ARGPARSE_INVALID_ARG;
    1163           0 :           return -1;
    1164             :         }
    1165           0 :       if (arg->r_type == ARGPARSE_TYPE_LONG)
    1166           0 :         arg->r.ret_long = l;
    1167           0 :       else if ( (l < 0 && l < INT_MIN) || l > INT_MAX )
    1168             :         {
    1169           0 :           arg->r_opt = ARGPARSE_INVALID_ARG;
    1170           0 :           return -1;
    1171             :         }
    1172             :       else
    1173           0 :         arg->r.ret_int = (int)l;
    1174           0 :       return 0;
    1175             : 
    1176             :     case ARGPARSE_TYPE_ULONG:
    1177           0 :       while (isascii (*s) && isspace(*s))
    1178           0 :         s++;
    1179           0 :       if (*s == '-')
    1180             :         {
    1181           0 :           arg->r.ret_ulong = 0;
    1182           0 :           arg->r_opt = ARGPARSE_INVALID_ARG;
    1183           0 :           return -1;
    1184             :         }
    1185           0 :       errno = 0;
    1186           0 :       arg->r.ret_ulong = strtoul (s, NULL, base);
    1187           0 :       if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE)
    1188             :         {
    1189           0 :           arg->r_opt = ARGPARSE_INVALID_ARG;
    1190           0 :           return -1;
    1191             :         }
    1192           0 :       return 0;
    1193             : 
    1194             :     case ARGPARSE_TYPE_STRING:
    1195             :     default:
    1196           0 :       arg->r.ret_str = s;
    1197           0 :       return 1;
    1198             :     }
    1199             : }
    1200             : 
    1201             : 
    1202             : static size_t
    1203           0 : long_opt_strlen( ARGPARSE_OPTS *o )
    1204             : {
    1205           0 :   size_t n = strlen (o->long_opt);
    1206             : 
    1207           0 :   if ( o->description && *o->description == '|' )
    1208             :     {
    1209             :       const char *s;
    1210           0 :       int is_utf8 = is_native_utf8 ();
    1211             : 
    1212           0 :       s=o->description+1;
    1213           0 :       if ( *s != '=' )
    1214           0 :         n++;
    1215             :       /* For a (mostly) correct length calculation we exclude
    1216             :          continuation bytes (10xxxxxx) if we are on a native utf8
    1217             :          terminal. */
    1218           0 :       for (; *s && *s != '|'; s++ )
    1219           0 :         if ( is_utf8 && (*s&0xc0) != 0x80 )
    1220           0 :           n++;
    1221             :     }
    1222           0 :   return n;
    1223             : }
    1224             : 
    1225             : 
    1226             : /****************
    1227             :  * Print formatted help. The description string has some special
    1228             :  * meanings:
    1229             :  *  - A description string which is "@" suppresses help output for
    1230             :  *    this option
    1231             :  *  - a description,ine which starts with a '@' and is followed by
    1232             :  *    any other characters is printed as is; this may be used for examples
    1233             :  *    ans such.
    1234             :  *  - A description which starts with a '|' outputs the string between this
    1235             :  *    bar and the next one as arguments of the long option.
    1236             :  */
    1237             : static void
    1238           0 : show_help (ARGPARSE_OPTS *opts, unsigned int flags)
    1239             : {
    1240             :   const char *s;
    1241             :   char tmp[2];
    1242             : 
    1243           0 :   show_version ();
    1244           0 :   writestrings (0, "\n", NULL);
    1245           0 :   s = strusage (42);
    1246           0 :   if (s && *s == '1')
    1247             :     {
    1248           0 :       s = strusage (40);
    1249           0 :       writestrings (1, s, NULL);
    1250           0 :       if (*s && s[strlen(s)] != '\n')
    1251           0 :         writestrings (1, "\n", NULL);
    1252             :     }
    1253           0 :   s = strusage(41);
    1254           0 :   writestrings (0, s, "\n", NULL);
    1255           0 :   if ( opts[0].description )
    1256             :     {
    1257             :       /* Auto format the option description.  */
    1258             :       int i,j, indent;
    1259             : 
    1260             :       /* Get max. length of long options.  */
    1261           0 :       for (i=indent=0; opts[i].short_opt; i++ )
    1262             :         {
    1263           0 :           if ( opts[i].long_opt )
    1264           0 :             if ( !opts[i].description || *opts[i].description != '@' )
    1265           0 :               if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
    1266           0 :                 indent = j;
    1267             :         }
    1268             : 
    1269             :       /* Example: " -v, --verbose   Viele Sachen ausgeben" */
    1270           0 :       indent += 10;
    1271           0 :       if ( *opts[0].description != '@' )
    1272           0 :         writestrings (0, "Options:", "\n", NULL);
    1273           0 :       for (i=0; opts[i].short_opt; i++ )
    1274             :         {
    1275           0 :           s = map_static_macro_string (_( opts[i].description ));
    1276           0 :           if ( s && *s== '@' && !s[1] ) /* Hide this line.  */
    1277           0 :             continue;
    1278           0 :           if ( s && *s == '@' )  /* Unindented comment only line.  */
    1279             :             {
    1280           0 :               for (s++; *s; s++ )
    1281             :                 {
    1282           0 :                   if ( *s == '\n' )
    1283             :                     {
    1284           0 :                       if( s[1] )
    1285           0 :                         writestrings (0, "\n", NULL);
    1286             :                     }
    1287             :                   else
    1288             :                     {
    1289           0 :                       tmp[0] = *s;
    1290           0 :                       tmp[1] = 0;
    1291           0 :                       writestrings (0, tmp, NULL);
    1292             :                     }
    1293             :                 }
    1294           0 :               writestrings (0, "\n", NULL);
    1295           0 :               continue;
    1296             :             }
    1297             : 
    1298           0 :           j = 3;
    1299           0 :           if ( opts[i].short_opt < 256 )
    1300             :             {
    1301           0 :               tmp[0] = opts[i].short_opt;
    1302           0 :               tmp[1] = 0;
    1303           0 :               writestrings (0, " -", tmp, NULL );
    1304           0 :               if ( !opts[i].long_opt )
    1305             :                 {
    1306           0 :                   if (s && *s == '|' )
    1307             :                     {
    1308           0 :                       writestrings (0, " ", NULL); j++;
    1309           0 :                       for (s++ ; *s && *s != '|'; s++, j++ )
    1310             :                         {
    1311           0 :                           tmp[0] = *s;
    1312           0 :                           tmp[1] = 0;
    1313           0 :                           writestrings (0, tmp, NULL);
    1314             :                         }
    1315           0 :                       if ( *s )
    1316           0 :                         s++;
    1317             :                     }
    1318             :                 }
    1319             :             }
    1320             :           else
    1321           0 :             writestrings (0, "   ", NULL);
    1322           0 :           if ( opts[i].long_opt )
    1323             :             {
    1324           0 :               tmp[0] = opts[i].short_opt < 256?',':' ';
    1325           0 :               tmp[1] = 0;
    1326           0 :               j += writestrings (0, tmp, " --", opts[i].long_opt, NULL);
    1327           0 :               if (s && *s == '|' )
    1328             :                 {
    1329           0 :                   if ( *++s != '=' )
    1330             :                     {
    1331           0 :                       writestrings (0, " ", NULL);
    1332           0 :                       j++;
    1333             :                     }
    1334           0 :                   for ( ; *s && *s != '|'; s++, j++ )
    1335             :                     {
    1336           0 :                       tmp[0] = *s;
    1337           0 :                       tmp[1] = 0;
    1338           0 :                       writestrings (0, tmp, NULL);
    1339             :                     }
    1340           0 :                   if ( *s )
    1341           0 :                     s++;
    1342             :                 }
    1343           0 :               writestrings (0, "   ", NULL);
    1344           0 :               j += 3;
    1345             :             }
    1346           0 :           for (;j < indent; j++ )
    1347           0 :             writestrings (0, " ", NULL);
    1348           0 :           if ( s )
    1349             :             {
    1350           0 :               if ( *s && j > indent )
    1351             :                 {
    1352           0 :                   writestrings (0, "\n", NULL);
    1353           0 :                   for (j=0;j < indent; j++ )
    1354           0 :                     writestrings (0, " ", NULL);
    1355             :                 }
    1356           0 :               for (; *s; s++ )
    1357             :                 {
    1358           0 :                   if ( *s == '\n' )
    1359             :                     {
    1360           0 :                       if ( s[1] )
    1361             :                         {
    1362           0 :                           writestrings (0, "\n", NULL);
    1363           0 :                           for (j=0; j < indent; j++ )
    1364           0 :                             writestrings (0, " ", NULL);
    1365             :                         }
    1366             :                     }
    1367             :                   else
    1368             :                     {
    1369           0 :                       tmp[0] = *s;
    1370           0 :                       tmp[1] = 0;
    1371           0 :                       writestrings (0, tmp, NULL);
    1372             :                     }
    1373             :                 }
    1374             :             }
    1375           0 :           writestrings (0, "\n", NULL);
    1376             :         }
    1377           0 :         if ( (flags & ARGPARSE_FLAG_ONEDASH) )
    1378           0 :           writestrings (0, "\n(A single dash may be used "
    1379             :                         "instead of the double ones)\n", NULL);
    1380             :     }
    1381           0 :   if ( (s=strusage(19)) )
    1382             :     {
    1383           0 :       writestrings (0, "\n", NULL);
    1384           0 :       writestrings (0, s, NULL);
    1385             :     }
    1386           0 :   flushstrings (0);
    1387           0 :   exit(0);
    1388             : }
    1389             : 
    1390             : static void
    1391           0 : show_version ()
    1392             : {
    1393             :   const char *s;
    1394             :   int i;
    1395             : 
    1396             :   /* Version line.  */
    1397           0 :   writestrings (0, strusage (11), NULL);
    1398           0 :   if ((s=strusage (12)))
    1399           0 :     writestrings (0, " (", s, ")", NULL);
    1400           0 :   writestrings (0, " ", strusage (13), "\n", NULL);
    1401             :   /* Additional version lines. */
    1402           0 :   for (i=20; i < 30; i++)
    1403           0 :     if ((s=strusage (i)))
    1404           0 :       writestrings (0, s, "\n", NULL);
    1405             :   /* Copyright string.  */
    1406           0 :   if ((s=strusage (14)))
    1407           0 :     writestrings (0, s, "\n", NULL);
    1408             :   /* Licence string.  */
    1409           0 :   if( (s=strusage (10)) )
    1410           0 :     writestrings (0, s, "\n", NULL);
    1411             :   /* Copying conditions. */
    1412           0 :   if ( (s=strusage(15)) )
    1413           0 :     writestrings (0, s, NULL);
    1414             :   /* Thanks. */
    1415           0 :   if ((s=strusage(18)))
    1416           0 :     writestrings (0, s, NULL);
    1417             :   /* Additional program info. */
    1418           0 :   for (i=30; i < 40; i++ )
    1419           0 :     if ( (s=strusage (i)) )
    1420           0 :       writestrings (0, s, NULL);
    1421           0 :   flushstrings (0);
    1422           0 : }
    1423             : 
    1424             : 
    1425             : void
    1426           0 : usage (int level)
    1427             : {
    1428             :   const char *p;
    1429             : 
    1430           0 :   if (!level)
    1431             :     {
    1432           0 :       writestrings (1, strusage(11), " ", strusage(13), "; ",
    1433             :                     strusage (14), "\n", NULL);
    1434           0 :       flushstrings (1);
    1435             :     }
    1436           0 :   else if (level == 1)
    1437             :     {
    1438           0 :       p = strusage (40);
    1439           0 :       writestrings (1, p, NULL);
    1440           0 :       if (*p && p[strlen(p)] != '\n')
    1441           0 :         writestrings (1, "\n", NULL);
    1442           0 :       exit (2);
    1443             :     }
    1444           0 :   else if (level == 2)
    1445             :     {
    1446           0 :       p = strusage (42);
    1447           0 :       if (p && *p == '1')
    1448             :         {
    1449           0 :           p = strusage (40);
    1450           0 :           writestrings (1, p, NULL);
    1451           0 :           if (*p && p[strlen(p)] != '\n')
    1452           0 :             writestrings (1, "\n", NULL);
    1453             :         }
    1454           0 :       writestrings (0, strusage(41), "\n", NULL);
    1455           0 :       exit (0);
    1456             :     }
    1457           0 : }
    1458             : 
    1459             : /* Level
    1460             :  *     0: Print copyright string to stderr
    1461             :  *     1: Print a short usage hint to stderr and terminate
    1462             :  *     2: Print a long usage hint to stdout and terminate
    1463             :  *    10: Return license info string
    1464             :  *    11: Return the name of the program
    1465             :  *    12: Return optional name of package which includes this program.
    1466             :  *    13: version  string
    1467             :  *    14: copyright string
    1468             :  *    15: Short copying conditions (with LFs)
    1469             :  *    16: Long copying conditions (with LFs)
    1470             :  *    17: Optional printable OS name
    1471             :  *    18: Optional thanks list (with LFs)
    1472             :  *    19: Bug report info
    1473             :  *20..29: Additional lib version strings.
    1474             :  *30..39: Additional program info (with LFs)
    1475             :  *    40: short usage note (with LF)
    1476             :  *    41: long usage note (with LF)
    1477             :  *    42: Flag string:
    1478             :  *          First char is '1':
    1479             :  *             The short usage notes needs to be printed
    1480             :  *             before the long usage note.
    1481             :  */
    1482             : const char *
    1483           0 : strusage( int level )
    1484             : {
    1485           0 :   const char *p = strusage_handler? strusage_handler(level) : NULL;
    1486             : 
    1487           0 :   if ( p )
    1488           0 :     return map_static_macro_string (p);
    1489             : 
    1490           0 :   switch ( level )
    1491             :     {
    1492             : 
    1493             :     case 10:
    1494             : #if ARGPARSE_GPL_VERSION == 3
    1495             :       p = ("License GPLv3+: GNU GPL version 3 or later "
    1496             :            "<http://gnu.org/licenses/gpl.html>");
    1497             : #else
    1498           0 :       p = ("License GPLv2+: GNU GPL version 2 or later "
    1499             :            "<http://gnu.org/licenses/>");
    1500             : #endif
    1501           0 :       break;
    1502           0 :     case 11: p = "foo"; break;
    1503           0 :     case 13: p = "0.0"; break;
    1504           0 :     case 14: p = ARGPARSE_CRIGHT_STR; break;
    1505           0 :     case 15: p =
    1506             : "This is free software: you are free to change and redistribute it.\n"
    1507             : "There is NO WARRANTY, to the extent permitted by law.\n";
    1508           0 :       break;
    1509           0 :     case 16: p =
    1510             : "This is free software; you can redistribute it and/or modify\n"
    1511             : "it under the terms of the GNU General Public License as published by\n"
    1512             : "the Free Software Foundation; either version "
    1513             : ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
    1514             : " of the License, or\n"
    1515             : "(at your option) any later version.\n\n"
    1516             : "It is distributed in the hope that it will be useful,\n"
    1517             : "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    1518             : "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
    1519             : "GNU General Public License for more details.\n\n"
    1520             : "You should have received a copy of the GNU General Public License\n"
    1521             : "along with this software.  If not, see <https://www.gnu.org/licenses/>.\n";
    1522           0 :       break;
    1523             :     case 40: /* short and long usage */
    1524           0 :     case 41: p = ""; break;
    1525             :     }
    1526             : 
    1527           0 :   return p;
    1528             : }
    1529             : 
    1530             : 
    1531             : /* Set the usage handler.  This function is basically a constructor.  */
    1532             : void
    1533           0 : set_strusage ( const char *(*f)( int ) )
    1534             : {
    1535           0 :   strusage_handler = f;
    1536           0 : }
    1537             : 
    1538             : 
    1539             : #ifdef TEST
    1540             : static struct {
    1541             :     int verbose;
    1542             :     int debug;
    1543             :     char *outfile;
    1544             :     char *crf;
    1545             :     int myopt;
    1546             :     int echo;
    1547             :     int a_long_one;
    1548             : } opt;
    1549             : 
    1550             : int
    1551             : main(int argc, char **argv)
    1552             : {
    1553             :   ARGPARSE_OPTS opts[] = {
    1554             :     ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"),
    1555             :     ARGPARSE_s_n('e', "echo"   , ("Zeile ausgeben, damit wir sehen, "
    1556             :                                   "was wir eingegeben haben")),
    1557             :     ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
    1558             :     ARGPARSE_s_s('o', "output", 0 ),
    1559             :     ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ),
    1560             :     /* Note that on a non-utf8 terminal the ß might garble the output. */
    1561             :     ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
    1562             :     ARGPARSE_o_i('m', "my-option", 0),
    1563             :     ARGPARSE_s_n(500, "a-long-option", 0 ),
    1564             :     ARGPARSE_end()
    1565             :   };
    1566             :   ARGPARSE_ARGS pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL
    1567             :                                          | ARGPARSE_FLAG_MIXED
    1568             :                                          | ARGPARSE_FLAG_ONEDASH) };
    1569             :   int i;
    1570             : 
    1571             :   while (arg_parse  (&pargs, opts))
    1572             :     {
    1573             :       switch (pargs.r_opt)
    1574             :         {
    1575             :         case ARGPARSE_IS_ARG :
    1576             :           printf ("arg='%s'\n", pargs.r.ret_str);
    1577             :           break;
    1578             :         case 'v': opt.verbose++; break;
    1579             :         case 'e': opt.echo++; break;
    1580             :         case 'd': opt.debug++; break;
    1581             :         case 'o': opt.outfile = pargs.r.ret_str; break;
    1582             :         case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
    1583             :         case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
    1584             :         case 500: opt.a_long_one++;  break;
    1585             :         default : pargs.err = ARGPARSE_PRINT_WARNING; break;
    1586             :         }
    1587             :     }
    1588             :   for (i=0; i < argc; i++ )
    1589             :     printf ("%3d -> (%s)\n", i, argv[i] );
    1590             :   puts ("Options:");
    1591             :   if (opt.verbose)
    1592             :     printf ("  verbose=%d\n", opt.verbose );
    1593             :   if (opt.debug)
    1594             :     printf ("  debug=%d\n", opt.debug );
    1595             :   if (opt.outfile)
    1596             :     printf ("  outfile='%s'\n", opt.outfile );
    1597             :   if (opt.crf)
    1598             :     printf ("  crffile='%s'\n", opt.crf );
    1599             :   if (opt.myopt)
    1600             :     printf ("  myopt=%d\n", opt.myopt );
    1601             :   if (opt.a_long_one)
    1602             :     printf ("  a-long-one=%d\n", opt.a_long_one );
    1603             :   if (opt.echo)
    1604             :     printf ("  echo=%d\n", opt.echo );
    1605             : 
    1606             :   return 0;
    1607             : }
    1608             : #endif /*TEST*/
    1609             : 
    1610             : /**** bottom of file ****/

Generated by: LCOV version 1.11