build: Require latest released libraries
[gnupg.git] / common / argparse.c
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 argparse_register_outfnc (int (*fnc)(int, const char *))
293 {
294   custom_outfnc = fnc;
295 }
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 writestrings (int is_error, const char *string, ...)
303 {
304   va_list arg_ptr;
305   const char *s;
306   int count = 0;
307
308   if (string)
309     {
310       s = string;
311       va_start (arg_ptr, string);
312       do
313         {
314           if (custom_outfnc)
315             custom_outfnc (is_error? 2:1, s);
316           else
317             fputs (s, is_error? stderr : stdout);
318           count += strlen (s);
319         }
320       while ((s = va_arg (arg_ptr, const char *)));
321       va_end (arg_ptr);
322     }
323   return count;
324 }
325
326
327 static void
328 flushstrings (int is_error)
329 {
330   if (custom_outfnc)
331     custom_outfnc (is_error? 2:1, NULL);
332   else
333     fflush (is_error? stderr : stdout);
334 }
335
336
337 static void
338 initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
339 {
340   if( !(arg->flags & (1<<15)) )
341     {
342       /* Initialize this instance. */
343       arg->internal.idx = 0;
344       arg->internal.last = NULL;
345       arg->internal.inarg = 0;
346       arg->internal.stopped = 0;
347       arg->internal.aliases = NULL;
348       arg->internal.cur_alias = NULL;
349       arg->internal.iio_list = NULL;
350       arg->err = 0;
351       arg->flags |= 1<<15; /* Mark as initialized.  */
352       if ( *arg->argc < 0 )
353         log_bug ("invalid argument for arg_parse\n");
354     }
355
356
357   if (arg->err)
358     {
359       /* Last option was erroneous.  */
360       const char *s;
361
362       if (filename)
363         {
364           if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
365             s = _("argument not expected");
366           else if ( arg->r_opt == ARGPARSE_READ_ERROR )
367             s = _("read error");
368           else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG )
369             s = _("keyword too long");
370           else if ( arg->r_opt == ARGPARSE_MISSING_ARG )
371             s = _("missing argument");
372           else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
373             s = _("invalid argument");
374           else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
375             s = _("invalid command");
376           else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS )
377             s = _("invalid alias definition");
378           else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
379             s = _("out of core");
380           else
381             s = _("invalid option");
382           log_error ("%s:%u: %s\n", filename, *lineno, s);
383         }
384       else
385         {
386           s = arg->internal.last? arg->internal.last:"[??]";
387
388           if ( arg->r_opt == ARGPARSE_MISSING_ARG )
389             log_error (_("missing argument for option \"%.50s\"\n"), s);
390           else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
391             log_error (_("invalid argument for option \"%.50s\"\n"), s);
392           else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
393             log_error (_("option \"%.50s\" does not expect an argument\n"), s);
394           else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
395             log_error (_("invalid command \"%.50s\"\n"), s);
396           else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )
397             log_error (_("option \"%.50s\" is ambiguous\n"), s);
398           else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND )
399             log_error (_("command \"%.50s\" is ambiguous\n"),s );
400           else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
401             log_error ("%s\n", _("out of core\n"));
402           else
403             log_error (_("invalid option \"%.50s\"\n"), s);
404         }
405       if (arg->err != ARGPARSE_PRINT_WARNING)
406         exit (2);
407       arg->err = 0;
408     }
409
410   /* Zero out the return value union.  */
411   arg->r.ret_str = NULL;
412   arg->r.ret_long = 0;
413 }
414
415
416 static void
417 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 }
434
435
436 /* Return true if KEYWORD is in the ignore-invalid-option list.  */
437 static int
438 ignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword)
439 {
440   IIO_ITEM_DEF item = arg->internal.iio_list;
441
442   for (; item; item = item->next)
443     if (!strcmp (item->name, keyword))
444       return 1;
445   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 ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp)
455 {
456   IIO_ITEM_DEF item;
457   int c;
458   char name[100];
459   int namelen = 0;
460   int ready = 0;
461   enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS;
462
463   while (!ready)
464     {
465       c = getc (fp);
466       if (c == '\n')
467         ready = 1;
468       else if (c == EOF)
469         {
470           c = '\n';
471           ready = 1;
472         }
473     again:
474       switch (state)
475         {
476         case skipWS:
477           if (!isascii (c) || !isspace(c))
478             {
479               namelen = 0;
480               state = collectNAME;
481               goto again;
482             }
483           break;
484
485         case collectNAME:
486           if (isspace (c))
487             {
488               state = addNAME;
489               goto again;
490             }
491           else if (namelen < DIM(name)-1)
492             name[namelen++] = c;
493           else /* Too long.  */
494             state = skipNAME;
495           break;
496
497         case skipNAME:
498           if (isspace (c))
499             {
500               state = skipWS;
501               goto again;
502             }
503           break;
504
505         case addNAME:
506           name[namelen] = 0;
507           if (!ignore_invalid_option_p (arg, name))
508             {
509               item = xtrymalloc (sizeof *item + namelen);
510               if (!item)
511                 return 1;
512               strcpy (item->name, name);
513               item->next = (IIO_ITEM_DEF)arg->internal.iio_list;
514               arg->internal.iio_list = item;
515             }
516           state = skipWS;
517           goto again;
518         }
519     }
520   return 0;
521 }
522
523
524 /* Clear the entire ignore-invalid-option list.  */
525 static void
526 ignore_invalid_option_clear (ARGPARSE_ARGS *arg)
527 {
528   IIO_ITEM_DEF item, tmpitem;
529
530   for (item = arg->internal.iio_list; item; item = tmpitem)
531     {
532       tmpitem = item->next;
533       xfree (item);
534     }
535   arg->internal.iio_list = NULL;
536 }
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 optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
563                ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
564 {
565   int state, i, c;
566   int idx=0;
567   char keyword[100];
568   char *buffer = NULL;
569   size_t buflen = 0;
570   int in_alias=0;
571
572   if (!fp) /* Divert to to arg_parse() in this case.  */
573     return arg_parse (arg, opts);
574
575   initialize (arg, filename, lineno);
576
577   /* Find the next keyword.  */
578   state = i = 0;
579   for (;;)
580     {
581       c = getc (fp);
582       if (c == '\n' || c== EOF )
583         {
584           if ( c != EOF )
585             ++*lineno;
586           if (state == -1)
587             break;
588           else if (state == 2)
589             {
590               keyword[i] = 0;
591               for (i=0; opts[i].short_opt; i++ )
592                 {
593                   if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
594                     break;
595                 }
596               idx = i;
597               arg->r_opt = opts[idx].short_opt;
598               if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
599                 {
600                   state = i = 0;
601                   continue;
602                 }
603               else if (!opts[idx].short_opt )
604                 {
605                   if (!strcmp (keyword, "ignore-invalid-option"))
606                     {
607                       /* No argument - ignore this meta option.  */
608                       state = i = 0;
609                       continue;
610                     }
611                   else if (ignore_invalid_option_p (arg, keyword))
612                     {
613                       /* This invalid option is in the iio list.  */
614                       state = i = 0;
615                       continue;
616                     }
617                   arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
618                                 ? ARGPARSE_INVALID_COMMAND
619                                 : ARGPARSE_INVALID_OPTION);
620                 }
621               else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
622                 arg->r_type = 0; /* Does not take an arg. */
623               else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) )
624                 arg->r_type = 0; /* Arg is optional.  */
625               else
626                 arg->r_opt = ARGPARSE_MISSING_ARG;
627
628               break;
629             }
630           else if (state == 3)
631             {
632               /* No argument found.  */
633               if (in_alias)
634                 arg->r_opt = ARGPARSE_MISSING_ARG;
635               else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
636                 arg->r_type = 0; /* Does not take an arg. */
637               else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
638                 arg->r_type = 0; /* No optional argument. */
639               else
640                 arg->r_opt = ARGPARSE_MISSING_ARG;
641
642               break;
643             }
644           else if (state == 4)
645             {
646               /* Has an argument. */
647               if (in_alias)
648                 {
649                   if (!buffer)
650                     arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
651                   else
652                     {
653                       char *p;
654
655                       buffer[i] = 0;
656                       p = strpbrk (buffer, " \t");
657                       if (p)
658                         {
659                           *p++ = 0;
660                           trim_spaces (p);
661                         }
662                       if (!p || !*p)
663                         {
664                           xfree (buffer);
665                           arg->r_opt = ARGPARSE_INVALID_ALIAS;
666                         }
667                       else
668                         {
669                           store_alias (arg, buffer, p);
670                         }
671                     }
672                 }
673               else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
674                 arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
675               else
676                 {
677                   char *p;
678
679                   if (!buffer)
680                     {
681                       keyword[i] = 0;
682                       buffer = xtrystrdup (keyword);
683                       if (!buffer)
684                         arg->r_opt = ARGPARSE_OUT_OF_CORE;
685                     }
686                   else
687                     buffer[i] = 0;
688
689                   if (buffer)
690                     {
691                       trim_spaces (buffer);
692                       p = buffer;
693                       if (*p == '"')
694                         {
695                           /* Remove quotes. */
696                           p++;
697                           if (*p && p[strlen(p)-1] == '\"' )
698                             p[strlen(p)-1] = 0;
699                         }
700                       if (!set_opt_arg (arg, opts[idx].flags, p))
701                         xfree (buffer);
702                       else
703                         gpgrt_annotate_leaked_object (buffer);
704                     }
705                 }
706               break;
707             }
708           else if (c == EOF)
709             {
710               ignore_invalid_option_clear (arg);
711               if (ferror (fp))
712                 arg->r_opt = ARGPARSE_READ_ERROR;
713               else
714                 arg->r_opt = 0; /* EOF. */
715               break;
716             }
717           state = 0;
718           i = 0;
719         }
720       else if (state == -1)
721         ; /* Skip. */
722       else if (state == 0 && isascii (c) && isspace(c))
723         ; /* Skip leading white space.  */
724       else if (state == 0 && c == '#' )
725         state = 1;      /* Start of a comment.  */
726       else if (state == 1)
727         ; /* Skip comments. */
728       else if (state == 2 && isascii (c) && isspace(c))
729         {
730           /* Check keyword.  */
731           keyword[i] = 0;
732           for (i=0; opts[i].short_opt; i++ )
733             if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
734               break;
735           idx = i;
736           arg->r_opt = opts[idx].short_opt;
737           if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
738             {
739               state = 1; /* Process like a comment.  */
740             }
741           else if (!opts[idx].short_opt)
742             {
743               if (!strcmp (keyword, "alias"))
744                 {
745                   in_alias = 1;
746                   state = 3;
747                 }
748               else if (!strcmp (keyword, "ignore-invalid-option"))
749                 {
750                   if (ignore_invalid_option_add (arg, fp))
751                     {
752                       arg->r_opt = ARGPARSE_OUT_OF_CORE;
753                       break;
754                     }
755                   state = i = 0;
756                   ++*lineno;
757                 }
758               else if (ignore_invalid_option_p (arg, keyword))
759                 state = 1; /* Process like a comment.  */
760               else
761                 {
762                   arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
763                                 ? ARGPARSE_INVALID_COMMAND
764                                 : ARGPARSE_INVALID_OPTION);
765                   state = -1; /* Skip rest of line and leave.  */
766                 }
767             }
768           else
769             state = 3;
770         }
771       else if (state == 3)
772         {
773           /* Skip leading spaces of the argument.  */
774           if (!isascii (c) || !isspace(c))
775             {
776               i = 0;
777               keyword[i++] = c;
778               state = 4;
779             }
780         }
781       else if (state == 4)
782         {
783           /* Collect the argument. */
784           if (buffer)
785             {
786               if (i < buflen-1)
787                 buffer[i++] = c;
788               else
789                 {
790                   char *tmp;
791                   size_t tmplen = buflen + 50;
792
793                   tmp = xtryrealloc (buffer, tmplen);
794                   if (tmp)
795                     {
796                       buflen = tmplen;
797                       buffer = tmp;
798                       buffer[i++] = c;
799                     }
800                   else
801                     {
802                       xfree (buffer);
803                       arg->r_opt = ARGPARSE_OUT_OF_CORE;
804                       break;
805                     }
806                 }
807             }
808           else if (i < DIM(keyword)-1)
809             keyword[i++] = c;
810           else
811             {
812               size_t tmplen = DIM(keyword) + 50;
813               buffer = xtrymalloc (tmplen);
814               if (buffer)
815                 {
816                   buflen = tmplen;
817                   memcpy(buffer, keyword, i);
818                   buffer[i++] = c;
819                 }
820               else
821                 {
822                   arg->r_opt = ARGPARSE_OUT_OF_CORE;
823                   break;
824                 }
825             }
826         }
827       else if (i >= DIM(keyword)-1)
828         {
829           arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
830           state = -1; /* Skip rest of line and leave.  */
831         }
832       else
833         {
834           keyword[i++] = c;
835           state = 2;
836         }
837     }
838
839   return arg->r_opt;
840 }
841
842
843
844 static int
845 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     if( !*keyword )
858         return -1;
859     for(i=0; opts[i].short_opt; i++ )
860         if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
861             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     n = strlen( keyword );
878     for(i=0; opts[i].short_opt; i++ ) {
879         if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) {
880             int j;
881             for(j=i+1; opts[j].short_opt; j++ ) {
882                 if( opts[j].long_opt
883                     && !strncmp( opts[j].long_opt, keyword, n ) )
884                     return -2;  /* abbreviation is ambiguous */
885             }
886             return i;
887         }
888     }
889     return -1;  /* Not found.  */
890 }
891
892 int
893 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   initialize( arg, NULL, NULL );
902   argc = *arg->argc;
903   argv = *arg->argv;
904   idx = arg->internal.idx;
905
906   if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
907     {
908       /* Skip the first argument.  */
909       argc--; argv++; idx++;
910     }
911
912  next_one:
913   if (!argc)
914     {
915       /* No more args.  */
916       arg->r_opt = 0;
917       goto leave; /* Ready. */
918     }
919
920   s = *argv;
921   arg->internal.last = s;
922
923   if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL))
924     {
925       arg->r_opt = ARGPARSE_IS_ARG;  /* Not an option but an argument.  */
926       arg->r_type = 2;
927       arg->r.ret_str = s;
928       argc--; argv++; idx++; /* set to next one */
929     }
930   else if( arg->internal.stopped )
931     {
932       arg->r_opt = 0;
933       goto leave; /* Ready.  */
934     }
935   else if ( *s == '-' && s[1] == '-' )
936     {
937       /* Long option.  */
938       char *argpos;
939
940       arg->internal.inarg = 0;
941       if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
942         {
943           /* Stop option processing.  */
944           arg->internal.stopped = 1;
945           arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
946           argc--; argv++; idx++;
947           goto next_one;
948         }
949
950       argpos = strchr( s+2, '=' );
951       if ( argpos )
952         *argpos = 0;
953       i = find_long_option ( arg, opts, s+2 );
954       if ( argpos )
955         *argpos = '=';
956
957       if ( i < 0 && !strcmp ( "help", s+2) )
958         show_help (opts, arg->flags);
959       else if ( i < 0 && !strcmp ( "version", s+2) )
960         {
961           if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
962             {
963               show_version ();
964               exit(0);
965             }
966         }
967       else if ( i < 0 && !strcmp( "warranty", s+2))
968         {
969           writestrings (0, strusage (16), "\n", NULL);
970           exit (0);
971         }
972       else if ( i < 0 && !strcmp( "dump-options", s+2) )
973         {
974           for (i=0; opts[i].short_opt; i++ )
975             {
976               if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
977                 writestrings (0, "--", opts[i].long_opt, "\n", NULL);
978             }
979           writestrings (0, "--dump-options\n--help\n--version\n--warranty\n",
980                         NULL);
981           exit (0);
982         }
983
984       if ( i == -2 )
985         arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
986       else if ( i == -1 )
987         {
988           arg->r_opt = ARGPARSE_INVALID_OPTION;
989           arg->r.ret_str = s+2;
990         }
991       else
992         arg->r_opt = opts[i].short_opt;
993       if ( i < 0 )
994         ;
995       else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
996         {
997           if ( argpos )
998             {
999               s2 = argpos+1;
1000               if ( !*s2 )
1001                 s2 = NULL;
1002             }
1003           else
1004             s2 = argv[1];
1005           if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1006             {
1007               arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional.  */
1008             }
1009           else if ( !s2 )
1010             {
1011               arg->r_opt = ARGPARSE_MISSING_ARG;
1012             }
1013           else if ( !argpos && *s2 == '-'
1014                     && (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               arg->r_type = ARGPARSE_TYPE_NONE;
1020             }
1021           else
1022             {
1023               set_opt_arg (arg, opts[i].flags, s2);
1024               if ( !argpos )
1025                 {
1026                   argc--; argv++; idx++; /* Skip one.  */
1027                 }
1028             }
1029         }
1030       else
1031         {
1032           /* Does not take an argument. */
1033           if ( argpos )
1034             arg->r_type = ARGPARSE_UNEXPECTED_ARG;
1035           else
1036             arg->r_type = 0;
1037         }
1038       argc--; argv++; idx++; /* Set to next one.  */
1039     }
1040     else if ( (*s == '-' && s[1]) || arg->internal.inarg )
1041       {
1042         /* Short option.  */
1043         int dash_kludge = 0;
1044
1045         i = 0;
1046         if ( !arg->internal.inarg )
1047           {
1048             arg->internal.inarg++;
1049             if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
1050               {
1051                 for (i=0; opts[i].short_opt; i++ )
1052                   if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1))
1053                     {
1054                       dash_kludge = 1;
1055                       break;
1056                     }
1057               }
1058           }
1059         s += arg->internal.inarg;
1060
1061         if (!dash_kludge )
1062           {
1063             for (i=0; opts[i].short_opt; i++ )
1064               if ( opts[i].short_opt == *s )
1065                 break;
1066           }
1067
1068         if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
1069           show_help (opts, arg->flags);
1070
1071         arg->r_opt = opts[i].short_opt;
1072         if (!opts[i].short_opt )
1073           {
1074             arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
1075               ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
1076             arg->internal.inarg++; /* Point to the next arg.  */
1077             arg->r.ret_str = s;
1078           }
1079         else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
1080           {
1081             if ( s[1] && !dash_kludge )
1082               {
1083                 s2 = s+1;
1084                 set_opt_arg (arg, opts[i].flags, s2);
1085               }
1086             else
1087               {
1088                 s2 = argv[1];
1089                 if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1090                   {
1091                     arg->r_type = ARGPARSE_TYPE_NONE;
1092                   }
1093                 else if ( !s2 )
1094                   {
1095                     arg->r_opt = ARGPARSE_MISSING_ARG;
1096                   }
1097                 else if ( *s2 == '-' && s2[1]
1098                           && (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                     arg->r_type = ARGPARSE_TYPE_NONE;
1104                   }
1105                 else
1106                   {
1107                     set_opt_arg (arg, opts[i].flags, s2);
1108                     argc--; argv++; idx++; /* Skip one.  */
1109                   }
1110               }
1111             s = "x"; /* This is so that !s[1] yields false.  */
1112           }
1113         else
1114           {
1115             /* Does not take an argument.  */
1116             arg->r_type = ARGPARSE_TYPE_NONE;
1117             arg->internal.inarg++; /* Point to the next arg.  */
1118           }
1119         if ( !s[1] || dash_kludge )
1120           {
1121             /* No more concatenated short options.  */
1122             arg->internal.inarg = 0;
1123             argc--; argv++; idx++;
1124           }
1125       }
1126   else if ( arg->flags & ARGPARSE_FLAG_MIXED )
1127     {
1128       arg->r_opt = ARGPARSE_IS_ARG;
1129       arg->r_type = 2;
1130       arg->r.ret_str = s;
1131       argc--; argv++; idx++; /* Set to next one.  */
1132     }
1133   else
1134     {
1135       arg->internal.stopped = 1; /* Stop option processing.  */
1136       goto next_one;
1137     }
1138
1139  leave:
1140   *arg->argc = argc;
1141   *arg->argv = argv;
1142   arg->internal.idx = idx;
1143   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 set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s)
1151 {
1152   int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
1153   long l;
1154
1155   switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
1156     {
1157     case ARGPARSE_TYPE_LONG:
1158     case ARGPARSE_TYPE_INT:
1159       errno = 0;
1160       l = strtol (s, NULL, base);
1161       if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)
1162         {
1163           arg->r_opt = ARGPARSE_INVALID_ARG;
1164           return -1;
1165         }
1166       if (arg->r_type == ARGPARSE_TYPE_LONG)
1167         arg->r.ret_long = l;
1168       else if ( (l < 0 && l < INT_MIN) || l > INT_MAX )
1169         {
1170           arg->r_opt = ARGPARSE_INVALID_ARG;
1171           return -1;
1172         }
1173       else
1174         arg->r.ret_int = (int)l;
1175       return 0;
1176
1177     case ARGPARSE_TYPE_ULONG:
1178       while (isascii (*s) && isspace(*s))
1179         s++;
1180       if (*s == '-')
1181         {
1182           arg->r.ret_ulong = 0;
1183           arg->r_opt = ARGPARSE_INVALID_ARG;
1184           return -1;
1185         }
1186       errno = 0;
1187       arg->r.ret_ulong = strtoul (s, NULL, base);
1188       if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE)
1189         {
1190           arg->r_opt = ARGPARSE_INVALID_ARG;
1191           return -1;
1192         }
1193       return 0;
1194
1195     case ARGPARSE_TYPE_STRING:
1196     default:
1197       arg->r.ret_str = s;
1198       return 1;
1199     }
1200 }
1201
1202
1203 static size_t
1204 long_opt_strlen( ARGPARSE_OPTS *o )
1205 {
1206   size_t n = strlen (o->long_opt);
1207
1208   if ( o->description && *o->description == '|' )
1209     {
1210       const char *s;
1211       int is_utf8 = is_native_utf8 ();
1212
1213       s=o->description+1;
1214       if ( *s != '=' )
1215         n++;
1216       /* For a (mostly) correct length calculation we exclude
1217          continuation bytes (10xxxxxx) if we are on a native utf8
1218          terminal. */
1219       for (; *s && *s != '|'; s++ )
1220         if ( is_utf8 && (*s&0xc0) != 0x80 )
1221           n++;
1222     }
1223   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 show_help (ARGPARSE_OPTS *opts, unsigned int flags)
1240 {
1241   const char *s;
1242   char tmp[2];
1243
1244   show_version ();
1245   writestrings (0, "\n", NULL);
1246   s = strusage (42);
1247   if (s && *s == '1')
1248     {
1249       s = strusage (40);
1250       writestrings (1, s, NULL);
1251       if (*s && s[strlen(s)] != '\n')
1252         writestrings (1, "\n", NULL);
1253     }
1254   s = strusage(41);
1255   writestrings (0, s, "\n", NULL);
1256   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       for (i=indent=0; opts[i].short_opt; i++ )
1263         {
1264           if ( opts[i].long_opt )
1265             if ( !opts[i].description || *opts[i].description != '@' )
1266               if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
1267                 indent = j;
1268         }
1269
1270       /* Example: " -v, --verbose   Viele Sachen ausgeben" */
1271       indent += 10;
1272       if ( *opts[0].description != '@' )
1273         writestrings (0, "Options:", "\n", NULL);
1274       for (i=0; opts[i].short_opt; i++ )
1275         {
1276           s = map_static_macro_string (_( opts[i].description ));
1277           if ( s && *s== '@' && !s[1] ) /* Hide this line.  */
1278             continue;
1279           if ( s && *s == '@' )  /* Unindented comment only line.  */
1280             {
1281               for (s++; *s; s++ )
1282                 {
1283                   if ( *s == '\n' )
1284                     {
1285                       if( s[1] )
1286                         writestrings (0, "\n", NULL);
1287                     }
1288                   else
1289                     {
1290                       tmp[0] = *s;
1291                       tmp[1] = 0;
1292                       writestrings (0, tmp, NULL);
1293                     }
1294                 }
1295               writestrings (0, "\n", NULL);
1296               continue;
1297             }
1298
1299           j = 3;
1300           if ( opts[i].short_opt < 256 )
1301             {
1302               tmp[0] = opts[i].short_opt;
1303               tmp[1] = 0;
1304               writestrings (0, " -", tmp, NULL );
1305               if ( !opts[i].long_opt )
1306                 {
1307                   if (s && *s == '|' )
1308                     {
1309                       writestrings (0, " ", NULL); j++;
1310                       for (s++ ; *s && *s != '|'; s++, j++ )
1311                         {
1312                           tmp[0] = *s;
1313                           tmp[1] = 0;
1314                           writestrings (0, tmp, NULL);
1315                         }
1316                       if ( *s )
1317                         s++;
1318                     }
1319                 }
1320             }
1321           else
1322             writestrings (0, "   ", NULL);
1323           if ( opts[i].long_opt )
1324             {
1325               tmp[0] = opts[i].short_opt < 256?',':' ';
1326               tmp[1] = 0;
1327               j += writestrings (0, tmp, " --", opts[i].long_opt, NULL);
1328               if (s && *s == '|' )
1329                 {
1330                   if ( *++s != '=' )
1331                     {
1332                       writestrings (0, " ", NULL);
1333                       j++;
1334                     }
1335                   for ( ; *s && *s != '|'; s++, j++ )
1336                     {
1337                       tmp[0] = *s;
1338                       tmp[1] = 0;
1339                       writestrings (0, tmp, NULL);
1340                     }
1341                   if ( *s )
1342                     s++;
1343                 }
1344               writestrings (0, "   ", NULL);
1345               j += 3;
1346             }
1347           for (;j < indent; j++ )
1348             writestrings (0, " ", NULL);
1349           if ( s )
1350             {
1351               if ( *s && j > indent )
1352                 {
1353                   writestrings (0, "\n", NULL);
1354                   for (j=0;j < indent; j++ )
1355                     writestrings (0, " ", NULL);
1356                 }
1357               for (; *s; s++ )
1358                 {
1359                   if ( *s == '\n' )
1360                     {
1361                       if ( s[1] )
1362                         {
1363                           writestrings (0, "\n", NULL);
1364                           for (j=0; j < indent; j++ )
1365                             writestrings (0, " ", NULL);
1366                         }
1367                     }
1368                   else
1369                     {
1370                       tmp[0] = *s;
1371                       tmp[1] = 0;
1372                       writestrings (0, tmp, NULL);
1373                     }
1374                 }
1375             }
1376           writestrings (0, "\n", NULL);
1377         }
1378         if ( (flags & ARGPARSE_FLAG_ONEDASH) )
1379           writestrings (0, "\n(A single dash may be used "
1380                         "instead of the double ones)\n", NULL);
1381     }
1382   if ( (s=strusage(19)) )
1383     {
1384       writestrings (0, "\n", NULL);
1385       writestrings (0, s, NULL);
1386     }
1387   flushstrings (0);
1388   exit(0);
1389 }
1390
1391 static void
1392 show_version ()
1393 {
1394   const char *s;
1395   int i;
1396
1397   /* Version line.  */
1398   writestrings (0, strusage (11), NULL);
1399   if ((s=strusage (12)))
1400     writestrings (0, " (", s, ")", NULL);
1401   writestrings (0, " ", strusage (13), "\n", NULL);
1402   /* Additional version lines. */
1403   for (i=20; i < 30; i++)
1404     if ((s=strusage (i)))
1405       writestrings (0, s, "\n", NULL);
1406   /* Copyright string.  */
1407   if ((s=strusage (14)))
1408     writestrings (0, s, "\n", NULL);
1409   /* Licence string.  */
1410   if( (s=strusage (10)) )
1411     writestrings (0, s, "\n", NULL);
1412   /* Copying conditions. */
1413   if ( (s=strusage(15)) )
1414     writestrings (0, s, NULL);
1415   /* Thanks. */
1416   if ((s=strusage(18)))
1417     writestrings (0, s, NULL);
1418   /* Additional program info. */
1419   for (i=30; i < 40; i++ )
1420     if ( (s=strusage (i)) )
1421       writestrings (0, s, NULL);
1422   flushstrings (0);
1423 }
1424
1425
1426 void
1427 usage (int level)
1428 {
1429   const char *p;
1430
1431   if (!level)
1432     {
1433       writestrings (1, strusage(11), " ", strusage(13), "; ",
1434                     strusage (14), "\n", NULL);
1435       flushstrings (1);
1436     }
1437   else if (level == 1)
1438     {
1439       p = strusage (40);
1440       writestrings (1, p, NULL);
1441       if (*p && p[strlen(p)] != '\n')
1442         writestrings (1, "\n", NULL);
1443       exit (2);
1444     }
1445   else if (level == 2)
1446     {
1447       p = strusage (42);
1448       if (p && *p == '1')
1449         {
1450           p = strusage (40);
1451           writestrings (1, p, NULL);
1452           if (*p && p[strlen(p)] != '\n')
1453             writestrings (1, "\n", NULL);
1454         }
1455       writestrings (0, strusage(41), "\n", NULL);
1456       exit (0);
1457     }
1458 }
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 strusage( int level )
1485 {
1486   const char *p = strusage_handler? strusage_handler(level) : NULL;
1487
1488   if ( p )
1489     return map_static_macro_string (p);
1490
1491   switch ( level )
1492     {
1493
1494     case 10:
1495 #if ARGPARSE_GPL_VERSION == 3
1496       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       break;
1503     case 11: p = "foo"; break;
1504     case 13: p = "0.0"; break;
1505     case 14: p = ARGPARSE_CRIGHT_STR; break;
1506     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       break;
1510     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       break;
1524     case 40: /* short and long usage */
1525     case 41: p = ""; break;
1526     }
1527
1528   return p;
1529 }
1530
1531
1532 /* Set the usage handler.  This function is basically a constructor.  */
1533 void
1534 set_strusage ( const char *(*f)( int ) )
1535 {
1536   strusage_handler = f;
1537 }
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 ****/