251
262
* Note: Abbreviation of options is here not allowed.
254
optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
265
optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
255
266
ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
265
if( !fp ) /* same as arg_parse() in this case */
266
return arg_parse( arg, opts );
268
initialize( arg, filename, lineno );
270
/* find the next keyword */
274
if( c == '\n' || c== EOF ) {
279
else if( state == 2 ) {
281
for(i=0; opts[i].short_opt; i++ )
282
if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
285
arg->r_opt = opts[idx].short_opt;
286
if( inverse ) /* this does not have an effect, hmmm */
287
arg->r_opt = -arg->r_opt;
288
if( !opts[idx].short_opt ) /* unknown command/option */
289
arg->r_opt = (opts[idx].flags & 256)? -7:-2;
290
else if( !(opts[idx].flags & 7) ) /* does not take an arg */
291
arg->r_type = 0; /* okay */
292
else if( (opts[idx].flags & 8) ) /* argument is optional */
293
arg->r_type = 0; /* okay */
294
else /* required argument */
295
arg->r_opt = -3; /* error */
298
else if( state == 3 ) { /* no argument found */
300
arg->r_opt = -3; /* error */
301
else if( !(opts[idx].flags & 7) ) /* does not take an arg */
302
arg->r_type = 0; /* okay */
303
else if( (opts[idx].flags & 8) ) /* no optional argument */
304
arg->r_type = 0; /* okay */
305
else /* no required argument */
306
arg->r_opt = -3; /* error */
309
else if( state == 4 ) { /* have an argument */
317
p = strpbrk( buffer, " \t" );
323
jnlib_free( buffer );
327
store_alias( arg, buffer, p );
275
if (!fp) /* Divert to to arg_parse() in this case. */
276
return arg_parse (arg, opts);
278
initialize (arg, filename, lineno);
280
/* Find the next keyword. */
285
if (c == '\n' || c== EOF )
294
for (i=0; opts[i].short_opt; i++ )
296
if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
300
arg->r_opt = opts[idx].short_opt;
301
if (!opts[idx].short_opt )
302
arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
303
? ARGPARSE_INVALID_COMMAND
304
: ARGPARSE_INVALID_OPTION);
305
else if (!(opts[idx].flags & 7))
306
arg->r_type = 0; /* Does not take an arg. */
307
else if ((opts[idx].flags & 8) )
308
arg->r_type = 0; /* Arg is optional. */
310
arg->r_opt = ARGPARSE_MISSING_ARG;
316
/* No argument found. */
318
arg->r_opt = ARGPARSE_MISSING_ARG;
319
else if (!(opts[idx].flags & 7))
320
arg->r_type = 0; /* Does not take an arg. */
321
else if ((opts[idx].flags & 8))
322
arg->r_type = 0; /* No optional argument. */
324
arg->r_opt = ARGPARSE_MISSING_ARG;
330
/* Has an argument. */
334
arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
340
p = strpbrk (buffer, " \t");
349
arg->r_opt = ARGPARSE_INVALID_ALIAS;
353
store_alias (arg, buffer, p);
331
else if( !(opts[idx].flags & 7) ) /* does not take an arg */
332
arg->r_opt = -6; /* error */
337
buffer = jnlib_xstrdup(keyword);
357
else if (!(opts[idx].flags & 7))
358
arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
342
trim_spaces( buffer );
344
if( *p == '"' ) { /* remove quotes */
346
if( *p && p[strlen(p)-1] == '"' )
366
buffer = jnlib_strdup (keyword);
368
arg->r_opt = ARGPARSE_OUT_OF_CORE;
349
if( !set_opt_arg(arg, opts[idx].flags, p) )
375
trim_spaces (buffer);
381
if (*p && p[strlen(p)-1] == '\"' )
384
if (!set_opt_arg (arg, opts[idx].flags, p))
350
385
jnlib_free(buffer);
354
else if( c == EOF ) {
356
arg->r_opt = -5; /* read error */
358
arg->r_opt = 0; /* eof */
364
else if( state == -1 )
366
else if( !state && isspace(c) )
367
; /* skip leading white space */
368
else if( !state && c == '#' )
369
state = 1; /* start of a comment */
370
else if( state == 1 )
371
; /* skip comments */
372
else if( state == 2 && isspace(c) ) {
374
for(i=0; opts[i].short_opt; i++ )
375
if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
378
arg->r_opt = opts[idx].short_opt;
379
if( !opts[idx].short_opt ) {
380
if( !strcmp( keyword, "alias" ) ) {
385
arg->r_opt = (opts[idx].flags & 256)? -7:-2;
386
state = -1; /* skip rest of line and leave */
392
else if( state == 3 ) { /* skip leading spaces of the argument */
399
else if( state == 4 ) { /* collect the argument */
405
buffer = jnlib_xrealloc(buffer, buflen);
409
else if( i < DIM(keyword)-1 )
412
buflen = DIM(keyword)+50;
413
buffer = jnlib_xmalloc(buflen);
414
memcpy(buffer, keyword, i);
418
else if( i >= DIM(keyword)-1 ) {
419
arg->r_opt = -4; /* keyword to long */
420
state = -1; /* skip rest of line and leave */
393
arg->r_opt = ARGPARSE_READ_ERROR;
395
arg->r_opt = 0; /* EOF. */
401
else if (state == -1)
403
else if (state == 0 && isascii (c) && isspace(c))
404
; /* Skip leading white space. */
405
else if (state == 0 && c == '#' )
406
state = 1; /* Start of a comment. */
408
; /* Skip comments. */
409
else if (state == 2 && isascii (c) && isspace(c))
413
for (i=0; opts[i].short_opt; i++ )
414
if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
417
arg->r_opt = opts[idx].short_opt;
418
if (!opts[idx].short_opt)
420
if (!strcmp (keyword, "alias"))
427
arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
428
? ARGPARSE_INVALID_COMMAND
429
: ARGPARSE_INVALID_OPTION);
430
state = -1; /* Skip rest of line and leave. */
438
/* Skip leading spaces of the argument. */
439
if (!isascii (c) || !isspace(c))
448
/* Collect the argument. */
456
size_t tmplen = buflen + 50;
458
tmp = jnlib_realloc (buffer, tmplen);
468
arg->r_opt = ARGPARSE_OUT_OF_CORE;
473
else if (i < DIM(keyword)-1)
477
size_t tmplen = DIM(keyword) + 50;
478
buffer = jnlib_malloc (tmplen);
482
memcpy(buffer, keyword, i);
487
arg->r_opt = ARGPARSE_OUT_OF_CORE;
492
else if (i >= DIM(keyword)-1)
494
arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
495
state = -1; /* Skip rest of line and leave. */
480
558
arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
488
initialize( arg, NULL, NULL );
491
idx = arg->internal.idx;
493
if( !idx && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */
494
argc--; argv++; idx++;
498
if( !argc ) { /* no more args */
500
goto leave; /* ready */
504
arg->internal.last = s;
506
if( arg->internal.stopped && (arg->flags & (1<<1)) ) {
507
arg->r_opt = -1; /* not an option but a argument */
510
argc--; argv++; idx++; /* set to next one */
512
else if( arg->internal.stopped ) { /* ready */
516
else if( *s == '-' && s[1] == '-' ) { /* long option */
519
arg->internal.inarg = 0;
520
if( !s[2] && !(arg->flags & (1<<3)) ) { /* stop option processing */
521
arg->internal.stopped = 1;
522
argc--; argv++; idx++;
526
argpos = strchr( s+2, '=' );
529
i = find_long_option( arg, opts, s+2 );
533
if( i < 0 && !strcmp( "help", s+2) )
534
show_help(opts, arg->flags);
535
else if( i < 0 && !strcmp( "version", s+2) ) {
536
if( !(arg->flags & (1<<6)) ) {
541
else if( i < 0 && !strcmp( "warranty", s+2) ) {
542
puts( strusage(16) );
545
else if( i < 0 && !strcmp( "dump-options", s+2) ) {
546
for(i=0; opts[i].short_opt; i++ ) {
547
if( opts[i].long_opt )
548
printf( "--%s\n", opts[i].long_opt );
550
fputs("--dump-options\n--help\n--version\n--warranty\n", stdout );
554
if( i == -2 ) /* ambiguous option */
558
arg->r.ret_str = s+2;
561
arg->r_opt = opts[i].short_opt;
564
else if( (opts[i].flags & 7) ) {
572
if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
573
arg->r_type = 0; /* because it is optional */
576
arg->r_opt = -3; /* missing argument */
578
else if( !argpos && *s2 == '-' && (opts[i].flags & 8) ) {
579
/* the argument is optional and the next seems to be
580
* an option. We do not check this possible option
581
* but assume no argument */
585
set_opt_arg(arg, opts[i].flags, s2);
587
argc--; argv++; idx++; /* skip one */
566
initialize( arg, NULL, NULL );
569
idx = arg->internal.idx;
571
if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
573
/* Skip the first argument. */
574
argc--; argv++; idx++;
582
goto leave; /* Ready. */
586
arg->internal.last = s;
588
if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL))
590
arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */
593
argc--; argv++; idx++; /* set to next one */
595
else if( arg->internal.stopped )
598
goto leave; /* Ready. */
600
else if ( *s == '-' && s[1] == '-' )
605
arg->internal.inarg = 0;
606
if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
608
/* Stop option processing. */
609
arg->internal.stopped = 1;
610
argc--; argv++; idx++;
614
argpos = strchr( s+2, '=' );
617
i = find_long_option ( arg, opts, s+2 );
621
if ( i < 0 && !strcmp ( "help", s+2) )
622
show_help (opts, arg->flags);
623
else if ( i < 0 && !strcmp ( "version", s+2) )
625
if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
631
else if ( i < 0 && !strcmp( "warranty", s+2))
633
puts ( strusage (16) );
636
else if ( i < 0 && !strcmp( "dump-options", s+2) )
638
for (i=0; opts[i].short_opt; i++ )
640
if ( opts[i].long_opt )
641
printf ("--%s\n", opts[i].long_opt);
643
fputs ("--dump-options\n--help\n--version\n--warranty\n", stdout);
648
arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
651
arg->r_opt = ARGPARSE_INVALID_OPTION;
652
arg->r.ret_str = s+2;
655
arg->r_opt = opts[i].short_opt;
658
else if ( (opts[i].flags & 0x07) )
668
if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
670
arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */
674
arg->r_opt = ARGPARSE_MISSING_ARG;
676
else if ( !argpos && *s2 == '-'
677
&& (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
679
/* The argument is optional and the next seems to be an
680
option. We do not check this possible option but
681
assume no argument */
682
arg->r_type = ARGPARSE_TYPE_NONE;
686
set_opt_arg (arg, opts[i].flags, s2);
689
argc--; argv++; idx++; /* Skip one. */
591
else { /* does not take an argument */
593
arg->r_type = -6; /* argument not expected */
695
/* Does not take an argument. */
697
arg->r_type = ARGPARSE_UNEXPECTED_ARG;
597
argc--; argv++; idx++; /* set to next one */
701
argc--; argv++; idx++; /* Set to next one. */
599
else if( (*s == '-' && s[1]) || arg->internal.inarg ) { /* short option */
703
else if ( (*s == '-' && s[1]) || arg->internal.inarg )
600
706
int dash_kludge = 0;
602
if( !arg->internal.inarg ) {
709
if ( !arg->internal.inarg )
603
711
arg->internal.inarg++;
604
if( arg->flags & (1<<5) ) {
605
for(i=0; opts[i].short_opt; i++ )
606
if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+1)) {
712
if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
714
for (i=0; opts[i].short_opt; i++ )
715
if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1))
612
722
s += arg->internal.inarg;
615
for(i=0; opts[i].short_opt; i++ )
616
if( opts[i].short_opt == *s )
620
if( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
621
show_help(opts, arg->flags);
726
for (i=0; opts[i].short_opt; i++ )
727
if ( opts[i].short_opt == *s )
731
if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
732
show_help (opts, arg->flags);
623
734
arg->r_opt = opts[i].short_opt;
624
if( !opts[i].short_opt ) {
625
arg->r_opt = (opts[i].flags & 256)? -7:-2;
626
arg->internal.inarg++; /* point to the next arg */
735
if (!opts[i].short_opt )
737
arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
738
ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
739
arg->internal.inarg++; /* Point to the next arg. */
627
740
arg->r.ret_str = s;
629
else if( (opts[i].flags & 7) ) {
630
if( s[1] && !dash_kludge ) {
742
else if ( (opts[i].flags & 7) )
744
if ( s[1] && !dash_kludge )
632
set_opt_arg(arg, opts[i].flags, s2);
747
set_opt_arg (arg, opts[i].flags, s2);
636
if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
637
arg->r_type = 0; /* because it is optional */
640
arg->r_opt = -3; /* missing argument */
642
else if( *s2 == '-' && s2[1] && (opts[i].flags & 8) ) {
643
/* the argument is optional and the next seems to be
644
* an option. We do not check this possible option
645
* but assume no argument */
649
set_opt_arg(arg, opts[i].flags, s2);
650
argc--; argv++; idx++; /* skip one */
653
s = "x"; /* so that !s[1] yields false */
655
else { /* does not take an argument */
657
arg->internal.inarg++; /* point to the next arg */
659
if( !s[1] || dash_kludge ) { /* no more concatenated short options */
752
if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
754
arg->r_type = ARGPARSE_TYPE_NONE;
758
arg->r_opt = ARGPARSE_MISSING_ARG;
760
else if ( *s2 == '-' && s2[1]
761
&& (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
763
/* The argument is optional and the next seems to
764
be an option. We do not check this possible
765
option but assume no argument. */
766
arg->r_type = ARGPARSE_TYPE_NONE;
770
set_opt_arg (arg, opts[i].flags, s2);
771
argc--; argv++; idx++; /* Skip one. */
774
s = "x"; /* This is so that !s[1] yields false. */
778
/* Does not take an argument. */
779
arg->r_type = ARGPARSE_TYPE_NONE;
780
arg->internal.inarg++; /* Point to the next arg. */
782
if ( !s[1] || dash_kludge )
784
/* No more concatenated short options. */
660
785
arg->internal.inarg = 0;
661
786
argc--; argv++; idx++;
664
else if( arg->flags & (1<<2) ) {
665
arg->r_opt = -1; /* not an option but a argument */
668
argc--; argv++; idx++; /* set to next one */
671
arg->internal.stopped = 1; /* stop option processing */
789
else if ( arg->flags & ARGPARSE_FLAG_MIXED )
791
arg->r_opt = ARGPARSE_IS_ARG;
794
argc--; argv++; idx++; /* Set to next one. */
798
arg->internal.stopped = 1; /* Stop option processing. */
678
arg->internal.idx = idx;
805
arg->internal.idx = idx;
743
872
* bar and the next one as arguments of the long option.
746
show_help( ARGPARSE_OPTS *opts, unsigned flags )
875
show_help (ARGPARSE_OPTS *opts, unsigned int flags)
883
if ( opts[0].description )
885
/* Auto format the option description. */
754
if( opts[0].description ) { /* auto format the option description */
756
/* get max. length of long options */
757
for(i=indent=0; opts[i].short_opt; i++ ) {
758
if( opts[i].long_opt )
759
if( !opts[i].description || *opts[i].description != '@' )
760
if( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
888
/* Get max. length of long options. */
889
for (i=indent=0; opts[i].short_opt; i++ )
891
if ( opts[i].long_opt )
892
if ( !opts[i].description || *opts[i].description != '@' )
893
if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
763
/* example: " -v, --verbose Viele Sachen ausgeben" */
765
if( *opts[0].description != '@' )
767
for(i=0; opts[i].short_opt; i++ ) {
768
s = _( opts[i].description );
769
if( s && *s== '@' && !s[1] ) /* hide this line */
771
if( s && *s == '@' ) { /* unindented comment only line */
785
if( opts[i].short_opt < 256 ) {
786
printf(" -%c", opts[i].short_opt );
787
if( !opts[i].long_opt ) {
788
if(s && *s == '|' ) {
790
for(s++ ; *s && *s != '|'; s++, j++ )
799
if( opts[i].long_opt ) {
800
j += printf("%c --%s", opts[i].short_opt < 256?',':' ',
802
if(s && *s == '|' ) {
807
for( ; *s && *s != '|'; s++, j++ )
815
for(;j < indent; j++ )
818
if( *s && j > indent ) {
820
for(j=0;j < indent; j++ )
827
for(j=0;j < indent; j++ )
897
/* Example: " -v, --verbose Viele Sachen ausgeben" */
899
if ( *opts[0].description != '@' )
901
for (i=0; opts[i].short_opt; i++ )
903
s = _( opts[i].description );
904
if ( s && *s== '@' && !s[1] ) /* Hide this line. */
906
if ( s && *s == '@' ) /* Unindented comment only line. */
923
if ( opts[i].short_opt < 256 )
925
printf (" -%c", opts[i].short_opt);
926
if ( !opts[i].long_opt )
931
for (s++ ; *s && *s != '|'; s++, j++ )
940
if ( opts[i].long_opt )
942
j += printf ("%c --%s", opts[i].short_opt < 256?',':' ',
951
for ( ; *s && *s != '|'; s++, j++ )
959
for (;j < indent; j++ )
963
if ( *s && j > indent )
966
for (j=0;j < indent; j++ )
976
for (j=0; j < indent; j++ )
838
puts("\n(A single dash may be used instead of the double ones)");
840
if( (s=strusage(19)) ) { /* bug reports to ... */
844
s2 = strstr (s, "@EMAIL@");
848
fwrite (s, s2-s, 1, stdout);
849
fputs (PACKAGE_BUGREPORT, stdout);
986
if ( (flags & ARGPARSE_FLAG_ONEDASH) )
987
puts ("\n(A single dash may be used instead of the double ones)");
989
if ( (s=strusage(19)) )
991
/* bug reports to ... */
995
s2 = strstr (s, "@EMAIL@");
999
fwrite (s, s2-s, 1, stdout);
1000
#ifdef PACKAGE_BUGREPORT
1001
fputs (PACKAGE_BUGREPORT, stdout);
1003
fputs ("bug@example.org", stdout);
992
1153
main(int argc, char **argv)
994
ARGPARSE_OPTS opts[] = {
995
{ 'v', "verbose", 0 , "Laut sein"},
996
{ 'e', "echo" , 0 , ("Zeile ausgeben, damit wir sehen, was wir ein"
998
{ 'd', "debug", 0 , "Debug\nfalls mal etwas\nschief geht"},
999
{ 'o', "output", 2 },
1000
{ 'c', "cross-ref", 2|8, "cross-reference erzeugen\n" },
1155
ARGPARSE_OPTS opts[] = {
1156
ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"),
1157
ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, "
1158
"was wir ein gegeben haben")),
1159
ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
1160
ARGPARSE_s_s('o', "output", 0 ),
1161
ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ),
1001
1162
/* Note that on a non-utf8 terminal the ß might garble the output. */
1002
{ 's', "street", 0, "|Straße|set the name of the street to Straße" },
1003
{ 'm', "my-option", 1|8 },
1004
{ 500, "a-long-option", 0 },
1006
ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 };
1163
ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
1164
ARGPARSE_o_i('m', "my-option", 0),
1165
ARGPARSE_s_n(500, "a-long-option", 0 ),
1168
ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 };
1009
1171
while( arg_parse ( &pargs, opts) ) {