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