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