python: Make EXTRA_DIST files explicit
[gpgme.git] / src / 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-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 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 problems 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 will 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                     }
703                 }
704               break;
705             }
706           else if (c == EOF)
707             {
708               ignore_invalid_option_clear (arg);
709               if (ferror (fp))
710                 arg->r_opt = ARGPARSE_READ_ERROR;
711               else
712                 arg->r_opt = 0; /* EOF. */
713               break;
714             }
715           state = 0;
716           i = 0;
717         }
718       else if (state == -1)
719         ; /* Skip. */
720       else if (state == 0 && isascii (c) && isspace(c))
721         ; /* Skip leading white space.  */
722       else if (state == 0 && c == '#' )
723         state = 1;      /* Start of a comment.  */
724       else if (state == 1)
725         ; /* Skip comments. */
726       else if (state == 2 && isascii (c) && isspace(c))
727         {
728           /* Check keyword.  */
729           keyword[i] = 0;
730           for (i=0; opts[i].short_opt; i++ )
731             if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
732               break;
733           idx = i;
734           arg->r_opt = opts[idx].short_opt;
735           if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
736             {
737               state = 1; /* Process like a comment.  */
738             }
739           else if (!opts[idx].short_opt)
740             {
741               if (!strcmp (keyword, "alias"))
742                 {
743                   in_alias = 1;
744                   state = 3;
745                 }
746               else if (!strcmp (keyword, "ignore-invalid-option"))
747                 {
748                   if (ignore_invalid_option_add (arg, fp))
749                     {
750                       arg->r_opt = ARGPARSE_OUT_OF_CORE;
751                       break;
752                     }
753                   state = i = 0;
754                   ++*lineno;
755                 }
756               else if (ignore_invalid_option_p (arg, keyword))
757                 state = 1; /* Process like a comment.  */
758               else
759                 {
760                   arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
761                                 ? ARGPARSE_INVALID_COMMAND
762                                 : ARGPARSE_INVALID_OPTION);
763                   state = -1; /* Skip rest of line and leave.  */
764                 }
765             }
766           else
767             state = 3;
768         }
769       else if (state == 3)
770         {
771           /* Skip leading spaces of the argument.  */
772           if (!isascii (c) || !isspace(c))
773             {
774               i = 0;
775               keyword[i++] = c;
776               state = 4;
777             }
778         }
779       else if (state == 4)
780         {
781           /* Collect the argument. */
782           if (buffer)
783             {
784               if (i < buflen-1)
785                 buffer[i++] = c;
786               else
787                 {
788                   char *tmp;
789                   size_t tmplen = buflen + 50;
790
791                   tmp = xtryrealloc (buffer, tmplen);
792                   if (tmp)
793                     {
794                       buflen = tmplen;
795                       buffer = tmp;
796                       buffer[i++] = c;
797                     }
798                   else
799                     {
800                       xfree (buffer);
801                       arg->r_opt = ARGPARSE_OUT_OF_CORE;
802                       break;
803                     }
804                 }
805             }
806           else if (i < DIM(keyword)-1)
807             keyword[i++] = c;
808           else
809             {
810               size_t tmplen = DIM(keyword) + 50;
811               buffer = xtrymalloc (tmplen);
812               if (buffer)
813                 {
814                   buflen = tmplen;
815                   memcpy(buffer, keyword, i);
816                   buffer[i++] = c;
817                 }
818               else
819                 {
820                   arg->r_opt = ARGPARSE_OUT_OF_CORE;
821                   break;
822                 }
823             }
824         }
825       else if (i >= DIM(keyword)-1)
826         {
827           arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
828           state = -1; /* Skip rest of line and leave.  */
829         }
830       else
831         {
832           keyword[i++] = c;
833           state = 2;
834         }
835     }
836
837   return arg->r_opt;
838 }
839
840
841
842 static int
843 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     if( !*keyword )
856         return -1;
857     for(i=0; opts[i].short_opt; i++ )
858         if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
859             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     n = strlen( keyword );
876     for(i=0; opts[i].short_opt; i++ ) {
877         if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) {
878             int j;
879             for(j=i+1; opts[j].short_opt; j++ ) {
880                 if( opts[j].long_opt
881                     && !strncmp( opts[j].long_opt, keyword, n ) )
882                     return -2;  /* abbreviation is ambiguous */
883             }
884             return i;
885         }
886     }
887     return -1;  /* Not found.  */
888 }
889
890 int
891 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   char string_with_x[] = "x";
899
900   initialize( arg, NULL, NULL );
901   argc = *arg->argc;
902   argv = *arg->argv;
903   idx = arg->internal.idx;
904
905   if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
906     {
907       /* Skip the first argument.  */
908       argc--; argv++; idx++;
909     }
910
911  next_one:
912   if (!argc)
913     {
914       /* No more args.  */
915       arg->r_opt = 0;
916       goto leave; /* Ready. */
917     }
918
919   s = *argv;
920   arg->internal.last = s;
921
922   if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL))
923     {
924       arg->r_opt = ARGPARSE_IS_ARG;  /* Not an option but an argument.  */
925       arg->r_type = 2;
926       arg->r.ret_str = s;
927       argc--; argv++; idx++; /* set to next one */
928     }
929   else if( arg->internal.stopped )
930     {
931       arg->r_opt = 0;
932       goto leave; /* Ready.  */
933     }
934   else if ( *s == '-' && s[1] == '-' )
935     {
936       /* Long option.  */
937       char *argpos;
938
939       arg->internal.inarg = 0;
940       if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
941         {
942           /* Stop option processing.  */
943           arg->internal.stopped = 1;
944           arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
945           argc--; argv++; idx++;
946           goto next_one;
947         }
948
949       argpos = strchr( s+2, '=' );
950       if ( argpos )
951         *argpos = 0;
952       i = find_long_option ( arg, opts, s+2 );
953       if ( argpos )
954         *argpos = '=';
955
956       if ( i < 0 && !strcmp ( "help", s+2) )
957         show_help (opts, arg->flags);
958       else if ( i < 0 && !strcmp ( "version", s+2) )
959         {
960           if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
961             {
962               show_version ();
963               exit(0);
964             }
965         }
966       else if ( i < 0 && !strcmp( "warranty", s+2))
967         {
968           writestrings (0, strusage (16), "\n", NULL);
969           exit (0);
970         }
971       else if ( i < 0 && !strcmp( "dump-options", s+2) )
972         {
973           for (i=0; opts[i].short_opt; i++ )
974             {
975               if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
976                 writestrings (0, "--", opts[i].long_opt, "\n", NULL);
977             }
978           writestrings (0, "--dump-options\n--help\n--version\n--warranty\n",
979                         NULL);
980           exit (0);
981         }
982
983       if ( i == -2 )
984         arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
985       else if ( i == -1 )
986         {
987           arg->r_opt = ARGPARSE_INVALID_OPTION;
988           arg->r.ret_str = s+2;
989         }
990       else
991         arg->r_opt = opts[i].short_opt;
992       if ( i < 0 )
993         ;
994       else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
995         {
996           if ( argpos )
997             {
998               s2 = argpos+1;
999               if ( !*s2 )
1000                 s2 = NULL;
1001             }
1002           else
1003             s2 = argv[1];
1004           if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1005             {
1006               arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional.  */
1007             }
1008           else if ( !s2 )
1009             {
1010               arg->r_opt = ARGPARSE_MISSING_ARG;
1011             }
1012           else if ( !argpos && *s2 == '-'
1013                     && (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               arg->r_type = ARGPARSE_TYPE_NONE;
1019             }
1020           else
1021             {
1022               set_opt_arg (arg, opts[i].flags, s2);
1023               if ( !argpos )
1024                 {
1025                   argc--; argv++; idx++; /* Skip one.  */
1026                 }
1027             }
1028         }
1029       else
1030         {
1031           /* Does not take an argument. */
1032           if ( argpos )
1033             arg->r_type = ARGPARSE_UNEXPECTED_ARG;
1034           else
1035             arg->r_type = 0;
1036         }
1037       argc--; argv++; idx++; /* Set to next one.  */
1038     }
1039     else if ( (*s == '-' && s[1]) || arg->internal.inarg )
1040       {
1041         /* Short option.  */
1042         int dash_kludge = 0;
1043
1044         i = 0;
1045         if ( !arg->internal.inarg )
1046           {
1047             arg->internal.inarg++;
1048             if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
1049               {
1050                 for (i=0; opts[i].short_opt; i++ )
1051                   if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1))
1052                     {
1053                       dash_kludge = 1;
1054                       break;
1055                     }
1056               }
1057           }
1058         s += arg->internal.inarg;
1059
1060         if (!dash_kludge )
1061           {
1062             for (i=0; opts[i].short_opt; i++ )
1063               if ( opts[i].short_opt == *s )
1064                 break;
1065           }
1066
1067         if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
1068           show_help (opts, arg->flags);
1069
1070         arg->r_opt = opts[i].short_opt;
1071         if (!opts[i].short_opt )
1072           {
1073             arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
1074               ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
1075             arg->internal.inarg++; /* Point to the next arg.  */
1076             arg->r.ret_str = s;
1077           }
1078         else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
1079           {
1080             if ( s[1] && !dash_kludge )
1081               {
1082                 s2 = s+1;
1083                 set_opt_arg (arg, opts[i].flags, s2);
1084               }
1085             else
1086               {
1087                 s2 = argv[1];
1088                 if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
1089                   {
1090                     arg->r_type = ARGPARSE_TYPE_NONE;
1091                   }
1092                 else if ( !s2 )
1093                   {
1094                     arg->r_opt = ARGPARSE_MISSING_ARG;
1095                   }
1096                 else if ( *s2 == '-' && s2[1]
1097                           && (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                     arg->r_type = ARGPARSE_TYPE_NONE;
1103                   }
1104                 else
1105                   {
1106                     set_opt_arg (arg, opts[i].flags, s2);
1107                     argc--; argv++; idx++; /* Skip one.  */
1108                   }
1109               }
1110             s = string_with_x; /* This is so that !s[1] yields false.  */
1111           }
1112         else
1113           {
1114             /* Does not take an argument.  */
1115             arg->r_type = ARGPARSE_TYPE_NONE;
1116             arg->internal.inarg++; /* Point to the next arg.  */
1117           }
1118         if ( !s[1] || dash_kludge )
1119           {
1120             /* No more concatenated short options.  */
1121             arg->internal.inarg = 0;
1122             argc--; argv++; idx++;
1123           }
1124       }
1125   else if ( arg->flags & ARGPARSE_FLAG_MIXED )
1126     {
1127       arg->r_opt = ARGPARSE_IS_ARG;
1128       arg->r_type = 2;
1129       arg->r.ret_str = s;
1130       argc--; argv++; idx++; /* Set to next one.  */
1131     }
1132   else
1133     {
1134       arg->internal.stopped = 1; /* Stop option processing.  */
1135       goto next_one;
1136     }
1137
1138  leave:
1139   *arg->argc = argc;
1140   *arg->argv = argv;
1141   arg->internal.idx = idx;
1142   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 set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s)
1150 {
1151   int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
1152   long l;
1153
1154   switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
1155     {
1156     case ARGPARSE_TYPE_LONG:
1157     case ARGPARSE_TYPE_INT:
1158       errno = 0;
1159       l = strtol (s, NULL, base);
1160       if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)
1161         {
1162           arg->r_opt = ARGPARSE_INVALID_ARG;
1163           return -1;
1164         }
1165       if (arg->r_type == ARGPARSE_TYPE_LONG)
1166         arg->r.ret_long = l;
1167       else if ( (l < 0 && l < INT_MIN) || l > INT_MAX )
1168         {
1169           arg->r_opt = ARGPARSE_INVALID_ARG;
1170           return -1;
1171         }
1172       else
1173         arg->r.ret_int = (int)l;
1174       return 0;
1175
1176     case ARGPARSE_TYPE_ULONG:
1177       while (isascii (*s) && isspace(*s))
1178         s++;
1179       if (*s == '-')
1180         {
1181           arg->r.ret_ulong = 0;
1182           arg->r_opt = ARGPARSE_INVALID_ARG;
1183           return -1;
1184         }
1185       errno = 0;
1186       arg->r.ret_ulong = strtoul (s, NULL, base);
1187       if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE)
1188         {
1189           arg->r_opt = ARGPARSE_INVALID_ARG;
1190           return -1;
1191         }
1192       return 0;
1193
1194     case ARGPARSE_TYPE_STRING:
1195     default:
1196       arg->r.ret_str = s;
1197       return 1;
1198     }
1199 }
1200
1201
1202 static size_t
1203 long_opt_strlen( ARGPARSE_OPTS *o )
1204 {
1205   size_t n = strlen (o->long_opt);
1206
1207   if ( o->description && *o->description == '|' )
1208     {
1209       const char *s;
1210       int is_utf8 = is_native_utf8 ();
1211
1212       s=o->description+1;
1213       if ( *s != '=' )
1214         n++;
1215       /* For a (mostly) correct length calculation we exclude
1216          continuation bytes (10xxxxxx) if we are on a native utf8
1217          terminal. */
1218       for (; *s && *s != '|'; s++ )
1219         if ( is_utf8 && (*s&0xc0) != 0x80 )
1220           n++;
1221     }
1222   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  *    as 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 show_help (ARGPARSE_OPTS *opts, unsigned int flags)
1239 {
1240   const char *s;
1241   char tmp[2];
1242
1243   show_version ();
1244   writestrings (0, "\n", NULL);
1245   s = strusage (42);
1246   if (s && *s == '1')
1247     {
1248       s = strusage (40);
1249       writestrings (1, s, NULL);
1250       if (*s && s[strlen(s)] != '\n')
1251         writestrings (1, "\n", NULL);
1252     }
1253   s = strusage(41);
1254   writestrings (0, s, "\n", NULL);
1255   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       for (i=indent=0; opts[i].short_opt; i++ )
1262         {
1263           if ( opts[i].long_opt )
1264             if ( !opts[i].description || *opts[i].description != '@' )
1265               if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
1266                 indent = j;
1267         }
1268
1269       /* Example: " -v, --verbose   Viele Sachen ausgeben" */
1270       indent += 10;
1271       if ( *opts[0].description != '@' )
1272         writestrings (0, "Options:", "\n", NULL);
1273       for (i=0; opts[i].short_opt; i++ )
1274         {
1275           s = map_static_macro_string (_( opts[i].description ));
1276           if ( s && *s== '@' && !s[1] ) /* Hide this line.  */
1277             continue;
1278           if ( s && *s == '@' )  /* Unindented comment only line.  */
1279             {
1280               for (s++; *s; s++ )
1281                 {
1282                   if ( *s == '\n' )
1283                     {
1284                       if( s[1] )
1285                         writestrings (0, "\n", NULL);
1286                     }
1287                   else
1288                     {
1289                       tmp[0] = *s;
1290                       tmp[1] = 0;
1291                       writestrings (0, tmp, NULL);
1292                     }
1293                 }
1294               writestrings (0, "\n", NULL);
1295               continue;
1296             }
1297
1298           j = 3;
1299           if ( opts[i].short_opt < 256 )
1300             {
1301               tmp[0] = opts[i].short_opt;
1302               tmp[1] = 0;
1303               writestrings (0, " -", tmp, NULL );
1304               if ( !opts[i].long_opt )
1305                 {
1306                   if (s && *s == '|' )
1307                     {
1308                       writestrings (0, " ", NULL); j++;
1309                       for (s++ ; *s && *s != '|'; s++, j++ )
1310                         {
1311                           tmp[0] = *s;
1312                           tmp[1] = 0;
1313                           writestrings (0, tmp, NULL);
1314                         }
1315                       if ( *s )
1316                         s++;
1317                     }
1318                 }
1319             }
1320           else
1321             writestrings (0, "   ", NULL);
1322           if ( opts[i].long_opt )
1323             {
1324               tmp[0] = opts[i].short_opt < 256?',':' ';
1325               tmp[1] = 0;
1326               j += writestrings (0, tmp, " --", opts[i].long_opt, NULL);
1327               if (s && *s == '|' )
1328                 {
1329                   if ( *++s != '=' )
1330                     {
1331                       writestrings (0, " ", NULL);
1332                       j++;
1333                     }
1334                   for ( ; *s && *s != '|'; s++, j++ )
1335                     {
1336                       tmp[0] = *s;
1337                       tmp[1] = 0;
1338                       writestrings (0, tmp, NULL);
1339                     }
1340                   if ( *s )
1341                     s++;
1342                 }
1343               writestrings (0, "   ", NULL);
1344               j += 3;
1345             }
1346           for (;j < indent; j++ )
1347             writestrings (0, " ", NULL);
1348           if ( s )
1349             {
1350               if ( *s && j > indent )
1351                 {
1352                   writestrings (0, "\n", NULL);
1353                   for (j=0;j < indent; j++ )
1354                     writestrings (0, " ", NULL);
1355                 }
1356               for (; *s; s++ )
1357                 {
1358                   if ( *s == '\n' )
1359                     {
1360                       if ( s[1] )
1361                         {
1362                           writestrings (0, "\n", NULL);
1363                           for (j=0; j < indent; j++ )
1364                             writestrings (0, " ", NULL);
1365                         }
1366                     }
1367                   else
1368                     {
1369                       tmp[0] = *s;
1370                       tmp[1] = 0;
1371                       writestrings (0, tmp, NULL);
1372                     }
1373                 }
1374             }
1375           writestrings (0, "\n", NULL);
1376         }
1377         if ( (flags & ARGPARSE_FLAG_ONEDASH) )
1378           writestrings (0, "\n(A single dash may be used "
1379                         "instead of the double ones)\n", NULL);
1380     }
1381   if ( (s=strusage(19)) )
1382     {
1383       writestrings (0, "\n", NULL);
1384       writestrings (0, s, NULL);
1385     }
1386   flushstrings (0);
1387   exit(0);
1388 }
1389
1390 static void
1391 show_version ()
1392 {
1393   const char *s;
1394   int i;
1395
1396   /* Version line.  */
1397   writestrings (0, strusage (11), NULL);
1398   if ((s=strusage (12)))
1399     writestrings (0, " (", s, ")", NULL);
1400   writestrings (0, " ", strusage (13), "\n", NULL);
1401   /* Additional version lines. */
1402   for (i=20; i < 30; i++)
1403     if ((s=strusage (i)))
1404       writestrings (0, s, "\n", NULL);
1405   /* Copyright string.  */
1406   if ((s=strusage (14)))
1407     writestrings (0, s, "\n", NULL);
1408   /* Licence string.  */
1409   if( (s=strusage (10)) )
1410     writestrings (0, s, "\n", NULL);
1411   /* Copying conditions. */
1412   if ( (s=strusage(15)) )
1413     writestrings (0, s, NULL);
1414   /* Thanks. */
1415   if ((s=strusage(18)))
1416     writestrings (0, s, NULL);
1417   /* Additional program info. */
1418   for (i=30; i < 40; i++ )
1419     if ( (s=strusage (i)) )
1420       writestrings (0, s, NULL);
1421   flushstrings (0);
1422 }
1423
1424
1425 void
1426 usage (int level)
1427 {
1428   const char *p;
1429
1430   if (!level)
1431     {
1432       writestrings (1, strusage(11), " ", strusage(13), "; ",
1433                     strusage (14), "\n", NULL);
1434       flushstrings (1);
1435     }
1436   else if (level == 1)
1437     {
1438       p = strusage (40);
1439       writestrings (1, p, NULL);
1440       if (*p && p[strlen(p)] != '\n')
1441         writestrings (1, "\n", NULL);
1442       exit (2);
1443     }
1444   else if (level == 2)
1445     {
1446       p = strusage (42);
1447       if (p && *p == '1')
1448         {
1449           p = strusage (40);
1450           writestrings (1, p, NULL);
1451           if (*p && p[strlen(p)] != '\n')
1452             writestrings (1, "\n", NULL);
1453         }
1454       writestrings (0, strusage(41), "\n", NULL);
1455       exit (0);
1456     }
1457 }
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 strusage( int level )
1484 {
1485   const char *p = strusage_handler? strusage_handler(level) : NULL;
1486
1487   if ( p )
1488     return map_static_macro_string (p);
1489
1490   switch ( level )
1491     {
1492
1493     case 10:
1494 #if ARGPARSE_GPL_VERSION == 3
1495       p = ("License GPLv3+: GNU GPL version 3 or later "
1496            "<https://www.gnu.org/licenses/gpl.html>");
1497 #else
1498       p = ("License GPLv2+: GNU GPL version 2 or later "
1499            "<https://www.gnu.org/licenses/>");
1500 #endif
1501       break;
1502     case 11: p = "foo"; break;
1503     case 13: p = "0.0"; break;
1504     case 14: p = ARGPARSE_CRIGHT_STR; break;
1505     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       break;
1509     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       break;
1523     case 40: /* short and long usage */
1524     case 41: p = ""; break;
1525     }
1526
1527   return p;
1528 }
1529
1530
1531 /* Set the usage handler.  This function is basically a constructor.  */
1532 void
1533 set_strusage ( const char *(*f)( int ) )
1534 {
1535   strusage_handler = f;
1536 }
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 ****/