Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
313 dpurdie 1
/* -*- c: tabs: 4 -*- ******************************************************
2
* Module name   : getopt
3
* Module type   : Core Services
4
* Compiler(s)   : ANSI C
5
* Environment(s): n/a
6
*
7
* Description:
8
*                 
9
    Command line option parsing
10
*
11
* Provides user functions
12
*
13
    getopt
14
    getoptl
15
*
16
* Contants:
17
*
18
    n/a
19
*
20
* Version   Who      Date        Description 
21
  1.0       APY      02/06/97    Long argument version.
22
  1.1       APY      07/05/98    Core Services
23
*
24
* $Name:  $
25
* $Source: /cvsroot/device/DEVL/UTILS/CMDFILE/getopt.c,v $            
26
* $Revision: 1.2 $ $Date: 2004/05/10 03:47:05 $ $State: Exp $    
27
* $Author: ayoung $ $Locker:  $
28
*/
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include "cmdfile.h"
33
#include "getopt.h"
34
 
35
#ifndef index
36
#define index               strchr
37
#define rindex              strrchr
38
#endif
39
 
40
 
41
/*
42
 * get option letter from argument vector
43
 */
44
#ifndef sun
45
int     opterr = 1,         /* if error message should be printed */
46
        optind = 1;         /* index into parent argv vector */
47
#else
48
extern  int opterr;
49
extern  int optind;
50
#endif
51
int     optopt,             /* character checked for validity */
52
        optlidx = -1;       /* long index */
53
char    *optarg;            /* argument associated with option */
54
 
55
#define BADCH               (int)'?'
56
#define EMSG                ""
57
 
58
 
59
 
60
 
61
/*----------------------------------------------------------------------------
62
    Synopsis:
63
        #include <getopt.h>
64
        int getopt
65
            (
66
                int nargc,
67
                char *const *nargv,
68
                const char *ostr
69
            )  
70
 
71
        extern int  optarg; 
72
        extern int  optind; 
73
        extern int  opterr;
74
 
75
        int CsGetoptl
76
            (
77
                int nargc,
78
                char *const *nargv,
79
                const char *ostr,
80
                const struct option *lopt,
81
                int long_only
82
            )
83
 
84
        extern int  optlidx;
85
 
86
    MT-Level:
87
        Unsafe                
88
 
89
    Purpose:
90
        The CsGetopt function returns the next option letter
91
        in 'argv' that matches a letter in 'ostr'.  It supports
92
        all the rules of the command syntax standard (see below).
93
        This function is the functional replacement of the
94
        standard UNIX getopt() function.
95
 
96
        The CsGetoptl functions extends the command syntax 
97
        including support for long options.
98
 
99
        'ostr' must contain the option letters the command using
100
        CsGetopt()/CsGetoptl() will recognize; if a letter is
101
        followed by a colon,  the option is expected to have
102
        an argument,  or group of arguments,  which may be
103
        separated from it by white space. 'optarg' is set to
104
        point to the start of the option argument on return.
105
 
106
        'optind' represents the 'argv' index of the next
107
        argument to be processed.  'optind' is external and
108
        is initialised to 1 before the first call.  When all
109
        options have been processed (that is, up to the
110
        first non-option argument), EOF is returned.  The 
111
        special option "--" (two hyphens) may be used to delimit
112
        the end of the options;  when it is encountered, EOF is
113
        returned and  "--"'  is skipped.   This is useful in 
114
        delimiting non-option arguments that begin with
115
        ``-'' (hyphen). 
116
 
117
        The additional parameters to CsGetoptl() enable long 
118
        argument handling. 'lopt' defines the argument names
119
        and 'long_only' is used to specify whether long
120
        options are only matched when preceded with "--" or
121
        or long and short arguments can be mixed.
122
 
123
        'optlidx' represents the 'lopt' index of the matched 
124
        long argument, initialised to -1 upon each call.
125
 
126
 
127
    Parameters:
128
 
129
        nargc,          Number of command line arguments.
130
 
131
        nargv,          The NULL terinated argument list.
132
 
133
        ostr,           Argument syntax specification
134
 
135
        lopt,           Specifies the pointer to the long argument list
136
 
137
                        struct option
138
                        {
139
                          char *name;   Option name 
140
                          int has_arg;  0=none, 1=required, 2=optional
141
                          int *flag;    Value buffer                 
142
                          int val;      value return on detection
143
                        };
144
 
145
                        The 'name' fields contains the address of the
146
                        NUL terminated string command label.  'has_arg' 
147
                        speicfies the whether an associated argument
148
                        isn't excepted (0), is required (1), or is 
149
                        optional (2).
150
 
151
                        The following manifest constants are defined for
152
                        use within the 'has_arg' field:
153
 
154
                        no_argument         No argument expected
155
                        required_argument   An argument must be supplied
156
                        optional_argument   An optional argument
157
 
158
                        'flag' is the optional address of the buffer
159
                        assigned with the value of argument. 'val' states
160
                        the value to be returned upon the given option
161
                        being encountered.
162
 
163
        long_only,      When specified as non-zero, long arguments are
164
                        only matched when preceded with "--".
165
 
166
    Command Syntax Standard:    
167
 
168
        The following command syntax should be obeyed. The 
169
        CsGetopt function supports Rules 3-10 below. Rules
170
        10b-10c are only active during long argument processing.
171
        The enforcement of the other rules must be done by
172
        the command itself.
173
 
174
        1.  Command names (name above) must be between two and
175
            nine characters long.
176
 
177
        2.  Command names must include only lower-case letters
178
            and digits.
179
 
180
        3.  Option names (option above) must be one character
181
            long.
182
 
183
        4.  All options must be preceded by "-".
184
 
185
        5.  Options with no arguments may be grouped after a
186
            single "-".
187
 
188
        6.  The first option-argument (optarg above) following
189
            an option must be preceded by a tab or space character.
190
 
191
        7.  Option-arguments cannot be optional.
192
 
193
        8.  Groups of option-arguments following an option
194
            must either be separated by commas or separated by
195
            tab or space character and quoted (-o xxx,z,yy or
196
            -o "xxx z yy").			  
197
 
198
        9.  All options must precede operands (cmdarg above)
199
            on the command line.
200
 
201
        10. "--" may be used to indicate the end of the options.
202
 
203
        10b "--" may precede a long option.
204
 
205
        10c If a command element has the form "-f", where f is a
206
            valid short option, don't consider it an abbreviated
207
            form of a long option that starts with f.  Otherwise
208
            there would be no way to give the -f short option.
209
 
210
            On the other hand, if there's a long option "fubar"
211
            and the command element is "-fu",  do consider that an
212
            abbreviation of the long option, just like "--fu", 
213
            and not "-f" with arg "u".
214
 
215
        11. The order of the options relative to one another
216
            should not matter.                      
217
 
218
        12. The relative order of the operands (cmdarg  above)
219
            may affect their significance in ways determined
220
            by the command with which they appear.
221
 
222
        13. "-" preceded and followed by a space character
223
            should only be used to mean standard input.
224
 
225
    Returns:    int - 
226
 
227
        The CsGetopt functions return the character matched, otherwise
228
        EOF at the end of input stream, or '?' upon a parer error.
229
 
230
        The parser prints an error message on the standard error
231
        and returns a "?" (question mark) when it encounters an option
232
        letter not included in 'ostr' or 'lopt' or no argument is located 
233
        after an option that expects one.  Error messages may be
234
        disabled by setting 'opterr' to 0.  The value of the character
235
        that caused the error is in 'optopt'.
236
 
237
        In addition CsGetoptl() generates messages when ambiguous
238
        arguments between the short and long selections are presented.
239
 
240
    Examples:
241
 
242
        The following code fragment shows how one might process  the
243
        arguments for a command that can take the mutually exclusive
244
        options a and b, and the option o, which requires an
245
        argument:                  
246
 
247
        #include <stdlib.h>
248
        #include <stdio.h>
249
        #include <csgetopt.h>
250
 
251
        int main(int argc, char **argv)
252
        {          
253
            int  aflg=0, bflg=0, errflg=0, c;
254
            char *ofile = NULL;
255
 
256
            while ((c = CsGetopt(argc, argv, "abo:")) != EOF)
257
                switch (c) {
258
                case 'a':
259
                    if (bflg)
260
                         errflg++;
261
                    else aflg++;
262
                    break;
263
                case 'b':
264
                    if (aflg)
265
                         errflg++;
266
                    else bflg++;
267
                    break;
268
                case 'o':
269
                    ofile = optarg;
270
                    void)printf("ofile = %s\n", ofile);
271
                    break;
272
                case '?':
273
                    errflg++;
274
                }
275
            if (errflg) {
276
                (void)fprintf(stderr, 
277
                    "usage: cmd [-a|-b] [-o <filename>] files...\n");
278
                exit (2);
279
            }
280
            while(optind < argc)
281
                printf("%s\n", argv[optind++]);
282
        }       
283
 
284
 
285
        The following code fragment shows how one might process the
286
        arguments for a command that can take the options 'a' and 'b',
287
        plus 'verbose' and 'debug' which requires an argument:                              
288
 
289
        #include <stdlib.h>
290
        #include <stdio.h>
291
        #include <csgetopt.h>         
292
 
293
        static struct option longopts[] =
294
        {
295
            {"verbose", 0,  NULL,   'v'},
296
            {"debug",   1,  NULL,   'd'},  
297
        };                          
298
 
299
        int main(int argc, char **argv)
300
        {          
301
            int  aflg=0, bflg=0, debug=0, verbose=0, c;
302
 
303
            while ((c = CsGetoptl(argc, argv, "ab", longopts, 1)) != EOF)
304
                switch (c) {
305
                case 'a':
306
                    aflg++;
307
                    break;
308
                case 'b':
309
                    bflg++;
310
                    break;         
311
                case 'd':
312
                    debug = atoi(optarg);
313
                    break;
314
                case 'v':
315
                    verbose++;
316
                    break;
317
                case '?':
318
                    (void)fprintf(stderr, 
319
                        "usage: cmd [-ab] [-debug <lvl>] [-verbose] ...\n");
320
                    exit (2);                                           
321
                }
322
            : 
323
        }                  
324
 
325
----------------------------------------------------------------------------*/
326
int
327
getopt(
328
    int nargc, char *const *nargv, const char *ostr)
329
{
330
    return getoptl(nargc, nargv, ostr, NULL, 0);
331
}   
332
 
333
 
334
int
335
getopt_long(
336
    int nargc, char *const *nargv, const char *ostr, 
337
    const struct option *lopts, int *longind)
338
{
339
    int ret = getoptl(nargc, nargv, ostr, lopts, 0);
340
    if (longind)
341
        *longind = optlidx;
342
    return (ret);
343
}
344
 
345
 
346
int
347
getopt_long_only(
348
    int nargc, char *const *nargv, const char *ostr, 
349
    const struct option *lopts, int *longind)
350
{
351
    int ret = getoptl(nargc, nargv, ostr, lopts, 1);
352
    if (longind)
353
        *longind = optlidx;
354
    return (ret);
355
}
356
 
357
 
358
int 
359
getoptl(
360
    int nargc, char *const *nargv, const char *ostr, 
361
    const struct option *lopt, int long_only)
362
{
363
    static   char   *place = EMSG;      /* option letter processing */
364
    register char   *oli;               /* option letter list index */
365
    char     *pProg;
366
 
367
    if ((pProg = rindex(*nargv, '/')) == NULL)
368
        pProg = *nargv;
369
    else pProg++;
370
    optlidx = -1;
371
 
372
    if (!*place)
373
    {
374
    /* Update scanning pointer */
375
        if (optind >= nargc || *(place = nargv[optind]) != '-')
376
        {
377
            place = EMSG;
378
            return (EOF);
379
        }
380
        if (place[1] && *++place == '-')
381
        {
382
            if (!*++place)
383
            {
384
            /* Found "--" , meaning premature end of options */
385
                optind++;
386
                place = EMSG;
387
                return (EOF);
388
            }
389
        }
390
 
391
    /* Reference GCC 'getopt':
392
        * If ARGV-element has the form "-f", where f is a valid short
393
        * option, don't consider it an abbreviated form of a long
394
        * option that starts with f.  Otherwise there would be no way
395
        * to give the -f short option.
396
        * 
397
        * On the other hand, if there's a long option "fubar" and
398
        * the ARGV-element is "-fu",  do consider that an abbreviation
399
        * of the long option, just like "--fu", and not "-f" with
400
        * arg "u".
401
        * 
402
        * This distinction seems to be the most useful approach.
403
        */
404
        if (lopt != NULL && 
405
             (nargv[optind][1] == '-' || 
406
              (!long_only && (nargv[optind][2] || 
407
                    !index(ostr?ostr:"", nargv[optind][1])))))
408
        {
409
            const   struct option *pOpt;
410
            #define EXTRACT     1
411
            #define NONEXTRACT  2 
412
            #define AMBIGUOUS   4
413
            int     flags = 0;
414
            char    *pEnd;
415
            int     i;
416
 
417
        /* Test all long options for either exact match 
418
            *   or abbreviated matches.
419
            */
420
            for (pEnd = place; *pEnd && *pEnd != '='; pEnd++)
421
                ;
422
            for (pOpt=lopt, i=0; pOpt->name; pOpt++, i++)
423
                if (!strncmp(pOpt->name, place, pEnd-place))
424
                {
425
                    if ((int)(pEnd - place) == (int)strlen(pOpt->name))
426
                    {
427
                        flags &= ~AMBIGUOUS;
428
                        flags |= EXTRACT;       /* Exact match */
429
                        optlidx = i;
430
                        break;
431
                    }
432
                    if (flags & NONEXTRACT)
433
                        flags |= AMBIGUOUS;     /* Multiple match(s) */
434
                    else
435
                    {
436
                        flags |= NONEXTRACT;    /* Part match */
437
                        optlidx = i;
438
                    }
439
                }
440
            if (flags & AMBIGUOUS)
441
            {
442
                if (opterr)
443
                    (void) fprintf(stderr, 
444
                            "%s: option `%s' is ambiguous\n",
445
                            pProg, place);
446
                optind++;
447
                place = EMSG;
448
                return BADCH;
449
            }
450
 
451
        /* Long option match */
452
            if (flags & (EXTRACT|NONEXTRACT))
453
            {
454
                pOpt = lopt+optlidx;            
455
                optind++;
456
 
457
            /* Parse argument request */
458
                if (*pEnd)
459
                {
460
                    if (pOpt->has_arg)
461
                        optarg = pEnd+1;
462
                    else
463
                    {
464
                        if (opterr)
465
                        {
466
                            if (nargv[optind-1][1] == '-') 
467
                            {
468
                            /* Long format */
469
                                (void) fprintf(stderr,
470
                                    "%s: option `--%s' doesn't allow an argument\n",
471
                                    pProg, pOpt->name);
472
                            } else {
473
                            /* Short */
474
                                (void) fprintf(stderr,
475
                                    "%s: option `%c%s' doesn't allow an argument\n",
476
                                    pProg, nargv[optind-1][0], pOpt->name);
477
                            }
478
                        }
479
                        place = EMSG;
480
                        return BADCH;
481
                    }
482
                }
483
                else if (pOpt->has_arg)
484
                {                               
485
                    if (optind < nargc && 
486
                            strcmp(nargv[optind], "--") != 0)
487
                    {
488
                    /* Argument available (non-terminator) */
489
                        optarg = nargv[optind++];
490
                    }
491
                    else if (pOpt->has_arg != optional_argument)
492
                    {   
493
                    /* No argument */
494
                        if (opterr)
495
                            (void) fprintf(stderr,
496
                                "%s: option `%s' requires an argument\n",
497
                                   pProg, nargv[optind - 1]);
498
                        place = EMSG;
499
                        return (ostr && ostr[0] == ':' ? ':' : BADCH);
500
                    }                   
501
                    else
502
                    {                    
503
                        optarg = NULL;    /* Optional argument */
504
                    }                     
505
               }                     
506
 
507
            /* Return completion value */
508
                place = EMSG;
509
                if (pOpt->flag)
510
                {
511
                    *(pOpt->flag) = pOpt->val;
512
                    return 0;
513
                }
514
                return pOpt->val;
515
            }
516
 
517
        /* Can't find it as a long option.  If this is not 
518
            *   'long_only', or the option starts with '--' or 
519
            *   is not a valid short option, then it's an error.
520
            *
521
            *   Otherwise interpret it as a short option.  
522
            */
523
            if (!long_only || nargv[optind][1] == '-' || 
524
                    index(ostr ? ostr : "", *place) == NULL)
525
            {
526
                if (opterr)
527
                {
528
                    if (nargv[optind][1] == '-') {
529
                    /* Long format */
530
                        (void) fprintf(stderr, 
531
                                "%s: unrecognized option `--%s'\n",
532
                                pProg, place);
533
                    } else {
534
                    /* Short */
535
                        (void) fprintf(stderr, 
536
                                "%s: unrecognized option `%c%s'\n",
537
                                pProg, nargv[optind][0], place);
538
                    }
539
                }
540
                optind++;
541
                place = EMSG;
542
                return BADCH;
543
            }
544
        }
545
    }
546
 
547
/* Option letter okay? */
548
    if ((optopt = (int) *place++) == (int) ':' ||
549
            (oli = index(ostr, optopt)) == NULL)
550
    {
551
    /* If the user didn't specify '-' as an option, assume it means EOF */
552
        if (optopt == (int) '-')
553
            return (EOF);
554
        if (!*place)
555
            ++optind;
556
        if (opterr)
557
            (void) fprintf(stderr, 
558
                    "%s: illegal option -- %c\n", 
559
                    pProg, optopt);
560
        return (BADCH);
561
    }
562
 
563
/*LINTED*/
564
    if (*++oli != ':')
565
    { 
566
    /* Don't need argument */
567
        optarg = NULL;
568
        if (!*place)
569
            ++optind;
570
    } 
571
    else
572
    { 
573
    /* Need an argument */
574
        if (*place)
575
        { 
576
        /* No white space */
577
            optarg = place;
578
        } 
579
        else if (nargc <= ++optind || strcmp(nargv[optind], "--") == 0)
580
        {                                         
581
        /* No argument, or terminator encountered  */
582
            if (opterr)
583
                (void) fprintf(stderr, 
584
                    "%s: option requires an argument -- %c\n", 
585
                        pProg, optopt);
586
            place = EMSG;
587
            return (BADCH);
588
        } 
589
        else
590
        { 
591
        /* White space -- return next argument */
592
            optarg = nargv[optind];
593
        }
594
        place = EMSG;
595
        ++optind;
596
    }
597
    return (optopt);        /* Dump back option letter */
598
}
599
 
600