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