diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-26 23:22:40 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-26 23:22:40 +0000 |
commit | 28e67966f3fc0728fb2f923265a8b2275f410655 (patch) | |
tree | 0c522b97ed681180f68d028094bd02b89b292b49 | |
parent | 572930027d5d86a18ebd68d5f4273150a2f302e1 (diff) | |
download | busybox-w32-28e67966f3fc0728fb2f923265a8b2275f410655.tar.gz busybox-w32-28e67966f3fc0728fb2f923265a8b2275f410655.tar.bz2 busybox-w32-28e67966f3fc0728fb2f923265a8b2275f410655.zip |
hush: make getopt32 usable in builtins. use it in unset.
more uses are expected in the future.
function old new delta
getopt32 1356 1393 +37
builtin_export 256 266 +10
builtin_unset 418 380 -38
-rw-r--r-- | libbb/getopt32.c | 31 | ||||
-rw-r--r-- | shell/hush.c | 42 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/unset.right | 5 |
3 files changed, 42 insertions, 36 deletions
diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 5190fa61a..1eb868c97 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c | |||
@@ -72,6 +72,9 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
72 | env -i ls -d / | 72 | env -i ls -d / |
73 | Here we want env to process just the '-i', not the '-d'. | 73 | Here we want env to process just the '-i', not the '-d'. |
74 | 74 | ||
75 | "!" Report bad option, missing required options, | ||
76 | inconsistent options with all-ones return value (instead of abort). | ||
77 | |||
75 | const char *applet_long_options | 78 | const char *applet_long_options |
76 | 79 | ||
77 | This struct allows you to define long options: | 80 | This struct allows you to define long options: |
@@ -327,6 +330,7 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
327 | unsigned flags = 0; | 330 | unsigned flags = 0; |
328 | unsigned requires = 0; | 331 | unsigned requires = 0; |
329 | t_complementary complementary[33]; /* last stays zero-filled */ | 332 | t_complementary complementary[33]; /* last stays zero-filled */ |
333 | char first_char; | ||
330 | int c; | 334 | int c; |
331 | const unsigned char *s; | 335 | const unsigned char *s; |
332 | t_complementary *on_off; | 336 | t_complementary *on_off; |
@@ -357,6 +361,11 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
357 | on_off = complementary; | 361 | on_off = complementary; |
358 | memset(on_off, 0, sizeof(complementary)); | 362 | memset(on_off, 0, sizeof(complementary)); |
359 | 363 | ||
364 | /* skip bbox extension */ | ||
365 | first_char = applet_opts[0]; | ||
366 | if (first_char == '!') | ||
367 | applet_opts++; | ||
368 | |||
360 | /* skip GNU extension */ | 369 | /* skip GNU extension */ |
361 | s = (const unsigned char *)applet_opts; | 370 | s = (const unsigned char *)applet_opts; |
362 | if (*s == '+' || *s == '-') | 371 | if (*s == '+' || *s == '-') |
@@ -549,11 +558,11 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
549 | * is always NULL (see above) */ | 558 | * is always NULL (see above) */ |
550 | if (on_off->opt_char == '\0' /* && c != '\0' */) { | 559 | if (on_off->opt_char == '\0' /* && c != '\0' */) { |
551 | /* c is probably '?' - "bad option" */ | 560 | /* c is probably '?' - "bad option" */ |
552 | bb_show_usage(); | 561 | goto error; |
553 | } | 562 | } |
554 | } | 563 | } |
555 | if (flags & on_off->incongruously) | 564 | if (flags & on_off->incongruously) |
556 | bb_show_usage(); | 565 | goto error; |
557 | trigger = on_off->switch_on & on_off->switch_off; | 566 | trigger = on_off->switch_on & on_off->switch_off; |
558 | flags &= ~(on_off->switch_off ^ trigger); | 567 | flags &= ~(on_off->switch_off ^ trigger); |
559 | flags |= on_off->switch_on ^ trigger; | 568 | flags |= on_off->switch_on ^ trigger; |
@@ -577,16 +586,24 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
577 | 586 | ||
578 | /* check depending requires for given options */ | 587 | /* check depending requires for given options */ |
579 | for (on_off = complementary; on_off->opt_char; on_off++) { | 588 | for (on_off = complementary; on_off->opt_char; on_off++) { |
580 | if (on_off->requires && (flags & on_off->switch_on) && | 589 | if (on_off->requires |
581 | (flags & on_off->requires) == 0) | 590 | && (flags & on_off->switch_on) |
582 | bb_show_usage(); | 591 | && (flags & on_off->requires) == 0 |
592 | ) { | ||
593 | goto error; | ||
594 | } | ||
583 | } | 595 | } |
584 | if (requires && (flags & requires) == 0) | 596 | if (requires && (flags & requires) == 0) |
585 | bb_show_usage(); | 597 | goto error; |
586 | argc -= optind; | 598 | argc -= optind; |
587 | if (argc < min_arg || (max_arg >= 0 && argc > max_arg)) | 599 | if (argc < min_arg || (max_arg >= 0 && argc > max_arg)) |
588 | bb_show_usage(); | 600 | goto error; |
589 | 601 | ||
590 | option_mask32 = flags; | 602 | option_mask32 = flags; |
591 | return flags; | 603 | return flags; |
604 | |||
605 | error: | ||
606 | if (first_char != '!') | ||
607 | bb_show_usage(); | ||
608 | return (int32_t)-1; | ||
592 | } | 609 | } |
diff --git a/shell/hush.c b/shell/hush.c index 292b8b2e3..d0819f691 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -6451,7 +6451,11 @@ static int builtin_export(char **argv) | |||
6451 | } | 6451 | } |
6452 | 6452 | ||
6453 | #if ENABLE_HUSH_EXPORT_N | 6453 | #if ENABLE_HUSH_EXPORT_N |
6454 | opt_unexport = getopt32(argv, "+n"); /* "+": stop at 1st non-option */ | 6454 | /* "!": do not abort on errors */ |
6455 | /* "+": stop at 1st non-option */ | ||
6456 | opt_unexport = getopt32(argv, "!+n"); | ||
6457 | if (opt_unexport == (unsigned)-1) | ||
6458 | return EXIT_FAILURE; | ||
6455 | argv += optind; | 6459 | argv += optind; |
6456 | #else | 6460 | #else |
6457 | opt_unexport = 0; | 6461 | opt_unexport = 0; |
@@ -6918,36 +6922,22 @@ static int builtin_umask(char **argv) | |||
6918 | static int builtin_unset(char **argv) | 6922 | static int builtin_unset(char **argv) |
6919 | { | 6923 | { |
6920 | int ret; | 6924 | int ret; |
6921 | char var; | 6925 | unsigned opts; |
6922 | char *arg; | ||
6923 | |||
6924 | if (!*++argv) | ||
6925 | return EXIT_SUCCESS; | ||
6926 | 6926 | ||
6927 | var = 0; | 6927 | /* "!": do not abort on errors */ |
6928 | while ((arg = *argv) != NULL && arg[0] == '-') { | 6928 | /* "+": stop at 1st non-option */ |
6929 | arg++; | 6929 | opts = getopt32(argv, "!+vf"); |
6930 | do { | 6930 | if (opts == (unsigned)-1) |
6931 | switch (*arg) { | 6931 | return EXIT_FAILURE; |
6932 | case 'v': | 6932 | if (opts == 3) { |
6933 | case 'f': | 6933 | bb_error_msg("unset: -v and -f are exclusive"); |
6934 | if (var == 0 || var == *arg) { | 6934 | return EXIT_FAILURE; |
6935 | var = *arg; | ||
6936 | break; | ||
6937 | } | ||
6938 | /* else: unset -vf, which is illegal. | ||
6939 | * fall through */ | ||
6940 | default: | ||
6941 | bb_error_msg("unset: %s: invalid option", *argv); | ||
6942 | return EXIT_FAILURE; | ||
6943 | } | ||
6944 | } while (*++arg); | ||
6945 | argv++; | ||
6946 | } | 6935 | } |
6936 | argv += optind; | ||
6947 | 6937 | ||
6948 | ret = EXIT_SUCCESS; | 6938 | ret = EXIT_SUCCESS; |
6949 | while (*argv) { | 6939 | while (*argv) { |
6950 | if (var != 'f') { | 6940 | if (!(opts & 2)) { /* not -f */ |
6951 | if (unset_local_var(*argv)) { | 6941 | if (unset_local_var(*argv)) { |
6952 | /* unset <nonexistent_var> doesn't fail. | 6942 | /* unset <nonexistent_var> doesn't fail. |
6953 | * Error is when one tries to unset RO var. | 6943 | * Error is when one tries to unset RO var. |
diff --git a/shell/hush_test/hush-vars/unset.right b/shell/hush_test/hush-vars/unset.right index 8dea7c40d..1fbe76a73 100644 --- a/shell/hush_test/hush-vars/unset.right +++ b/shell/hush_test/hush-vars/unset.right | |||
@@ -1,6 +1,5 @@ | |||
1 | hush: unset: -: invalid option | 1 | 0 |
2 | 1 | 2 | unset: invalid option -- m |
3 | hush: unset: -m: invalid option | ||
4 | 1 | 3 | 1 |
5 | 0 | 4 | 0 |
6 | ___ | 5 | ___ |