new release
[gnupg.git] / util / argparse.c
1 /* [argparse.c wk 17.06.97] Argument Parser for option handling
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *  This file is part of WkLib.
4  *
5  *  WkLib is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  WkLib is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18  *
19  *
20  * Note: This is an independent version of the one in WkLib
21  */
22
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <ctype.h>
27 #include <string.h>
28
29 #include "util.h"
30 #include "i18n.h"
31
32
33 /*********************************
34  * @Summary arg_parse
35  *  #include <wk/lib.h>
36  *
37  *  typedef struct {
38  *      char *argc;               pointer to argc (value subject to change)
39  *      char ***argv;             pointer to argv (value subject to change)
40  *      unsigned flags;           Global flags (DO NOT CHANGE)
41  *      int err;                  print error about last option
42  *                                1 = warning, 2 = abort
43  *      int r_opt;                return option
44  *      int r_type;               type of return value (0 = no argument found)
45  *      union {
46  *          int   ret_int;
47  *          long  ret_long
48  *          ulong ret_ulong;
49  *          char *ret_str;
50  *      } r;                      Return values
51  *      struct {
52  *          int index;
53  *          const char *last;
54  *      } internal;               DO NOT CHANGE
55  *  } ARGPARSE_ARGS;
56  *
57  *  typedef struct {
58  *      int         short_opt;
59  *      const char *long_opt;
60  *      unsigned flags;
61  *  } ARGPARSE_OPTS;
62  *
63  *  int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
64  *
65  * @Description
66  *  This is my replacement for getopt(). See the example for a typical usage.
67  *  Global flags are:
68  *     Bit 0 : Do not remove options form argv
69  *     Bit 1 : Do not stop at last option but return other args
70  *             with r_opt set to -1.
71  *     Bit 2 : Assume options and real args are mixed.
72  *     Bit 3 : Do not use -- to stop option processing.
73  *     Bit 4 : Do not skip the first arg.
74  *     Bit 5 : allow usage of long option with only one dash
75  *     all other bits must be set to zero, this value is modified by the function
76  *     so assume this is write only.
77  *  Local flags (for each option):
78  *     Bit 2-0 : 0 = does not take an argument
79  *               1 = takes int argument
80  *               2 = takes string argument
81  *               3 = takes long argument
82  *               4 = takes ulong argument
83  *     Bit 3 : argument is optional (r_type will the be set to 0)
84  *     Bit 4 : allow 0x etc. prefixed values.
85  *  If can stop the option processing by setting opts to NULL, the function will
86  *  then return 0.
87  * @Return Value
88  *   Returns the args.r_opt or 0 if ready
89  *   r_opt may be -2 to indicate an unknown option.
90  * @See Also
91  *   ArgExpand
92  * @Notes
93  *  You do not need to process the options 'h', '--help' or '--version'
94  *  because this function includes standard help processing; but if you
95  *  specify '-h', '--help' or '--version' you have to do it yourself.
96  *  The option '--' stops argument processing; if bit 1 is set the function
97  *  continues to return normal arguments.
98  *  To process float args or unsigned args you must use a string args and do
99  *  the conversion yourself.
100  * @Example
101  *
102  *     ARGPARSE_OPTS opts[] = {
103  *     { 'v', "verbose",   0 },
104  *     { 'd', "debug",     0 },
105  *     { 'o', "output",    2 },
106  *     { 'c', "cross-ref", 2|8 },
107  *     { 'm', "my-option", 1|8 },
108  *     { 500, "have-no-short-option-for-this-long-option", 0 },
109  *     {0} };
110  *     ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
111  *
112  *     while( ArgParse( &pargs, &opts) ) {
113  *         switch( pargs.r_opt ) {
114  *           case 'v': opt.verbose++; break;
115  *           case 'd': opt.debug++; break;
116  *           case 'o': opt.outfile = pargs.r.ret_str; break;
117  *           case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
118  *           case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
119  *           case 500: opt.a_long_one++;  break
120  *           default : pargs.err = 1; break; -- force warning output --
121  *         }
122  *     }
123  *     if( argc > 1 )
124  *         log_fatal( "Too many args");
125  *
126  */
127
128
129 static int  set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
130 static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
131 static void show_version(void);
132
133 static void
134 initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
135 {
136     if( !(arg->flags & (1<<15)) ) { /* initialize this instance */
137         arg->internal.index = 0;
138         arg->internal.last = NULL;
139         arg->internal.inarg = 0;
140         arg->internal.stopped= 0;
141         arg->err = 0;
142         arg->flags |= 1<<15; /* mark initialized */
143         if( *arg->argc < 0 )
144             log_bug("Invalid argument for ArgParse\n");
145     }
146
147     if( arg->err ) { /* last option was erroneous */
148         const char *s;
149
150         if( filename ) {
151             if( arg->r_opt == -6 )
152                 s = "%s:%u: argument not expected\n";
153             else if( arg->r_opt == -5 )
154                 s = "%s:%u: read error\n";
155             else if( arg->r_opt == -4 )
156                 s = "%s:%u: keyword too long\n";
157             else if( arg->r_opt == -3 )
158                 s = "%s:%u: missing argument\n";
159             else
160                 s = "%s:%u: invalid option\n";
161             log_error(s, filename, *lineno );
162         }
163         else {
164             if( arg->r_opt == -3 )
165                 s = "Missing argument for option \"%.50s\"\n";
166             else
167                 s = "Invalid option \"%.50s\"\n";
168             log_error(s, arg->internal.last? arg->internal.last:"[??]" );
169         }
170         if( arg->err != 1 )
171             exit(2);
172         arg->err = 0;
173     }
174 }
175
176
177
178 /****************
179  * Get options from a file.
180  * Lines starting with '#' are comment lines.
181  * Syntax is simply a keyword and the argument.
182  * Valid keywords are all keywords from the long_opt list without
183  * the leading dashes. The special keywords help, warranty and version
184  * are not valid here.
185  * Caller must free returned strings.
186  * If called with FP set to NULL command line args are parse instead.
187  */
188 int
189 optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
190                ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
191 {
192     int state, i, c;
193     int index=0;
194     char keyword[100];
195     char *buffer = NULL;
196     size_t buflen = 0;
197     int inverse=0;
198
199     if( !fp ) /* same as arg_parse() in this case */
200         return arg_parse( arg, opts );
201
202     initialize( arg, filename, lineno );
203
204     /* find the next keyword */
205     state = i = 0;
206     for(;;) {
207         c=getc(fp);
208         if( c == '\n' || c== EOF ) {
209             if( c != EOF )
210                 ++*lineno;
211             if( state == -1 )
212                 break;
213             else if( state == 2 ) {
214                 keyword[i] = 0;
215                 for(i=0; opts[i].short_opt; i++ )
216                     if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
217                         break;
218                 index = i;
219                 arg->r_opt = opts[index].short_opt;
220                 if( inverse )
221                     arg->r_opt = -arg->r_opt;
222                 if( !opts[index].short_opt )
223                     arg->r_opt = -2;           /* unknown option */
224                 else if( (opts[index].flags & 8) ) /* no argument */
225                     arg->r_opt = -3;           /* error */
226                 else                           /* no or optiona argument */
227                     arg->r_type = 0;           /* okay */
228                 break;
229             }
230             else if( state == 3 ) {            /* no argument found */
231                 if( !(opts[index].flags & 7) ) /* does not take an argument */
232                     arg->r_type = 0;           /* okay */
233                 else if( (opts[index].flags & 8) )  /* no optional argument */
234                     arg->r_type = 0;           /* okay */
235                 else                           /* no required argument */
236                     arg->r_opt = -3;           /* error */
237                 break;
238             }
239             else if( state == 4 ) {     /* have an argument */
240                 if( !(opts[index].flags & 7) )  /* does not take an argument */
241                     arg->r_opt = -6;        /* error */
242                 else {
243                     if( !buffer ) {
244                         keyword[i] = 0;
245                         buffer = m_strdup(keyword);
246                     }
247                     else
248                         buffer[i] = 0;
249
250                     if( !set_opt_arg(arg, opts[index].flags, buffer) )
251                         m_free(buffer);
252                 }
253                 break;
254             }
255             else if( c == EOF ) {
256                 if( ferror(fp) )
257                     arg->r_opt = -5;   /* read error */
258                 else
259                     arg->r_opt = 0;    /* eof */
260                 break;
261             }
262             state = 0;
263             i = 0;
264         }
265         else if( state == -1 )
266             ; /* skip */
267         else if( !state && isspace(c) )
268             ; /* skip leading white space */
269         else if( !state && c == '#' )
270             state = 1;  /* start of a comment */
271         else if( state == 1 )
272             ; /* skip comments */
273         else if( state == 2 && isspace(c) ) {
274             keyword[i] = 0;
275             for(i=0; opts[i].short_opt; i++ )
276                 if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
277                     break;
278             index = i;
279             arg->r_opt = opts[index].short_opt;
280             if( !opts[index].short_opt ) {
281                 arg->r_opt = -2;   /* unknown option */
282                 state = -1;        /* skip rest of line and leave */
283             }
284             else
285                 state = 3;
286         }
287         else if( state == 3 ) { /* skip leading spaces of the argument */
288             if( !isspace(c) ) {
289                 i = 0;
290                 keyword[i++] = c;
291                 state = 4;
292             }
293         }
294         else if( state == 4 ) { /* collect the argument */
295             if( buffer ) {
296                 if( i < buflen-1 )
297                     buffer[i++] = c;
298                 else {
299                     buflen += 50;
300                     buffer = m_realloc(buffer, buflen);
301                     buffer[i++] = c;
302                 }
303             }
304             else if( i < DIM(keyword)-1 )
305                 keyword[i++] = c;
306             else {
307                 buflen = DIM(keyword)+50;
308                 buffer = m_alloc(buflen);
309                 memcpy(buffer, keyword, i);
310                 buffer[i++] = c;
311             }
312         }
313         else if( i >= DIM(keyword)-1 ) {
314             arg->r_opt = -4;   /* keyword to long */
315             state = -1;        /* skip rest of line and leave */
316         }
317         else {
318             keyword[i++] = c;
319             state = 2;
320         }
321     }
322
323     return arg->r_opt;
324 }
325
326
327
328 int
329 arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
330 {
331     int index;
332     int argc;
333     char **argv;
334     char *s, *s2;
335     int i;
336
337     initialize( arg, NULL, NULL );
338     argc = *arg->argc;
339     argv = *arg->argv;
340     index = arg->internal.index;
341
342     if( !index && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */
343         argc--; argv++; index++;
344     }
345
346   next_one:
347     if( !argc ) { /* no more args */
348         arg->r_opt = 0;
349         goto leave; /* ready */
350     }
351
352     s = *argv;
353     arg->internal.last = s;
354
355     if( arg->internal.stopped && (arg->flags & (1<<1)) ) {
356         arg->r_opt = -1;  /* not an option but a argument */
357         arg->r_type = 2;
358         arg->r.ret_str = s;
359         argc--; argv++; index++; /* set to next one */
360     }
361     else if( arg->internal.stopped ) { /* ready */
362         arg->r_opt = 0;
363         goto leave;
364     }
365     else if( *s == '-' && s[1] == '-' ) { /* long option */
366         arg->internal.inarg = 0;
367         if( !s[2] && !(arg->flags & (1<<3)) ) { /* stop option processing */
368             arg->internal.stopped = 1;
369             argc--; argv++; index++;
370             goto next_one;
371         }
372
373         for(i=0; opts[i].short_opt; i++ )
374             if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+2) )
375                 break;
376
377         if( !opts[i].short_opt && !strcmp( "help", s+2) )
378             show_help(opts, arg->flags);
379         else if( !opts[i].short_opt && !strcmp( "version", s+2) ) {
380             show_version();
381             exit(0);
382         }
383         else if( !opts[i].short_opt && !strcmp( "warranty", s+2) ) {
384             puts( strusage(16) );
385             exit(0);
386         }
387
388         arg->r_opt = opts[i].short_opt;
389         if( !opts[i].short_opt ) {
390             arg->r_opt = -2; /* unknown option */
391             arg->r.ret_str = s+2;
392         }
393         else if( (opts[i].flags & 7) ) {
394             s2 = argv[1];
395             if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
396                 arg->r_type = 0;               /* because it is optional */
397             }
398             else if( !s2 ) {
399                 arg->r_opt = -3; /* missing argument */
400             }
401             else if( *s2 == '-' && (opts[i].flags & 8) ) {
402                 /* the argument is optional and the next seems to be
403                  * an option. We do not check this possible option
404                  * but assume no argument */
405                 arg->r_type = 0;
406             }
407             else {
408                 set_opt_arg(arg, opts[i].flags, s2);
409                 argc--; argv++; index++; /* skip one */
410             }
411         }
412         else { /* does not take an argument */
413             arg->r_type = 0;
414         }
415         argc--; argv++; index++; /* set to next one */
416     }
417     else if( (*s == '-' && s[1]) || arg->internal.inarg ) { /* short option */
418         int dash_kludge = 0;
419         i = 0;
420         if( !arg->internal.inarg ) {
421             arg->internal.inarg++;
422             if( arg->flags & (1<<5) ) {
423                 for(i=0; opts[i].short_opt; i++ )
424                     if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+1)) {
425                         dash_kludge=1;
426                         break;
427                     }
428             }
429         }
430         s += arg->internal.inarg;
431
432         if( !dash_kludge ) {
433             for(i=0; opts[i].short_opt; i++ )
434                 if( opts[i].short_opt == *s )
435                     break;
436         }
437
438         if( !opts[i].short_opt && *s == 'h' )
439             show_help(opts, arg->flags);
440
441         arg->r_opt = opts[i].short_opt;
442         if( !opts[i].short_opt ) {
443             arg->r_opt = -2; /* unknown option */
444             arg->internal.inarg++; /* point to the next arg */
445             arg->r.ret_str = s;
446         }
447         else if( (opts[i].flags & 7) ) {
448             if( s[1] && !dash_kludge ) {
449                 s2 = s+1;
450                 set_opt_arg(arg, opts[i].flags, s2);
451             }
452             else {
453                 s2 = argv[1];
454                 if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
455                     arg->r_type = 0;               /* because it is optional */
456                 }
457                 else if( !s2 ) {
458                     arg->r_opt = -3; /* missing argument */
459                 }
460                 else if( *s2 == '-' && s2[1] && (opts[i].flags & 8) ) {
461                     /* the argument is optional and the next seems to be
462                      * an option. We do not check this possible option
463                      * but assume no argument */
464                     arg->r_type = 0;
465                 }
466                 else {
467                     set_opt_arg(arg, opts[i].flags, s2);
468                     argc--; argv++; index++; /* skip one */
469                 }
470             }
471             s = "x"; /* so that !s[1] yields false */
472         }
473         else { /* does not take an argument */
474             arg->r_type = 0;
475             arg->internal.inarg++; /* point to the next arg */
476         }
477         if( !s[1] || dash_kludge ) { /* no more concatenated short options */
478             arg->internal.inarg = 0;
479             argc--; argv++; index++;
480         }
481     }
482     else if( arg->flags & (1<<2) ) {
483         arg->r_opt = -1;  /* not an option but a argument */
484         arg->r_type = 2;
485         arg->r.ret_str = s;
486         argc--; argv++; index++; /* set to next one */
487     }
488     else {
489         arg->internal.stopped = 1; /* stop option processing */
490         goto next_one;
491     }
492
493   leave:
494     *arg->argc = argc;
495     *arg->argv = argv;
496     arg->internal.index = index;
497     return arg->r_opt;
498 }
499
500
501
502 static int
503 set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
504 {
505     int base = (flags & 16)? 0 : 10;
506
507     switch( arg->r_type = (flags & 7) ) {
508       case 1: /* takes int argument */
509         arg->r.ret_int = (int)strtol(s,NULL,base);
510         return 0;
511       case 3: /* takes long argument   */
512         arg->r.ret_long= strtol(s,NULL,base);
513         return 0;
514       case 4: /* takes ulong argument  */
515         arg->r.ret_ulong= strtoul(s,NULL,base);
516         return 0;
517       case 2: /* takes string argument */
518       default:
519         arg->r.ret_str = s;
520         return 1;
521     }
522 }
523
524
525 static size_t
526 long_opt_strlen( ARGPARSE_OPTS *o )
527 {
528     size_t n = strlen(o->long_opt);
529
530     if( o->description && *o->description == '|' ) {
531         const char *s;
532
533         s=o->description+1;
534         if( *s != '=' )
535             n++;
536         for(; *s && *s != '|'; s++ )
537             n++;
538     }
539     return n;
540 }
541
542 /****************
543  * Print formatted help. The description string has some special
544  * meanings:
545  *  - A description string which is "@" suppresses help output for
546  *    this option
547  *  - a description,ine which starts with a '@' and is followed by
548  *    any other characters is printed as is; this may be used for examples
549  *    ans such.
550  *  - A description which starts with a '|' outputs the string between this
551  *    bar and the next one as arguments of the long option.
552  */
553 static void
554 show_help( ARGPARSE_OPTS *opts, unsigned flags )
555 {
556     const char *s;
557
558     show_version();
559     putchar('\n');
560     s = strusage(41);
561     puts(s);
562     if( opts[0].description ) { /* auto format the option description */
563         int i,j, indent;
564         /* get max. length of long options */
565         for(i=indent=0; opts[i].short_opt; i++ ) {
566             if( opts[i].long_opt )
567                 if( !opts[i].description || *opts[i].description != '@' )
568                     if( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
569                          indent = j;
570         }
571         /* example: " -v, --verbose   Viele Sachen ausgeben" */
572         indent += 10;
573         if( *opts[0].description != '@' )
574             puts("Options:");
575         for(i=0; opts[i].short_opt; i++ ) {
576             s = _( opts[i].description );
577             if( s && *s== '@' && !s[1] ) /* hide this line */
578                 continue;
579             if( s && *s == '@' ) { /* unindented comment only line */
580                 for(s++; *s; s++ ) {
581                     if( *s == '\n' ) {
582                         if( s[1] )
583                             putchar('\n');
584                     }
585                     else
586                         putchar(*s);
587                 }
588                 putchar('\n');
589                 continue;
590             }
591
592             j = 3;
593             if( opts[i].short_opt < 256 ) {
594                 printf(" -%c", opts[i].short_opt );
595                 if( !opts[i].long_opt ) {
596                     if(s && *s == '|' ) {
597                         putchar(' '); j++;
598                         for(s++ ; *s && *s != '|'; s++, j++ )
599                             putchar(*s);
600                         if( *s )
601                             s++;
602                     }
603                 }
604             }
605             else
606                 fputs("   ", stdout);
607             if( opts[i].long_opt ) {
608                 j += printf("%c --%s", opts[i].short_opt < 256?',':' ',
609                                        opts[i].long_opt );
610                 if(s && *s == '|' ) {
611                     if( *++s != '=' ) {
612                         putchar(' ');
613                         j++;
614                     }
615                     for( ; *s && *s != '|'; s++, j++ )
616                         putchar(*s);
617                     if( *s )
618                         s++;
619                 }
620                 fputs("   ", stdout);
621                 j += 3;
622             }
623             for(;j < indent; j++ )
624                 putchar(' ');
625             if( s ) {
626                 if( *s && j > indent ) {
627                     putchar('\n');
628                     for(j=0;j < indent; j++ )
629                         putchar(' ');
630                 }
631                 for(; *s; s++ ) {
632                     if( *s == '\n' ) {
633                         if( s[1] ) {
634                             putchar('\n');
635                             for(j=0;j < indent; j++ )
636                                 putchar(' ');
637                         }
638                     }
639                     else
640                         putchar(*s);
641                 }
642             }
643             putchar('\n');
644         }
645         if( flags & 32 )
646             puts("\n(A single dash may be used instead of the double ones)");
647     }
648     if( (s=strusage(19)) ) {  /* bug reports to ... */
649         putchar('\n');
650         fputs(s, stdout);
651     }
652     fflush(stdout);
653     exit(0);
654 }
655
656 static void
657 show_version()
658 {
659     const char *s;
660     int i;
661     /* version line */
662     fputs(strusage(11), stdout);
663     if( (s=strusage(12)) )
664         printf(" (%s)", s );
665     printf(" %s\n", strusage(13) );
666     /* additional version lines */
667     for(i=20; i < 30; i++ )
668         if( (s=strusage(i)) )
669             printf("%s\n", s );
670     /* copyright string */
671     if( (s=strusage(14)) )
672         printf("%s\n", s );
673     /* copying conditions */
674     if( (s=strusage(15)) )
675         fputs(s, stdout);
676     /* thanks */
677     if( (s=strusage(18)) )
678         fputs(s, stdout);
679     /* additional program info */
680     for(i=30; i < 40; i++ )
681         if( (s=strusage(i)) )
682             fputs(s, stdout);
683     fflush(stdout);
684 }
685
686
687 void
688 usage( int level )
689 {
690     if( !level ) {
691         fprintf(stderr,"%s %s; %s\n", strusage(11), strusage(13),
692                                                      strusage(14) );
693         fflush(stderr);
694     }
695     else if( level == 1 ) {
696         fputs(strusage(40),stderr);
697         exit(2);
698     }
699     else if( level == 2 ) {
700         puts(strusage(41));
701         exit(0);
702     }
703 }
704
705 /* Level
706  *     0: Copyright String auf stderr ausgeben
707  *     1: Kurzusage auf stderr ausgeben und beenden
708  *     2: Langusage auf stdout ausgeben und beenden
709  *    11: name of program
710  *    12: optional name of package which includes this program.
711  *    13: version  string
712  *    14: copyright string
713  *    15: Short copying conditions (with LFs)
714  *    16: Long copying conditions (with LFs)
715  *    17: Optional printable OS name
716  *    18: Optional thanks list   (with LFs)
717  *    19: Bug report info
718  *20..29: Additional lib version strings.
719  *30..39: Additional program info (with LFs)
720  *    40: short usage note (with LF)
721  *    41: long usage note (with LF)
722  */
723 const char *
724 default_strusage( int level )
725 {
726     const char *p = NULL;
727     switch( level ) {
728       case 11: p = "foo"; break;
729       case 13: p = "0.0"; break;
730       case 14: p = "Copyright (C) 1998 Free Software Foundation, Inc."; break;
731       case 15: p =
732 "This program comes with ABSOLUTELY NO WARRANTY.\n"
733 "This is free software, and you are welcome to redistribute it\n"
734 "under certain conditions. See the file COPYING for details.\n"; break;
735       case 16:  p =
736 "This is free software; you can redistribute it and/or modify\n"
737 "it under the terms of the GNU General Public License as published by\n"
738 "the Free Software Foundation; either version 2 of the License, or\n"
739 "(at your option) any later version.\n\n"
740 "It is distributed in the hope that it will be useful,\n"
741 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
742 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
743 "GNU General Public License for more details.\n\n"
744 "You should have received a copy of the GNU General Public License\n"
745 "along with this program; if not, write to the Free Software\n"
746 "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n";
747         break;
748       case 40: /* short and long usage */
749       case 41: p = ""; break;
750     }
751
752     return p;
753 }
754
755
756
757 #ifdef TEST
758 static struct {
759     int verbose;
760     int debug;
761     char *outfile;
762     char *crf;
763     int myopt;
764     int echo;
765     int a_long_one;
766 }opt;
767
768 int
769 main(int argc, char **argv)
770 {
771     ARGPARSE_OPTS opts[] = {
772     { 'v', "verbose",   0 , "Laut sein"},
773     { 'e', "echo"   ,   0 , "Zeile ausgeben, damit wir sehen, was wir einegegeben haben"},
774     { 'd', "debug",     0 , "Debug\nfalls mal etasws\nSchief geht"},
775     { 'o', "output",    2   },
776     { 'c', "cross-ref", 2|8, "cross-reference erzeugen\n" },
777     { 'm', "my-option", 1|8 },
778     { 500, "a-long-option", 0 },
779     {0} };
780     ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 };
781     int i;
782
783     while( ArgParse( &pargs, opts) ) {
784         switch( pargs.r_opt ) {
785           case -1 : printf( "arg='%s'\n", pargs.r.ret_str); break;
786           case 'v': opt.verbose++; break;
787           case 'e': opt.echo++; break;
788           case 'd': opt.debug++; break;
789           case 'o': opt.outfile = pargs.r.ret_str; break;
790           case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
791           case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
792           case 500: opt.a_long_one++;  break;
793           default : pargs.err = 1; break; /* force warning output */
794         }
795     }
796     for(i=0; i < argc; i++ )
797         printf("%3d -> (%s)\n", i, argv[i] );
798     puts("Options:");
799     if( opt.verbose )
800         printf("  verbose=%d\n", opt.verbose );
801     if( opt.debug )
802         printf("  debug=%d\n", opt.debug );
803     if( opt.outfile )
804         printf("  outfile='%s'\n", opt.outfile );
805     if( opt.crf )
806         printf("  crffile='%s'\n", opt.crf );
807     if( opt.myopt )
808         printf("  myopt=%d\n", opt.myopt );
809     if( opt.a_long_one )
810         printf("  a-long-one=%d\n", opt.a_long_one );
811     if( opt.echo       )
812         printf("  echo=%d\n", opt.echo );
813     return 0;
814 }
815 #endif
816
817 /**** bottom of file ****/