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