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