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