Revert last. It is still wrong.
[gnupg.git] / util / argparse.c
blobcdc56bf3a416c6d4bb70cb32cbaec7fbee41e7fd
1 /* [argparse.c wk 17.06.97] Argument Parser for option handling
2 * Copyright (C) 1998, 1999, 2000, 2001, 2003,
3 * 2004 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 * Note: This is an independent version of the one in WkLib
25 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <string.h>
31 #include "util.h"
32 #include "i18n.h"
35 /*********************************
36 * @Summary arg_parse
37 * #include <wk/lib.h>
39 * typedef struct {
40 * char *argc; pointer to argc (value subject to change)
41 * char ***argv; pointer to argv (value subject to change)
42 * unsigned flags; Global flags (DO NOT CHANGE)
43 * int err; print error about last option
44 * 1 = warning, 2 = abort
45 * int r_opt; return option
46 * int r_type; type of return value (0 = no argument found)
47 * union {
48 * int ret_int;
49 * long ret_long
50 * ulong ret_ulong;
51 * char *ret_str;
52 * } r; Return values
53 * struct {
54 * int idx;
55 * const char *last;
56 * void *aliases;
57 * } internal; DO NOT CHANGE
58 * } ARGPARSE_ARGS;
60 * typedef struct {
61 * int short_opt;
62 * const char *long_opt;
63 * unsigned flags;
64 * } ARGPARSE_OPTS;
66 * int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
68 * @Description
69 * This is my replacement for getopt(). See the example for a typical usage.
70 * Global flags are:
71 * Bit 0 : Do not remove options form argv
72 * Bit 1 : Do not stop at last option but return other args
73 * with r_opt set to -1.
74 * Bit 2 : Assume options and real args are mixed.
75 * Bit 3 : Do not use -- to stop option processing.
76 * Bit 4 : Do not skip the first arg.
77 * Bit 5 : allow usage of long option with only one dash
78 * Bit 6 : ignore --version and --help
79 * all other bits must be set to zero, this value is modified by the
80 * function, so assume this is write only.
81 * Local flags (for each option):
82 * Bit 2-0 : 0 = does not take an argument
83 * 1 = takes int argument
84 * 2 = takes string argument
85 * 3 = takes long argument
86 * 4 = takes ulong argument
87 * Bit 3 : argument is optional (r_type will the be set to 0)
88 * Bit 4 : allow 0x etc. prefixed values.
89 * Bit 7 : this is a command and not an option
90 * You stop the option processing by setting opts to NULL, the function will
91 * then return 0.
92 * @Return Value
93 * Returns the args.r_opt or 0 if ready
94 * r_opt may be -2/-7 to indicate an unknown option/command.
95 * @See Also
96 * ArgExpand
97 * @Notes
98 * You do not need to process the options 'h', '--help' or '--version'
99 * because this function includes standard help processing; but if you
100 * specify '-h', '--help' or '--version' you have to do it yourself.
101 * The option '--' stops argument processing; if bit 1 is set the function
102 * continues to return normal arguments.
103 * To process float args or unsigned args you must use a string args and do
104 * the conversion yourself.
105 * @Example
107 * ARGPARSE_OPTS opts[] = {
108 * { 'v', "verbose", 0 },
109 * { 'd', "debug", 0 },
110 * { 'o', "output", 2 },
111 * { 'c', "cross-ref", 2|8 },
112 * { 'm', "my-option", 1|8 },
113 * { 500, "have-no-short-option-for-this-long-option", 0 },
114 * {0} };
115 * ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
117 * while( ArgParse( &pargs, &opts) ) {
118 * switch( pargs.r_opt ) {
119 * case 'v': opt.verbose++; break;
120 * case 'd': opt.debug++; break;
121 * case 'o': opt.outfile = pargs.r.ret_str; break;
122 * case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
123 * case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
124 * case 500: opt.a_long_one++; break
125 * default : pargs.err = 1; break; -- force warning output --
128 * if( argc > 1 )
129 * log_fatal( "Too many args");
133 typedef struct alias_def_s *ALIAS_DEF;
134 struct alias_def_s {
135 ALIAS_DEF next;
136 char *name; /* malloced buffer with name, \0, value */
137 const char *value; /* ptr into name */
140 static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
141 static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
142 static void show_version(void);
144 static void
145 initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
147 if( !(arg->flags & (1<<15)) ) { /* initialize this instance */
148 arg->internal.idx = 0;
149 arg->internal.last = NULL;
150 arg->internal.inarg = 0;
151 arg->internal.stopped = 0;
152 arg->internal.aliases = NULL;
153 arg->internal.cur_alias = NULL;
154 arg->err = 0;
155 arg->flags |= 1<<15; /* mark initialized */
156 if( *arg->argc < 0 )
157 log_bug("Invalid argument for ArgParse\n");
161 if( arg->err ) { /* last option was erroneous */
163 if( filename ) {
164 if( arg->r_opt == -6 )
165 log_error("%s:%u: argument not expected\n", filename, *lineno );
166 else if( arg->r_opt == -5 )
167 log_error("%s:%u: read error\n", filename, *lineno );
168 else if( arg->r_opt == -4 )
169 log_error("%s:%u: keyword too long\n", filename, *lineno );
170 else if( arg->r_opt == -3 )
171 log_error("%s:%u: missing argument\n", filename, *lineno );
172 else if( arg->r_opt == -7 )
173 log_error("%s:%u: invalid command\n", filename, *lineno );
174 else if( arg->r_opt == -10 )
175 log_error("%s:%u: invalid alias definition\n",filename,*lineno);
176 else
177 log_error("%s:%u: invalid option\n", filename, *lineno );
179 else {
180 if( arg->r_opt == -3 )
181 log_error("Missing argument for option \"%.50s\"\n",
182 arg->internal.last? arg->internal.last:"[??]" );
183 else if( arg->r_opt == -6 )
184 log_error("Option \"%.50s\" does not expect an argument\n",
185 arg->internal.last? arg->internal.last:"[??]" );
186 else if( arg->r_opt == -7 )
187 log_error("Invalid command \"%.50s\"\n",
188 arg->internal.last? arg->internal.last:"[??]" );
189 else if( arg->r_opt == -8 )
190 log_error("Option \"%.50s\" is ambiguous\n",
191 arg->internal.last? arg->internal.last:"[??]" );
192 else if( arg->r_opt == -9 )
193 log_error("Command \"%.50s\" is ambiguous\n",
194 arg->internal.last? arg->internal.last:"[??]" );
195 else
196 log_error("Invalid option \"%.50s\"\n",
197 arg->internal.last? arg->internal.last:"[??]" );
199 if( arg->err != 1 || arg->r_opt == -5 )
200 exit(2);
201 arg->err = 0;
204 /* clearout the return value union */
205 arg->r.ret_str = NULL;
206 arg->r.ret_long= 0;
210 static void
211 store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
213 /* TODO: replace this dummy function with a rea one
214 * and fix the probelms IRIX has with (ALIAS_DEV)arg..
215 * used as lvalue
217 #if 0
218 ALIAS_DEF a = xmalloc( sizeof *a );
219 a->name = name;
220 a->value = value;
221 a->next = (ALIAS_DEF)arg->internal.aliases;
222 (ALIAS_DEF)arg->internal.aliases = a;
223 #endif
226 /****************
227 * Get options from a file.
228 * Lines starting with '#' are comment lines.
229 * Syntax is simply a keyword and the argument.
230 * Valid keywords are all keywords from the long_opt list without
231 * the leading dashes. The special keywords "help", "warranty" and "version"
232 * are not valid here.
233 * The special keyword "alias" may be used to store alias definitions,
234 * which are later expanded like long options.
235 * Caller must free returned strings.
236 * If called with FP set to NULL command line args are parse instead.
238 * Q: Should we allow the syntax
239 * keyword = value
240 * and accept for boolean options a value of 1/0, yes/no or true/false?
241 * Note: Abbreviation of options is here not allowed.
244 optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
245 ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
247 int state, i, c;
248 int idx=0;
249 char keyword[100];
250 char *buffer = NULL;
251 size_t buflen = 0;
252 int inverse=0;
253 int in_alias=0;
255 if( !fp ) /* same as arg_parse() in this case */
256 return arg_parse( arg, opts );
258 initialize( arg, filename, lineno );
260 /* find the next keyword */
261 state = i = 0;
262 for(;;) {
263 c=getc(fp);
264 if( c == '\n' || c== EOF ) {
265 if( c != EOF )
266 ++*lineno;
267 if( state == -1 )
268 break;
269 else if( state == 2 ) {
270 keyword[i] = 0;
271 for(i=0; opts[i].short_opt; i++ )
272 if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
273 break;
274 idx = i;
275 arg->r_opt = opts[idx].short_opt;
276 if( inverse ) /* this does not have an effect, hmmm */
277 arg->r_opt = -arg->r_opt;
278 if( !opts[idx].short_opt ) /* unknown command/option */
279 arg->r_opt = (opts[idx].flags & 256)? -7:-2;
280 else if( !(opts[idx].flags & 7) ) /* does not take an arg */
281 arg->r_type = 0; /* okay */
282 else if( (opts[idx].flags & 8) ) /* argument is optional */
283 arg->r_type = 0; /* okay */
284 else /* required argument */
285 arg->r_opt = -3; /* error */
286 break;
288 else if( state == 3 ) { /* no argument found */
289 if( in_alias )
290 arg->r_opt = -3; /* error */
291 else if( !(opts[idx].flags & 7) ) /* does not take an arg */
292 arg->r_type = 0; /* okay */
293 else if( (opts[idx].flags & 8) ) /* no optional argument */
294 arg->r_type = 0; /* okay */
295 else /* no required argument */
296 arg->r_opt = -3; /* error */
297 break;
299 else if( state == 4 ) { /* have an argument */
300 if( in_alias ) {
301 if( !buffer )
302 arg->r_opt = -6;
303 else {
304 char *p;
306 buffer[i] = 0;
307 p = strpbrk( buffer, " \t" );
308 if( p ) {
309 *p++ = 0;
310 trim_spaces( p );
312 if( !p || !*p ) {
313 xfree( buffer );
314 arg->r_opt = -10;
316 else {
317 store_alias( arg, buffer, p );
321 else if( !(opts[idx].flags & 7) ) /* does not take an arg */
322 arg->r_opt = -6; /* error */
323 else {
324 char *p;
325 if( !buffer ) {
326 keyword[i] = 0;
327 buffer = xstrdup(keyword);
329 else
330 buffer[i] = 0;
332 trim_spaces( buffer );
333 p = buffer;
334 /* remove quotes if they totally enclose the
335 string, and do not occur within the string */
336 if( *p == '"' && p[strlen(p)-1]=='"') {
337 char *p2=p;
339 while(*(++p2))
340 if(*p2=='"')
341 break;
343 if(*p2=='"' && *(p2+1)=='\0') {
344 p[strlen(p)-1] = 0;
345 p++;
348 if( !set_opt_arg(arg, opts[idx].flags, p) )
349 xfree(buffer);
351 break;
353 else if( c == EOF ) {
354 if( ferror(fp) )
355 arg->r_opt = -5; /* read error */
356 else
357 arg->r_opt = 0; /* eof */
358 break;
360 state = 0;
361 i = 0;
363 else if( state == -1 )
364 ; /* skip */
365 else if( !state && isspace(c) )
366 ; /* skip leading white space */
367 else if( !state && c == '#' )
368 state = 1; /* start of a comment */
369 else if( state == 1 )
370 ; /* skip comments */
371 else if( state == 2 && isspace(c) ) {
372 keyword[i] = 0;
373 for(i=0; opts[i].short_opt; i++ )
374 if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
375 break;
376 idx = i;
377 arg->r_opt = opts[idx].short_opt;
378 if( !opts[idx].short_opt ) {
379 if( !strcmp( keyword, "alias" ) ) {
380 in_alias = 1;
381 state = 3;
383 else {
384 arg->r_opt = (opts[idx].flags & 256)? -7:-2;
385 state = -1; /* skip rest of line and leave */
388 else
389 state = 3;
391 else if( state == 3 ) { /* skip leading spaces of the argument */
392 if( !isspace(c) ) {
393 i = 0;
394 keyword[i++] = c;
395 state = 4;
398 else if( state == 4 ) { /* collect the argument */
399 if( buffer ) {
400 if( i < buflen-1 )
401 buffer[i++] = c;
402 else {
403 buflen += 50;
404 buffer = xrealloc(buffer, buflen);
405 buffer[i++] = c;
408 else if( i < DIM(keyword)-1 )
409 keyword[i++] = c;
410 else {
411 buflen = DIM(keyword)+50;
412 buffer = xmalloc(buflen);
413 memcpy(buffer, keyword, i);
414 buffer[i++] = c;
417 else if( i >= DIM(keyword)-1 ) {
418 arg->r_opt = -4; /* keyword to long */
419 state = -1; /* skip rest of line and leave */
421 else {
422 keyword[i++] = c;
423 state = 2;
427 return arg->r_opt;
432 static int
433 find_long_option( ARGPARSE_ARGS *arg,
434 ARGPARSE_OPTS *opts, const char *keyword )
436 int i;
437 size_t n;
439 /* Would be better if we can do a binary search, but it is not
440 possible to reorder our option table because we would mess
441 up our help strings - What we can do is: Build a nice option
442 lookup table wehn this function is first invoked */
443 if( !*keyword )
444 return -1;
445 for(i=0; opts[i].short_opt; i++ )
446 if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
447 return i;
448 #if 0
450 ALIAS_DEF a;
451 /* see whether it is an alias */
452 for( a = args->internal.aliases; a; a = a->next ) {
453 if( !strcmp( a->name, keyword) ) {
454 /* todo: must parse the alias here */
455 args->internal.cur_alias = a;
456 return -3; /* alias available */
460 #endif
461 /* not found, see whether it is an abbreviation */
462 /* aliases may not be abbreviated */
463 n = strlen( keyword );
464 for(i=0; opts[i].short_opt; i++ ) {
465 if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) {
466 int j;
467 for(j=i+1; opts[j].short_opt; j++ ) {
468 if( opts[j].long_opt
469 && !strncmp( opts[j].long_opt, keyword, n ) )
470 return -2; /* abbreviation is ambiguous */
472 return i;
475 return -1;
479 arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
481 int idx;
482 int argc;
483 char **argv;
484 char *s, *s2;
485 int i;
487 initialize( arg, NULL, NULL );
488 argc = *arg->argc;
489 argv = *arg->argv;
490 idx = arg->internal.idx;
492 if( !idx && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */
493 argc--; argv++; idx++;
496 next_one:
497 if( !argc ) { /* no more args */
498 arg->r_opt = 0;
499 goto leave; /* ready */
502 s = *argv;
503 arg->internal.last = s;
505 if( arg->internal.stopped && (arg->flags & (1<<1)) ) {
506 arg->r_opt = -1; /* not an option but a argument */
507 arg->r_type = 2;
508 arg->r.ret_str = s;
509 argc--; argv++; idx++; /* set to next one */
511 else if( arg->internal.stopped ) { /* ready */
512 arg->r_opt = 0;
513 goto leave;
515 else if( *s == '-' && s[1] == '-' ) { /* long option */
516 char *argpos;
518 arg->internal.inarg = 0;
519 if( !s[2] && !(arg->flags & (1<<3)) ) { /* stop option processing */
520 arg->internal.stopped = 1;
521 argc--; argv++; idx++;
522 goto next_one;
525 argpos = strchr( s+2, '=' );
526 if( argpos )
527 *argpos = 0;
528 i = find_long_option( arg, opts, s+2 );
529 if( argpos )
530 *argpos = '=';
532 if( i < 0 && !strcmp( "help", s+2) ) {
533 if( !(arg->flags & (1<<6)) ) {
534 show_help(opts, arg->flags);
537 else if( i < 0 && !strcmp( "version", s+2) ) {
538 if( !(arg->flags & (1<<6)) ) {
539 show_version();
540 exit(0);
543 else if( i < 0 && !strcmp( "warranty", s+2) ) {
544 puts( strusage(16) );
545 exit(0);
547 else if( i < 0 && !strcmp( "dump-options", s+2) ) {
548 for(i=0; opts[i].short_opt; i++ ) {
549 if( opts[i].long_opt )
550 printf( "--%s\n", opts[i].long_opt );
552 fputs("--dump-options\n--help\n--version\n--warranty\n", stdout );
553 exit(0);
556 if( i == -2 ) /* ambiguous option */
557 arg->r_opt = -8;
558 else if( i == -1 ) {
559 arg->r_opt = -2;
560 arg->r.ret_str = s+2;
562 else
563 arg->r_opt = opts[i].short_opt;
564 if( i < 0 )
566 else if( (opts[i].flags & 7) ) {
567 if( argpos ) {
568 s2 = argpos+1;
569 if( !*s2 )
570 s2 = NULL;
572 else
573 s2 = argv[1];
574 if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
575 arg->r_type = 0; /* because it is optional */
577 else if( !s2 ) {
578 arg->r_opt = -3; /* missing argument */
580 else if( !argpos && *s2 == '-' && (opts[i].flags & 8) ) {
581 /* the argument is optional and the next seems to be
582 * an option. We do not check this possible option
583 * but assume no argument */
584 arg->r_type = 0;
586 else {
587 set_opt_arg(arg, opts[i].flags, s2);
588 if( !argpos ) {
589 argc--; argv++; idx++; /* skip one */
593 else { /* does not take an argument */
594 if( argpos )
595 arg->r_type = -6; /* argument not expected */
596 else
597 arg->r_type = 0;
599 argc--; argv++; idx++; /* set to next one */
601 else if( (*s == '-' && s[1]) || arg->internal.inarg ) { /* short option */
602 int dash_kludge = 0;
603 i = 0;
604 if( !arg->internal.inarg ) {
605 arg->internal.inarg++;
606 if( arg->flags & (1<<5) ) {
607 for(i=0; opts[i].short_opt; i++ )
608 if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+1)) {
609 dash_kludge=1;
610 break;
614 s += arg->internal.inarg;
616 if( !dash_kludge ) {
617 for(i=0; opts[i].short_opt; i++ )
618 if( opts[i].short_opt == *s )
619 break;
622 if( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) ) {
623 if( !(arg->flags & (1<<6)) ) {
624 show_help(opts, arg->flags);
628 arg->r_opt = opts[i].short_opt;
629 if( !opts[i].short_opt ) {
630 arg->r_opt = (opts[i].flags & 256)? -7:-2;
631 arg->internal.inarg++; /* point to the next arg */
632 arg->r.ret_str = s;
634 else if( (opts[i].flags & 7) ) {
635 if( s[1] && !dash_kludge ) {
636 s2 = s+1;
637 set_opt_arg(arg, opts[i].flags, s2);
639 else {
640 s2 = argv[1];
641 if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
642 arg->r_type = 0; /* because it is optional */
644 else if( !s2 ) {
645 arg->r_opt = -3; /* missing argument */
647 else if( *s2 == '-' && s2[1] && (opts[i].flags & 8) ) {
648 /* the argument is optional and the next seems to be
649 * an option. We do not check this possible option
650 * but assume no argument */
651 arg->r_type = 0;
653 else {
654 set_opt_arg(arg, opts[i].flags, s2);
655 argc--; argv++; idx++; /* skip one */
658 s = "x"; /* so that !s[1] yields false */
660 else { /* does not take an argument */
661 arg->r_type = 0;
662 arg->internal.inarg++; /* point to the next arg */
664 if( !s[1] || dash_kludge ) { /* no more concatenated short options */
665 arg->internal.inarg = 0;
666 argc--; argv++; idx++;
669 else if( arg->flags & (1<<2) ) {
670 arg->r_opt = -1; /* not an option but a argument */
671 arg->r_type = 2;
672 arg->r.ret_str = s;
673 argc--; argv++; idx++; /* set to next one */
675 else {
676 arg->internal.stopped = 1; /* stop option processing */
677 goto next_one;
680 leave:
681 *arg->argc = argc;
682 *arg->argv = argv;
683 arg->internal.idx = idx;
684 return arg->r_opt;
689 static int
690 set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
692 int base = (flags & 16)? 0 : 10;
694 switch( arg->r_type = (flags & 7) ) {
695 case 1: /* takes int argument */
696 arg->r.ret_int = (int)strtol(s,NULL,base);
697 return 0;
698 case 3: /* takes long argument */
699 arg->r.ret_long= strtol(s,NULL,base);
700 return 0;
701 case 4: /* takes ulong argument */
702 arg->r.ret_ulong= strtoul(s,NULL,base);
703 return 0;
704 case 2: /* takes string argument */
705 default:
706 arg->r.ret_str = s;
707 return 1;
712 static size_t
713 long_opt_strlen( ARGPARSE_OPTS *o )
715 size_t n = strlen(o->long_opt);
717 if( o->description && *o->description == '|' ) {
718 const char *s;
720 s=o->description+1;
721 if( *s != '=' )
722 n++;
723 for(; *s && *s != '|'; s++ )
724 n++;
726 return n;
729 /****************
730 * Print formatted help. The description string has some special
731 * meanings:
732 * - A description string which is "@" suppresses help output for
733 * this option
734 * - a description,ine which starts with a '@' and is followed by
735 * any other characters is printed as is; this may be used for examples
736 * ans such.
737 * - A description which starts with a '|' outputs the string between this
738 * bar and the next one as arguments of the long option.
740 static void
741 show_help( ARGPARSE_OPTS *opts, unsigned flags )
743 const char *s;
745 show_version();
746 putchar('\n');
747 s = strusage(41);
748 puts(s);
749 if( opts[0].description ) { /* auto format the option description */
750 int i,j, indent;
751 /* get max. length of long options */
752 for(i=indent=0; opts[i].short_opt; i++ ) {
753 if( opts[i].long_opt )
754 if( !opts[i].description || *opts[i].description != '@' )
755 if( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
756 indent = j;
758 /* example: " -v, --verbose Viele Sachen ausgeben" */
759 indent += 10;
760 if( *opts[0].description != '@' )
761 puts("Options:");
762 for(i=0; opts[i].short_opt; i++ ) {
763 s = _( opts[i].description );
764 if( s && *s== '@' && !s[1] ) /* hide this line */
765 continue;
766 if( s && *s == '@' ) { /* unindented comment only line */
767 for(s++; *s; s++ ) {
768 if( *s == '\n' ) {
769 if( s[1] )
770 putchar('\n');
772 else
773 putchar(*s);
775 putchar('\n');
776 continue;
779 j = 3;
780 if( opts[i].short_opt < 256 ) {
781 printf(" -%c", opts[i].short_opt );
782 if( !opts[i].long_opt ) {
783 if(s && *s == '|' ) {
784 putchar(' '); j++;
785 for(s++ ; *s && *s != '|'; s++, j++ )
786 putchar(*s);
787 if( *s )
788 s++;
792 else
793 fputs(" ", stdout);
794 if( opts[i].long_opt ) {
795 j += printf("%c --%s", opts[i].short_opt < 256?',':' ',
796 opts[i].long_opt );
797 if(s && *s == '|' ) {
798 if( *++s != '=' ) {
799 putchar(' ');
800 j++;
802 for( ; *s && *s != '|'; s++, j++ )
803 putchar(*s);
804 if( *s )
805 s++;
807 fputs(" ", stdout);
808 j += 3;
810 for(;j < indent; j++ )
811 putchar(' ');
812 if( s ) {
813 if( *s && j > indent ) {
814 putchar('\n');
815 for(j=0;j < indent; j++ )
816 putchar(' ');
818 for(; *s; s++ ) {
819 if( *s == '\n' ) {
820 if( s[1] ) {
821 putchar('\n');
822 for(j=0;j < indent; j++ )
823 putchar(' ');
826 else
827 putchar(*s);
830 putchar('\n');
832 if( flags & 32 )
833 puts("\n(A single dash may be used instead of the double ones)");
835 if( (s=strusage(19)) ) { /* bug reports to ... */
836 putchar('\n');
837 fputs(s, stdout);
839 fflush(stdout);
840 exit(0);
843 static void
844 show_version()
846 const char *s;
847 int i;
848 /* version line */
849 fputs(strusage(11), stdout);
850 if( (s=strusage(12)) )
851 printf(" (%s)", s );
852 printf(" %s\n", strusage(13) );
853 /* additional version lines */
854 for(i=20; i < 30; i++ )
855 if( (s=strusage(i)) )
856 printf("%s\n", s );
857 /* copyright string */
858 if( (s=strusage(14)) )
859 printf("%s\n", s );
860 /* copying conditions */
861 if( (s=strusage(15)) )
862 fputs(s, stdout);
863 /* thanks */
864 if( (s=strusage(18)) )
865 fputs(s, stdout);
866 /* additional program info */
867 for(i=30; i < 40; i++ )
868 if( (s=strusage(i)) )
869 fputs( (const byte*)s, stdout);
870 fflush(stdout);
874 void
875 usage( int level )
877 if( !level ) {
878 fprintf(stderr,"%s %s; %s\n", strusage(11), strusage(13),
879 strusage(14) );
880 fflush(stderr);
882 else if( level == 1 ) {
883 fputs(strusage(40),stderr);
884 exit(2);
886 else if( level == 2 ) {
887 puts(strusage(41));
888 exit(0);
892 /* Level
893 * 0: Copyright String auf stderr ausgeben
894 * 1: Kurzusage auf stderr ausgeben und beenden
895 * 2: Langusage auf stdout ausgeben und beenden
896 * 11: name of program
897 * 12: optional name of package which includes this program.
898 * 13: version string
899 * 14: copyright string
900 * 15: Short copying conditions (with LFs)
901 * 16: Long copying conditions (with LFs)
902 * 17: Optional printable OS name
903 * 18: Optional thanks list (with LFs)
904 * 19: Bug report info
905 *20..29: Additional lib version strings.
906 *30..39: Additional program info (with LFs)
907 * 40: short usage note (with LF)
908 * 41: long usage note (with LF)
910 const char *
911 default_strusage( int level )
913 const char *p = NULL;
914 switch( level ) {
915 case 11: p = "foo"; break;
916 case 13: p = "0.0"; break;
917 case 14: p = "Copyright (C) 2006 Free Software Foundation, Inc."; break;
918 case 15: p =
919 "This program comes with ABSOLUTELY NO WARRANTY.\n"
920 "This is free software, and you are welcome to redistribute it\n"
921 "under certain conditions. See the file COPYING for details.\n"; break;
922 case 16: p =
923 "This is free software; you can redistribute it and/or modify\n"
924 "it under the terms of the GNU General Public License as published by\n"
925 "the Free Software Foundation; either version 2 of the License, or\n"
926 "(at your option) any later version.\n\n"
927 "It is distributed in the hope that it will be useful,\n"
928 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
929 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
930 "GNU General Public License for more details.\n\n"
931 "You should have received a copy of the GNU General Public License\n"
932 "along with this program; if not, write to the Free Software\n"
933 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n";
934 break;
935 case 40: /* short and long usage */
936 case 41: p = ""; break;
939 return p;
944 #ifdef TEST
945 static struct {
946 int verbose;
947 int debug;
948 char *outfile;
949 char *crf;
950 int myopt;
951 int echo;
952 int a_long_one;
953 }opt;
956 main(int argc, char **argv)
958 ARGPARSE_OPTS opts[] = {
959 { 'v', "verbose", 0 , "Laut sein"},
960 { 'e', "echo" , 0 , "Zeile ausgeben, damit wir sehen, was wir einegegeben haben"},
961 { 'd', "debug", 0 , "Debug\nfalls mal etasws\nSchief geht"},
962 { 'o', "output", 2 },
963 { 'c', "cross-ref", 2|8, "cross-reference erzeugen\n" },
964 { 'm', "my-option", 1|8 },
965 { 500, "a-long-option", 0 },
966 {0} };
967 ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 };
968 int i;
970 while( ArgParse( &pargs, opts) ) {
971 switch( pargs.r_opt ) {
972 case -1 : printf( "arg=`%s'\n", pargs.r.ret_str); break;
973 case 'v': opt.verbose++; break;
974 case 'e': opt.echo++; break;
975 case 'd': opt.debug++; break;
976 case 'o': opt.outfile = pargs.r.ret_str; break;
977 case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
978 case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
979 case 500: opt.a_long_one++; break;
980 default : pargs.err = 1; break; /* force warning output */
983 for(i=0; i < argc; i++ )
984 printf("%3d -> (%s)\n", i, argv[i] );
985 puts("Options:");
986 if( opt.verbose )
987 printf(" verbose=%d\n", opt.verbose );
988 if( opt.debug )
989 printf(" debug=%d\n", opt.debug );
990 if( opt.outfile )
991 printf(" outfile=`%s'\n", opt.outfile );
992 if( opt.crf )
993 printf(" crffile=`%s'\n", opt.crf );
994 if( opt.myopt )
995 printf(" myopt=%d\n", opt.myopt );
996 if( opt.a_long_one )
997 printf(" a-long-one=%d\n", opt.a_long_one );
998 if( opt.echo )
999 printf(" echo=%d\n", opt.echo );
1000 return 0;
1002 #endif
1004 /**** bottom of file ****/