~vcs-imports/busybox/trunk

« back to all changes in this revision

Viewing changes to libbb/getopt32.c

  • Committer: Eric Andersen
  • Date: 1999-11-24 09:04:33 UTC
  • Revision ID: git-v1:b99df0fd65abe3245fa2d04115326100847f865e
First draft

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* vi: set sw=4 ts=4: */
2
 
/*
3
 
 * universal getopt32 implementation for busybox
4
 
 *
5
 
 * Copyright (C) 2003-2005  Vladimir Oleynik  <dzo@simtreas.ru>
6
 
 *
7
 
 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8
 
 */
9
 
#if ENABLE_LONG_OPTS
10
 
# include <getopt.h>
11
 
#endif
12
 
#include "libbb.h"
13
 
 
14
 
//kbuild:lib-y += getopt32.o
15
 
 
16
 
/*      Documentation
17
 
 
18
 
uint32_t
19
 
getopt32(char **argv, const char *applet_opts, ...)
20
 
 
21
 
        The command line options are passed as the applet_opts string.
22
 
 
23
 
        If one of the given options is found, a flag value is added to
24
 
        the return value.
25
 
 
26
 
        The flag value is determined by the position of the char in
27
 
        applet_opts string.  For example:
28
 
 
29
 
        flags = getopt32(argv, "rnug");
30
 
 
31
 
        "r" will set 1    (bit 0)
32
 
        "n" will set 2    (bit 1)
33
 
        "u" will set 4    (bit 2)
34
 
        "g" will set 8    (bit 3)
35
 
 
36
 
        and so on.  You can also look at the return value as a bit
37
 
        field and each option sets one bit.
38
 
 
39
 
        On exit, global variable optind is set so that if you
40
 
        will do argc -= optind; argv += optind; then
41
 
        argc will be equal to number of remaining non-option
42
 
        arguments, first one would be in argv[0], next in argv[1] and so on
43
 
        (options and their parameters will be moved into argv[]
44
 
        positions prior to argv[optind]).
45
 
 
46
 
 "o:"   If one of the options requires an argument, then add a ":"
47
 
        after the char in applet_opts and provide a pointer to store
48
 
        the argument.  For example:
49
 
 
50
 
        char *pointer_to_arg_for_a;
51
 
        char *pointer_to_arg_for_b;
52
 
        char *pointer_to_arg_for_c;
53
 
        char *pointer_to_arg_for_d;
54
 
 
55
 
        flags = getopt32(argv, "a:b:c:d:",
56
 
                        &pointer_to_arg_for_a, &pointer_to_arg_for_b,
57
 
                        &pointer_to_arg_for_c, &pointer_to_arg_for_d);
58
 
 
59
 
        The type of the pointer may be controlled by "o::" or "o+" in
60
 
        the external string opt_complementary (see below for more info).
61
 
 
62
 
 "o::"  If option can have an *optional* argument, then add a "::"
63
 
        after its char in applet_opts and provide a pointer to store
64
 
        the argument.  Note that optional arguments _must_
65
 
        immediately follow the option: -oparam, not -o param.
66
 
 
67
 
 "o:+"  This means that the parameter for this option is a nonnegative integer.
68
 
        It will be processed with xatoi_positive() - allowed range
69
 
        is 0..INT_MAX.
70
 
 
71
 
        int param;  // "unsigned param;" will also work
72
 
        getopt32(argv, "p:+", &param);
73
 
 
74
 
 "o:*"  This means that the option can occur multiple times. Each occurrence
75
 
        will be saved as a llist_t element instead of char*.
76
 
 
77
 
        For example:
78
 
        The grep applet can have one or more "-e pattern" arguments.
79
 
        In this case you should use getopt32() as follows:
80
 
 
81
 
        llist_t *patterns = NULL;
82
 
 
83
 
        (this pointer must be initializated to NULL if the list is empty
84
 
        as required by llist_add_to_end(llist_t **old_head, char *new_item).)
85
 
 
86
 
        getopt32(argv, "e:*", &patterns);
87
 
 
88
 
        $ grep -e user -e root /etc/passwd
89
 
        root:x:0:0:root:/root:/bin/bash
90
 
        user:x:500:500::/home/user:/bin/bash
91
 
 
92
 
 "^"    options string is "^optchars""\0""opt_complementary".
93
 
 
94
 
 "!"    If the first character in the applet_opts string is a '!',
95
 
        report bad options, missing required options,
96
 
        inconsistent options with all-ones return value (instead of abort.
97
 
 
98
 
 "+"    If the first character in the applet_opts string is a plus,
99
 
        then option processing will stop as soon as a non-option is
100
 
        encountered in the argv array.  Useful for applets like env
101
 
        which should not process arguments to subprograms:
102
 
        env -i ls -d /
103
 
        Here we want env to process just the '-i', not the '-d'.
104
 
 
105
 
        (The order of multiple prefixes must be "^!+...")
106
 
 
107
 
uint32_t
108
 
getopt32long(char **argv, const char *applet_opts, const char *logopts...)
109
 
 
110
 
        This allows you to define long options:
111
 
 
112
 
        static const char applet_longopts[] ALIGN1 =
113
 
                //"name\0"  has_arg     val
114
 
                "verbose\0" No_argument "v"
115
 
                ;
116
 
        opt = getopt32long(argv, applet_opts, applet_longopts, ...);
117
 
 
118
 
        The last element (val) typically is set to
119
 
        matching short option from applet_opts. If there is no matching
120
 
        char in applet_opts, then:
121
 
        - return bit has next position after short options
122
 
        - if has_arg is not "No_argument", use ptr for arg also
123
 
        - opt_complementary affects it too
124
 
 
125
 
        Note: a good applet will make long options configurable via the
126
 
        config process and not a required feature.  The current standard
127
 
        is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS.
128
 
 
129
 
opt_complementary - option modifiers.
130
 
 
131
 
 ":"    The colon (":") is used to separate groups of two or more chars
132
 
        and/or groups of chars and special characters (stating some
133
 
        conditions to be checked).
134
 
 
135
 
 "abc"  If groups of two or more chars are specified, the first char
136
 
        is the main option and the other chars are secondary options.
137
 
        Their flags will be turned on if the main option is found even
138
 
        if they are not specified on the command line.  For example:
139
 
 
140
 
        flags = getopt32(argv, "^abcd""\0""abc")
141
 
 
142
 
        If getopt() finds "-a" on the command line, then
143
 
        getopt32's return value will be as if "-a -b -c" were
144
 
        found.
145
 
 
146
 
 "ww"   Adjacent double options have a counter associated which indicates
147
 
        the number of occurrences of the option.
148
 
        For example the ps applet needs:
149
 
        if w is given once, GNU ps sets the width to 132,
150
 
        if w is given more than once, it is "unlimited"
151
 
 
152
 
        int w_counter = 0; // must be initialized!
153
 
        getopt32(argv, "^w""\0""ww", &w_counter);
154
 
        if (w_counter)
155
 
                width = (w_counter == 1) ? 132 : INT_MAX;
156
 
        else
157
 
                get_terminal_width(...&width...);
158
 
 
159
 
        w_counter is a pointer to an integer. It has to be passed to
160
 
        getopt32() after all other option argument sinks.
161
 
 
162
 
        For example: accept multiple -v to indicate the level of verbosity
163
 
        and for each -b optarg, add optarg to my_b. Finally, if b is given,
164
 
        turn off c and vice versa:
165
 
 
166
 
        llist_t *my_b = NULL;
167
 
        int verbose_level = 0;
168
 
        f = getopt32(argv, "^vb:*c"
169
 
                        "\0""vv:b-c:c-b"
170
 
                        , &my_b, &verbose_level);
171
 
        if (f & 2)       // -c after -b unsets -b flag
172
 
                while (my_b) dosomething_with(llist_pop(&my_b));
173
 
        if (my_b)        // but llist is stored if -b is specified
174
 
                free_llist(my_b);
175
 
        if (verbose_level) printf("verbose level is %d\n", verbose_level);
176
 
 
177
 
Special characters:
178
 
 
179
 
 "-N"   A dash as the first char in a opt_complementary group followed
180
 
        by a single digit (0-9) means that at least N non-option
181
 
        arguments must be present on the command line
182
 
 
183
 
 "=N"   An equal sign as the first char in a opt_complementary group followed
184
 
        by a single digit (0-9) means that exactly N non-option
185
 
        arguments must be present on the command line
186
 
 
187
 
 "?N"   A "?" as the first char in a opt_complementary group followed
188
 
        by a single digit (0-9) means that at most N arguments must be present
189
 
        on the command line.
190
 
 
191
 
 "V-"   An option with dash before colon or end-of-line results in
192
 
        bb_show_usage() being called if this option is encountered.
193
 
        This is typically used to implement "print verbose usage message
194
 
        and exit" option.
195
 
 
196
 
 "a-b"  A dash between two options causes the second of the two
197
 
        to be unset (and ignored) if it is given on the command line.
198
 
 
199
 
        [FIXME: what if they are the same? like "x-x"? Is it ever useful?]
200
 
 
201
 
        For example:
202
 
        The du applet has the options "-s" and "-d depth".  If
203
 
        getopt32 finds -s, then -d is unset or if it finds -d
204
 
        then -s is unset.  (Note:  busybox implements the GNU
205
 
        "--max-depth" option as "-d".)  To obtain this behavior, you
206
 
        set opt_complementary to "s-d:d-s".  Only one flag value is
207
 
        added to getopt32's return value depending on the
208
 
        position of the options on the command line.  If one of the
209
 
        two options requires an argument pointer (":" in applet_opts
210
 
        as in "d:") optarg is set accordingly.
211
 
 
212
 
        char *smax_print_depth;
213
 
 
214
 
        opt = getopt32(argv, "^sd:x""\0""s-d:d-s:x-x", &smax_print_depth);
215
 
 
216
 
        if (opt & 2)
217
 
                max_print_depth = atoi(smax_print_depth);
218
 
        if (opt & 4)
219
 
                printf("Detected odd -x usage\n");
220
 
 
221
 
 "a--b" A double dash between two options, or between an option and a group
222
 
        of options, means that they are mutually exclusive.  Unlike
223
 
        the "-" case above, an error will be forced if the options
224
 
        are used together.
225
 
 
226
 
        For example:
227
 
        The cut applet must have only one type of list specified, so
228
 
        -b, -c and -f are mutually exclusive and should raise an error
229
 
        if specified together.  In this case you must set
230
 
        opt_complementary to "b--cf:c--bf:f--bc".  If two of the
231
 
        mutually exclusive options are found, getopt32 will call
232
 
        bb_show_usage() and die.
233
 
 
234
 
 "x--x" Variation of the above, it means that -x option should occur
235
 
        at most once.
236
 
 
237
 
 "o+"   A plus after a char in opt_complementary means that the parameter
238
 
        for this option is a nonnegative integer. It will be processed
239
 
        with xatoi_positive() - allowed range is 0..INT_MAX.
240
 
 
241
 
        int param;  // "unsigned param;" will also work
242
 
        getopt32(argv, "^p:""\0""p+", &param);
243
 
 
244
 
 "o::"  A double colon after a char in opt_complementary means that the
245
 
        option can occur multiple times. Each occurrence will be saved as
246
 
        a llist_t element instead of char*.
247
 
 
248
 
        For example:
249
 
        The grep applet can have one or more "-e pattern" arguments.
250
 
        In this case you should use getopt32() as follows:
251
 
 
252
 
        llist_t *patterns = NULL;
253
 
 
254
 
        (this pointer must be initializated to NULL if the list is empty
255
 
        as required by llist_add_to_end(llist_t **old_head, char *new_item).)
256
 
 
257
 
        getopt32(argv, "^e:""\0""e::", &patterns);
258
 
 
259
 
        $ grep -e user -e root /etc/passwd
260
 
        root:x:0:0:root:/root:/bin/bash
261
 
        user:x:500:500::/home/user:/bin/bash
262
 
 
263
 
        "o+" and "o::" can be handled by "o:+" and "o:*" specifiers
264
 
        in option string (and it is preferred), but this does not work
265
 
        for "long options only" cases, such as tar --exclude=PATTERN,
266
 
        wget --header=HDR cases.
267
 
 
268
 
 "a?b"  A "?" between an option and a group of options means that
269
 
        at least one of them is required to occur if the first option
270
 
        occurs in preceding command line arguments.
271
 
 
272
 
        For example from "id" applet:
273
 
 
274
 
        // Don't allow -n -r -rn -ug -rug -nug -rnug
275
 
        flags = getopt32(argv, "^rnug""\0""r?ug:n?ug:u--g:g--u");
276
 
 
277
 
        This example allowed only:
278
 
        $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng
279
 
 
280
 
 "X"    A opt_complementary group with just a single letter means
281
 
        that this option is required. If more than one such group exists,
282
 
        at least one option is required to occur (not all of them).
283
 
        For example from "start-stop-daemon" applet:
284
 
 
285
 
        // Don't allow -KS -SK, but -S or -K is required
286
 
        flags = getopt32(argv, "^KS...""\0""K:S:K--S:S--K");
287
 
 
288
 
 
289
 
        Don't forget to use ':'. For example, "?322-22-23X-x-a"
290
 
        is interpreted as "?3:22:-2:2-2:2-3Xa:2--x" -
291
 
        max 3 args; count uses of '-2'; min 2 args; if there is
292
 
        a '-2' option then unset '-3', '-X' and '-a'; if there is
293
 
        a '-2' and after it a '-x' then error out.
294
 
        But it's far too obfuscated. Use ':' to separate groups.
295
 
*/
296
 
 
297
 
/* Code here assumes that 'unsigned' is at least 32 bits wide */
298
 
 
299
 
const char *const bb_argv_dash[] ALIGN_PTR = { "-", NULL };
300
 
 
301
 
enum {
302
 
        PARAM_STRING,
303
 
        PARAM_LIST,
304
 
        PARAM_INT,
305
 
};
306
 
 
307
 
typedef struct {
308
 
        unsigned char opt_char;
309
 
        smallint param_type;
310
 
        unsigned switch_on;
311
 
        unsigned switch_off;
312
 
        unsigned incongruously;
313
 
        unsigned requires;
314
 
        void **optarg;  /* char**, llist_t** or int *. */
315
 
        int *counter;
316
 
} t_complementary;
317
 
 
318
 
uint32_t option_mask32;
319
 
 
320
 
#if ENABLE_LONG_OPTS
321
 
static const struct option bb_null_long_options[1] = {
322
 
        { 0, 0, 0, 0 }
323
 
};
324
 
#else
325
 
#define vgetopt32(argv,applet_opts,applet_long_options,p) \
326
 
        vgetopt32(argv,applet_opts,p)
327
 
#endif
328
 
 
329
 
/* Please keep getopt32 free from xmalloc */
330
 
 
331
 
static uint32_t
332
 
vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, va_list p)
333
 
{
334
 
        int argc;
335
 
        unsigned flags = 0;
336
 
        unsigned requires = 0;
337
 
        unsigned len;
338
 
        t_complementary complementary[33]; /* last stays zero-filled */
339
 
        char dont_die_flag;
340
 
        int c;
341
 
        const unsigned char *s;
342
 
        const char *opt_complementary;
343
 
        t_complementary *on_off;
344
 
#if ENABLE_LONG_OPTS
345
 
        const struct option *l_o;
346
 
        struct option *long_options = (struct option *) &bb_null_long_options;
347
 
#endif
348
 
        unsigned trigger;
349
 
        int min_arg = 0;
350
 
        int max_arg = -1;
351
 
        int spec_flgs = 0;
352
 
 
353
 
#define SHOW_USAGE_IF_ERROR     1
354
 
 
355
 
        on_off = complementary;
356
 
        memset(on_off, 0, sizeof(complementary));
357
 
 
358
 
        len = strlen(applet_opts);
359
 
 
360
 
        /* skip bbox extension */
361
 
        opt_complementary = NULL;
362
 
        if (applet_opts[0] == '^') {
363
 
                applet_opts++;
364
 
                /* point it past terminating NUL */
365
 
                opt_complementary = applet_opts + len;
366
 
        }
367
 
 
368
 
        /* skip another bbox extension */
369
 
        dont_die_flag = applet_opts[0];
370
 
        if (dont_die_flag == '!')
371
 
                applet_opts++;
372
 
 
373
 
        applet_opts = strcpy(alloca(len + 1), applet_opts);
374
 
 
375
 
        /* skip GNU extension */
376
 
        s = (const unsigned char *)applet_opts;
377
 
        if (*s == '+' || *s == '-')
378
 
                s++;
379
 
        c = 0;
380
 
        while (*s) {
381
 
                if (c >= 32)
382
 
                        break;
383
 
                on_off->opt_char = *s;
384
 
                on_off->switch_on = (1U << c);
385
 
                if (*++s == ':') {
386
 
                        on_off->optarg = va_arg(p, void **);
387
 
                        if (s[1] == '+' || s[1] == '*') {
388
 
                                /* 'o:+' or 'o:*' */
389
 
                                on_off->param_type = (s[1] == '+') ?
390
 
                                        PARAM_INT : PARAM_LIST;
391
 
                                overlapping_strcpy((char*)s + 1, (char*)s + 2);
392
 
                        }
393
 
                        /* skip possible 'o::' (or 'o:+:' !) */
394
 
                        while (*++s == ':')
395
 
                                continue;
396
 
                }
397
 
                on_off++;
398
 
                c++;
399
 
        }
400
 
 
401
 
#if ENABLE_LONG_OPTS
402
 
        if (applet_long_options) {
403
 
                const char *optstr;
404
 
                unsigned i, count;
405
 
 
406
 
                count = 1;
407
 
                optstr = applet_long_options;
408
 
                while (optstr[0]) {
409
 
                        optstr += strlen(optstr) + 3; /* skip NUL, has_arg, val */
410
 
                        count++;
411
 
                }
412
 
                /* count == no. of longopts + 1 */
413
 
                long_options = alloca(count * sizeof(*long_options));
414
 
                memset(long_options, 0, count * sizeof(*long_options));
415
 
                i = 0;
416
 
                optstr = applet_long_options;
417
 
                while (--count) {
418
 
                        long_options[i].name = optstr;
419
 
                        optstr += strlen(optstr) + 1;
420
 
                        long_options[i].has_arg = (unsigned char)(*optstr++);
421
 
                        /* long_options[i].flag = NULL; */
422
 
                        long_options[i].val = (unsigned char)(*optstr++);
423
 
                        i++;
424
 
                }
425
 
                for (l_o = long_options; l_o->name; l_o++) {
426
 
                        if (l_o->flag)
427
 
                                continue;
428
 
                        for (on_off = complementary; on_off->opt_char; on_off++)
429
 
                                if (on_off->opt_char == l_o->val)
430
 
                                        goto next_long;
431
 
                        if (c >= 32)
432
 
                                break;
433
 
                        on_off->opt_char = l_o->val;
434
 
                        on_off->switch_on = (1U << c);
435
 
                        if (l_o->has_arg != no_argument)
436
 
                                on_off->optarg = va_arg(p, void **);
437
 
                        c++;
438
 
 next_long: ;
439
 
                }
440
 
        }
441
 
#endif /* ENABLE_LONG_OPTS */
442
 
 
443
 
        s = (const unsigned char *)opt_complementary;
444
 
        if (s) for (; *s; s++) {
445
 
                t_complementary *pair;
446
 
                unsigned *pair_switch;
447
 
 
448
 
                if (*s == ':')
449
 
                        continue;
450
 
                c = s[1];
451
 
                if (*s == '?') {
452
 
                        if (c < '0' || c > '9') {
453
 
                                spec_flgs |= SHOW_USAGE_IF_ERROR;
454
 
                        } else {
455
 
                                max_arg = c - '0';
456
 
                                s++;
457
 
                        }
458
 
                        continue;
459
 
                }
460
 
                if (*s == '-') {
461
 
                        if (c >= '0' && c <= '9') {
462
 
                                min_arg = c - '0';
463
 
                                s++;
464
 
                        }
465
 
                        continue;
466
 
                }
467
 
                if (*s == '=') {
468
 
                        min_arg = max_arg = c - '0';
469
 
                        s++;
470
 
                        continue;
471
 
                }
472
 
                for (on_off = complementary; on_off->opt_char; on_off++)
473
 
                        if (on_off->opt_char == *s)
474
 
                                goto found_opt;
475
 
                /* Without this, diagnostic of such bugs is not easy */
476
 
                bb_error_msg_and_die("NO OPT %c!", *s);
477
 
 found_opt:
478
 
                if (c == ':' && s[2] == ':') {
479
 
                        on_off->param_type = PARAM_LIST;
480
 
                        continue;
481
 
                }
482
 
                if (c == '+' && (s[2] == ':' || s[2] == '\0')) {
483
 
                        on_off->param_type = PARAM_INT;
484
 
                        s++;
485
 
                        continue;
486
 
                }
487
 
                if (c == ':' || c == '\0') {
488
 
                        requires |= on_off->switch_on;
489
 
                        continue;
490
 
                }
491
 
                if (c == '-' && (s[2] == ':' || s[2] == '\0')) {
492
 
                        flags |= on_off->switch_on;
493
 
                        on_off->incongruously |= on_off->switch_on;
494
 
                        s++;
495
 
                        continue;
496
 
                }
497
 
                if (c == *s) {
498
 
                        on_off->counter = va_arg(p, int *);
499
 
                        s++;
500
 
                }
501
 
                pair = on_off;
502
 
                pair_switch = &pair->switch_on;
503
 
                for (s++; *s && *s != ':'; s++) {
504
 
                        if (*s == '?') {
505
 
                                pair_switch = &pair->requires;
506
 
                        } else if (*s == '-') {
507
 
                                if (pair_switch == &pair->switch_off)
508
 
                                        pair_switch = &pair->incongruously;
509
 
                                else
510
 
                                        pair_switch = &pair->switch_off;
511
 
                        } else {
512
 
                                for (on_off = complementary; on_off->opt_char; on_off++)
513
 
                                        if (on_off->opt_char == *s) {
514
 
                                                *pair_switch |= on_off->switch_on;
515
 
                                                break;
516
 
                                        }
517
 
                        }
518
 
                }
519
 
                s--;
520
 
        }
521
 
 
522
 
        /* In case getopt32 was already called:
523
 
         * reset libc getopt() internal state.
524
 
         * run_nofork_applet() does this, but we might end up here
525
 
         * also via gunzip_main() -> gzip_main(). Play safe.
526
 
         */
527
 
        GETOPT_RESET();
528
 
 
529
 
        /* skip 0: some applets cheat: they do not actually HAVE argv[0] */
530
 
        argc = 1 + string_array_len(argv + 1);
531
 
 
532
 
        /* Note: just "getopt() <= 0" will not work well for
533
 
         * "fake" short options, like this one:
534
 
         * wget $'-\203' "Test: test" http://kernel.org/
535
 
         * (supposed to act as --header, but doesn't) */
536
 
#if ENABLE_LONG_OPTS
537
 
        while ((c = getopt_long(argc, argv, applet_opts,
538
 
                        long_options, NULL)) != -1) {
539
 
#else
540
 
        while ((c = getopt(argc, argv, applet_opts)) != -1) {
541
 
#endif
542
 
                /* getopt prints "option requires an argument -- X"
543
 
                 * and returns '?' if an option has no arg, but one is reqd */
544
 
                c &= 0xff; /* fight libc's sign extension */
545
 
                for (on_off = complementary; on_off->opt_char != c; on_off++) {
546
 
                        /* c can be NUL if long opt has non-NULL ->flag,
547
 
                         * but we construct long opts so that flag
548
 
                         * is always NULL (see above) */
549
 
                        if (on_off->opt_char == '\0' /* && c != '\0' */) {
550
 
                                /* c is probably '?' - "bad option" */
551
 
                                goto error;
552
 
                        }
553
 
                }
554
 
                if (flags & on_off->incongruously)
555
 
                        goto error;
556
 
                trigger = on_off->switch_on & on_off->switch_off;
557
 
                flags &= ~(on_off->switch_off ^ trigger);
558
 
                flags |= on_off->switch_on ^ trigger;
559
 
                flags ^= trigger;
560
 
                if (on_off->counter)
561
 
                        (*(on_off->counter))++;
562
 
                if (optarg) {
563
 
                        if (on_off->param_type == PARAM_LIST) {
564
 
                                llist_add_to_end((llist_t **)(on_off->optarg), optarg);
565
 
                        } else if (on_off->param_type == PARAM_INT) {
566
 
//TODO: xatoi_positive indirectly pulls in printf machinery
567
 
                                *(unsigned*)(on_off->optarg) = xatoi_positive(optarg);
568
 
                        } else if (on_off->optarg) {
569
 
                                *(char **)(on_off->optarg) = optarg;
570
 
                        }
571
 
                }
572
 
        }
573
 
 
574
 
        /* check depending requires for given options */
575
 
        for (on_off = complementary; on_off->opt_char; on_off++) {
576
 
                if (on_off->requires
577
 
                 && (flags & on_off->switch_on)
578
 
                 && (flags & on_off->requires) == 0
579
 
                ) {
580
 
                        goto error;
581
 
                }
582
 
        }
583
 
        if (requires && (flags & requires) == 0)
584
 
                goto error;
585
 
        argc -= optind;
586
 
        if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
587
 
                goto error;
588
 
 
589
 
        option_mask32 = flags;
590
 
        return flags;
591
 
 
592
 
 error:
593
 
        if (dont_die_flag != '!')
594
 
                bb_show_usage();
595
 
        return (int32_t)-1;
596
 
}
597
 
 
598
 
uint32_t FAST_FUNC
599
 
getopt32(char **argv, const char *applet_opts, ...)
600
 
{
601
 
        uint32_t opt;
602
 
        va_list p;
603
 
 
604
 
        va_start(p, applet_opts);
605
 
        opt = vgetopt32(argv, applet_opts, NULL, p);
606
 
        va_end(p);
607
 
        return opt;
608
 
}
609
 
 
610
 
#if ENABLE_LONG_OPTS
611
 
uint32_t FAST_FUNC
612
 
getopt32long(char **argv, const char *applet_opts, const char *longopts, ...)
613
 
{
614
 
        uint32_t opt;
615
 
        va_list p;
616
 
 
617
 
        va_start(p, longopts);
618
 
        opt = vgetopt32(argv, applet_opts, longopts, p);
619
 
        va_end(p);
620
 
        return opt;
621
 
}
622
 
#endif