~ubuntu-branches/ubuntu/oneiric/gnupg2/oneiric-updates

« back to all changes in this revision

Viewing changes to util/argparse.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-10-04 10:25:53 UTC
  • mfrom: (5.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20081004102553-fv62pp8dsitxli47
Tags: 2.0.9-3.1
* Non-maintainer upload.
* agent/gpg-agent.c: Deinit the threading library before exec'ing
  the command to run in --daemon mode. And because that still doesn't
  restore the sigprocmask, do that manually. Closes: #499569

Show diffs side-by-side

added added

removed removed

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