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