aboutsummaryrefslogtreecommitdiff
path: root/libbb/getopt32.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbb/getopt32.c')
-rw-r--r--libbb/getopt32.c198
1 files changed, 87 insertions, 111 deletions
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index 80f4cc060..f778c6e89 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -6,12 +6,13 @@
6 * 6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9 9#if ENABLE_LONG_OPTS
10#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
11# include <getopt.h> 10# include <getopt.h>
12#endif 11#endif
13#include "libbb.h" 12#include "libbb.h"
14 13
14//kbuild:lib-y += getopt32.o
15
15/* Documentation 16/* Documentation
16 17
17uint32_t 18uint32_t
@@ -95,20 +96,23 @@ getopt32(char **argv, const char *applet_opts, ...)
95 env -i ls -d / 96 env -i ls -d /
96 Here we want env to process just the '-i', not the '-d'. 97 Here we want env to process just the '-i', not the '-d'.
97 98
98 "!" Report bad option, missing required options, 99 "!" Report bad options, missing required options,
99 inconsistent options with all-ones return value (instead of abort). 100 inconsistent options with all-ones return value (instead of abort).
100 101
101const char *applet_long_options 102 "^" options string is "^optchars""\0""opt_complementary".
103
104uint32_t
105getopt32long(char **argv, const char *applet_opts, const char *logopts...)
102 106
103 This struct allows you to define long options: 107 This allows you to define long options:
104 108
105 static const char applet_longopts[] ALIGN1 = 109 static const char applet_longopts[] ALIGN1 =
106 //"name\0" has_arg val 110 //"name\0" has_arg val
107 "verbose\0" No_argument "v" 111 "verbose\0" No_argument "v"
108 ; 112 ;
109 applet_long_options = applet_longopts; 113 opt = getopt32long(argv, applet_opts, applet_longopts, ...);
110 114
111 The last member of struct option (val) typically is set to 115 The last element (val) typically is set to
112 matching short option from applet_opts. If there is no matching 116 matching short option from applet_opts. If there is no matching
113 char in applet_opts, then: 117 char in applet_opts, then:
114 - return bit has next position after short options 118 - return bit has next position after short options
@@ -119,7 +123,7 @@ const char *applet_long_options
119 config process and not a required feature. The current standard 123 config process and not a required feature. The current standard
120 is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS. 124 is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS.
121 125
122const char *opt_complementary 126opt_complementary - option modifiers.
123 127
124 ":" The colon (":") is used to separate groups of two or more chars 128 ":" The colon (":") is used to separate groups of two or more chars
125 and/or groups of chars and special characters (stating some 129 and/or groups of chars and special characters (stating some
@@ -130,8 +134,7 @@ const char *opt_complementary
130 Their flags will be turned on if the main option is found even 134 Their flags will be turned on if the main option is found even
131 if they are not specified on the command line. For example: 135 if they are not specified on the command line. For example:
132 136
133 opt_complementary = "abc"; 137 flags = getopt32(argv, "^abcd""\0""abc")
134 flags = getopt32(argv, "abcd")
135 138
136 If getopt() finds "-a" on the command line, then 139 If getopt() finds "-a" on the command line, then
137 getopt32's return value will be as if "-a -b -c" were 140 getopt32's return value will be as if "-a -b -c" were
@@ -144,8 +147,7 @@ const char *opt_complementary
144 if w is given more than once, it is "unlimited" 147 if w is given more than once, it is "unlimited"
145 148
146 int w_counter = 0; // must be initialized! 149 int w_counter = 0; // must be initialized!
147 opt_complementary = "ww"; 150 getopt32(argv, "^w""\0""ww", &w_counter);
148 getopt32(argv, "w", &w_counter);
149 if (w_counter) 151 if (w_counter)
150 width = (w_counter == 1) ? 132 : INT_MAX; 152 width = (w_counter == 1) ? 132 : INT_MAX;
151 else 153 else
@@ -160,8 +162,9 @@ const char *opt_complementary
160 162
161 llist_t *my_b = NULL; 163 llist_t *my_b = NULL;
162 int verbose_level = 0; 164 int verbose_level = 0;
163 opt_complementary = "vv:b-c:c-b"; 165 f = getopt32(argv, "^vb:*c"
164 f = getopt32(argv, "vb:*c", &my_b, &verbose_level); 166 "\0""vv:b-c:c-b"
167 , &my_b, &verbose_level);
165 if (f & 2) // -c after -b unsets -b flag 168 if (f & 2) // -c after -b unsets -b flag
166 while (my_b) dosomething_with(llist_pop(&my_b)); 169 while (my_b) dosomething_with(llist_pop(&my_b));
167 if (my_b) // but llist is stored if -b is specified 170 if (my_b) // but llist is stored if -b is specified
@@ -170,31 +173,6 @@ const char *opt_complementary
170 173
171Special characters: 174Special characters:
172 175
173 "-" A group consisting of just a dash forces all arguments
174 to be treated as options, even if they have no leading dashes.
175 Next char in this case can't be a digit (0-9), use ':' or end of line.
176 Example:
177
178 opt_complementary = "-:w-x:x-w"; // "-w-x:x-w" would also work,
179 getopt32(argv, "wx"); // but is less readable
180
181 This makes it possible to use options without a dash (./program w x)
182 as well as with a dash (./program -x).
183
184 NB: getopt32() will leak a small amount of memory if you use
185 this option! Do not use it if there is a possibility of recursive
186 getopt32() calls.
187
188 "--" A double dash at the beginning of opt_complementary means the
189 argv[1] string should always be treated as options, even if it isn't
190 prefixed with a "-". This is useful for special syntax in applets
191 such as "ar" and "tar":
192 tar xvf foo.tar
193
194 NB: getopt32() will leak a small amount of memory if you use
195 this option! Do not use it if there is a possibility of recursive
196 getopt32() calls.
197
198 "-N" A dash as the first char in a opt_complementary group followed 176 "-N" A dash as the first char in a opt_complementary group followed
199 by a single digit (0-9) means that at least N non-option 177 by a single digit (0-9) means that at least N non-option
200 arguments must be present on the command line 178 arguments must be present on the command line
@@ -222,7 +200,7 @@ Special characters:
222 getopt32 finds -s, then -d is unset or if it finds -d 200 getopt32 finds -s, then -d is unset or if it finds -d
223 then -s is unset. (Note: busybox implements the GNU 201 then -s is unset. (Note: busybox implements the GNU
224 "--max-depth" option as "-d".) To obtain this behavior, you 202 "--max-depth" option as "-d".) To obtain this behavior, you
225 set opt_complementary = "s-d:d-s". Only one flag value is 203 set opt_complementary to "s-d:d-s". Only one flag value is
226 added to getopt32's return value depending on the 204 added to getopt32's return value depending on the
227 position of the options on the command line. If one of the 205 position of the options on the command line. If one of the
228 two options requires an argument pointer (":" in applet_opts 206 two options requires an argument pointer (":" in applet_opts
@@ -230,8 +208,7 @@ Special characters:
230 208
231 char *smax_print_depth; 209 char *smax_print_depth;
232 210
233 opt_complementary = "s-d:d-s:x-x"; 211 opt = getopt32(argv, "^sd:x""\0""s-d:d-s:x-x", &smax_print_depth);
234 opt = getopt32(argv, "sd:x", &smax_print_depth);
235 212
236 if (opt & 2) 213 if (opt & 2)
237 max_print_depth = atoi(smax_print_depth); 214 max_print_depth = atoi(smax_print_depth);
@@ -247,7 +224,7 @@ Special characters:
247 The cut applet must have only one type of list specified, so 224 The cut applet must have only one type of list specified, so
248 -b, -c and -f are mutually exclusive and should raise an error 225 -b, -c and -f are mutually exclusive and should raise an error
249 if specified together. In this case you must set 226 if specified together. In this case you must set
250 opt_complementary = "b--cf:c--bf:f--bc". If two of the 227 opt_complementary to "b--cf:c--bf:f--bc". If two of the
251 mutually exclusive options are found, getopt32 will call 228 mutually exclusive options are found, getopt32 will call
252 bb_show_usage() and die. 229 bb_show_usage() and die.
253 230
@@ -259,8 +236,7 @@ Special characters:
259 with xatoi_positive() - allowed range is 0..INT_MAX. 236 with xatoi_positive() - allowed range is 0..INT_MAX.
260 237
261 int param; // "unsigned param;" will also work 238 int param; // "unsigned param;" will also work
262 opt_complementary = "p+"; 239 getopt32(argv, "^p:""\0""p+", &param);
263 getopt32(argv, "p:", &param);
264 240
265 "o::" A double colon after a char in opt_complementary means that the 241 "o::" A double colon after a char in opt_complementary means that the
266 option can occur multiple times. Each occurrence will be saved as 242 option can occur multiple times. Each occurrence will be saved as
@@ -275,8 +251,7 @@ Special characters:
275 (this pointer must be initializated to NULL if the list is empty 251 (this pointer must be initializated to NULL if the list is empty
276 as required by llist_add_to_end(llist_t **old_head, char *new_item).) 252 as required by llist_add_to_end(llist_t **old_head, char *new_item).)
277 253
278 opt_complementary = "e::"; 254 getopt32(argv, "^e:""\0""e::", &patterns);
279 getopt32(argv, "e:", &patterns);
280 255
281 $ grep -e user -e root /etc/passwd 256 $ grep -e user -e root /etc/passwd
282 root:x:0:0:root:/root:/bin/bash 257 root:x:0:0:root:/root:/bin/bash
@@ -294,8 +269,7 @@ Special characters:
294 For example from "id" applet: 269 For example from "id" applet:
295 270
296 // Don't allow -n -r -rn -ug -rug -nug -rnug 271 // Don't allow -n -r -rn -ug -rug -nug -rnug
297 opt_complementary = "r?ug:n?ug:u--g:g--u"; 272 flags = getopt32(argv, "^rnug""\0""r?ug:n?ug:u--g:g--u");
298 flags = getopt32(argv, "rnug");
299 273
300 This example allowed only: 274 This example allowed only:
301 $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng 275 $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng
@@ -306,8 +280,7 @@ Special characters:
306 For example from "start-stop-daemon" applet: 280 For example from "start-stop-daemon" applet:
307 281
308 // Don't allow -KS -SK, but -S or -K is required 282 // Don't allow -KS -SK, but -S or -K is required
309 opt_complementary = "K:S:K--S:S--K"; 283 flags = getopt32(argv, "^KS...""\0""K:S:K--S:S--K");
310 flags = getopt32(argv, "KS...);
311 284
312 285
313 Don't forget to use ':'. For example, "?322-22-23X-x-a" 286 Don't forget to use ':'. For example, "?322-22-23X-x-a"
@@ -322,8 +295,6 @@ Special characters:
322 295
323const char *const bb_argv_dash[] = { "-", NULL }; 296const char *const bb_argv_dash[] = { "-", NULL };
324 297
325const char *opt_complementary;
326
327enum { 298enum {
328 PARAM_STRING, 299 PARAM_STRING,
329 PARAM_LIST, 300 PARAM_LIST,
@@ -341,58 +312,63 @@ typedef struct {
341 int *counter; 312 int *counter;
342} t_complementary; 313} t_complementary;
343 314
344/* You can set applet_long_options for parse called long options */ 315uint32_t option_mask32;
345#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 316
317#if ENABLE_LONG_OPTS
346static const struct option bb_null_long_options[1] = { 318static const struct option bb_null_long_options[1] = {
347 { 0, 0, 0, 0 } 319 { 0, 0, 0, 0 }
348}; 320};
349const char *applet_long_options; 321#else
322#define vgetopt32(argv,applet_opts,applet_long_options,p) \
323 vgetopt32(argv,applet_opts,p)
350#endif 324#endif
351 325
352uint32_t option_mask32; 326/* Please keep getopt32 free from xmalloc */
353 327
354uint32_t FAST_FUNC 328static uint32_t
355getopt32(char **argv, const char *applet_opts, ...) 329vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, va_list p)
356{ 330{
357 int argc; 331 int argc;
358 unsigned flags = 0; 332 unsigned flags = 0;
359 unsigned requires = 0; 333 unsigned requires = 0;
334 unsigned len;
360 t_complementary complementary[33]; /* last stays zero-filled */ 335 t_complementary complementary[33]; /* last stays zero-filled */
361 char first_char; 336 char dont_die_flag;
362 int c; 337 int c;
363 const unsigned char *s; 338 const unsigned char *s;
339 const char *opt_complementary;
364 t_complementary *on_off; 340 t_complementary *on_off;
365 va_list p; 341#if ENABLE_LONG_OPTS
366#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
367 const struct option *l_o; 342 const struct option *l_o;
368 struct option *long_options = (struct option *) &bb_null_long_options; 343 struct option *long_options = (struct option *) &bb_null_long_options;
369#endif 344#endif
370 unsigned trigger; 345 unsigned trigger;
371 char **pargv;
372 int min_arg = 0; 346 int min_arg = 0;
373 int max_arg = -1; 347 int max_arg = -1;
374
375#define SHOW_USAGE_IF_ERROR 1
376#define ALL_ARGV_IS_OPTS 2
377#define FIRST_ARGV_IS_OPT 4
378
379 int spec_flgs = 0; 348 int spec_flgs = 0;
380 349
381 /* skip 0: some applets cheat: they do not actually HAVE argv[0] */ 350#define SHOW_USAGE_IF_ERROR 1
382 argc = 1 + string_array_len(argv + 1);
383
384 va_start(p, applet_opts);
385 351
386 on_off = complementary; 352 on_off = complementary;
387 memset(on_off, 0, sizeof(complementary)); 353 memset(on_off, 0, sizeof(complementary));
388 354
389 applet_opts = strcpy(alloca(strlen(applet_opts) + 1), applet_opts); 355 len = strlen(applet_opts);
390 356
391 /* skip bbox extension */ 357 /* skip bbox extension */
392 first_char = applet_opts[0]; 358 opt_complementary = NULL;
393 if (first_char == '!') 359 if (applet_opts[0] == '^') {
360 applet_opts++;
361 /* point it past terminating NUL */
362 opt_complementary = applet_opts + len;
363 }
364
365 /* skip another bbox extension */
366 dont_die_flag = applet_opts[0];
367 if (dont_die_flag == '!')
394 applet_opts++; 368 applet_opts++;
395 369
370 applet_opts = strcpy(alloca(len + 1), applet_opts);
371
396 /* skip GNU extension */ 372 /* skip GNU extension */
397 s = (const unsigned char *)applet_opts; 373 s = (const unsigned char *)applet_opts;
398 if (*s == '+' || *s == '-') 374 if (*s == '+' || *s == '-')
@@ -419,7 +395,7 @@ getopt32(char **argv, const char *applet_opts, ...)
419 c++; 395 c++;
420 } 396 }
421 397
422#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 398#if ENABLE_LONG_OPTS
423 if (applet_long_options) { 399 if (applet_long_options) {
424 const char *optstr; 400 const char *optstr;
425 unsigned i, count; 401 unsigned i, count;
@@ -458,14 +434,11 @@ getopt32(char **argv, const char *applet_opts, ...)
458 c++; 434 c++;
459 next_long: ; 435 next_long: ;
460 } 436 }
461 /* Make it unnecessary to clear applet_long_options
462 * by hand after each call to getopt32
463 */
464 applet_long_options = NULL;
465 } 437 }
466#endif /* ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG */ 438#endif /* ENABLE_LONG_OPTS */
467 439
468 for (s = (const unsigned char *)opt_complementary; s && *s; s++) { 440 s = (const unsigned char *)opt_complementary;
441 if (s) for (; *s; s++) {
469 t_complementary *pair; 442 t_complementary *pair;
470 unsigned *pair_switch; 443 unsigned *pair_switch;
471 444
@@ -482,13 +455,7 @@ getopt32(char **argv, const char *applet_opts, ...)
482 continue; 455 continue;
483 } 456 }
484 if (*s == '-') { 457 if (*s == '-') {
485 if (c < '0' || c > '9') { 458 if (c >= '0' && c <= '9') {
486 if (c == '-') {
487 spec_flgs |= FIRST_ARGV_IS_OPT;
488 s++;
489 } else
490 spec_flgs |= ALL_ARGV_IS_OPTS;
491 } else {
492 min_arg = c - '0'; 459 min_arg = c - '0';
493 s++; 460 s++;
494 } 461 }
@@ -548,26 +515,6 @@ getopt32(char **argv, const char *applet_opts, ...)
548 } 515 }
549 s--; 516 s--;
550 } 517 }
551 opt_complementary = NULL;
552 va_end(p);
553
554 if (spec_flgs & (FIRST_ARGV_IS_OPT | ALL_ARGV_IS_OPTS)) {
555 pargv = argv + 1;
556 while (*pargv) {
557 if (pargv[0][0] != '-' && pargv[0][0] != '\0') {
558 /* Can't use alloca: opts with params will
559 * return pointers to stack!
560 * NB: we leak these allocations... */
561 char *pp = xmalloc(strlen(*pargv) + 2);
562 *pp = '-';
563 strcpy(pp + 1, *pargv);
564 *pargv = pp;
565 }
566 if (!(spec_flgs & ALL_ARGV_IS_OPTS))
567 break;
568 pargv++;
569 }
570 }
571 518
572 /* In case getopt32 was already called: 519 /* In case getopt32 was already called:
573 * reset the libc getopt() function, which keeps internal state. 520 * reset the libc getopt() function, which keeps internal state.
@@ -576,11 +523,14 @@ getopt32(char **argv, const char *applet_opts, ...)
576 */ 523 */
577 GETOPT_RESET(); 524 GETOPT_RESET();
578 525
526 /* skip 0: some applets cheat: they do not actually HAVE argv[0] */
527 argc = 1 + string_array_len(argv + 1);
528
579 /* Note: just "getopt() <= 0" will not work well for 529 /* Note: just "getopt() <= 0" will not work well for
580 * "fake" short options, like this one: 530 * "fake" short options, like this one:
581 * wget $'-\203' "Test: test" http://kernel.org/ 531 * wget $'-\203' "Test: test" http://kernel.org/
582 * (supposed to act as --header, but doesn't) */ 532 * (supposed to act as --header, but doesn't) */
583#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 533#if ENABLE_LONG_OPTS
584 while ((c = getopt_long(argc, argv, applet_opts, 534 while ((c = getopt_long(argc, argv, applet_opts,
585 long_options, NULL)) != -1) { 535 long_options, NULL)) != -1) {
586#else 536#else
@@ -637,7 +587,33 @@ getopt32(char **argv, const char *applet_opts, ...)
637 return flags; 587 return flags;
638 588
639 error: 589 error:
640 if (first_char != '!') 590 if (dont_die_flag != '!')
641 bb_show_usage(); 591 bb_show_usage();
642 return (int32_t)-1; 592 return (int32_t)-1;
643} 593}
594
595uint32_t FAST_FUNC
596getopt32(char **argv, const char *applet_opts, ...)
597{
598 uint32_t opt;
599 va_list p;
600
601 va_start(p, applet_opts);
602 opt = vgetopt32(argv, applet_opts, NULL, p);
603 va_end(p);
604 return opt;
605}
606
607#if ENABLE_LONG_OPTS
608uint32_t FAST_FUNC
609getopt32long(char **argv, const char *applet_opts, const char *longopts, ...)
610{
611 uint32_t opt;
612 va_list p;
613
614 va_start(p, longopts);
615 opt = vgetopt32(argv, applet_opts, longopts, p);
616 va_end(p);
617 return opt;
618}
619#endif