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
This commit is contained in:
Denis Vlasenko 2009-04-26 23:22:40 +00:00
parent 572930027d
commit 28e67966f3
3 changed files with 42 additions and 36 deletions

View File

@ -72,6 +72,9 @@ getopt32(char **argv, const char *applet_opts, ...)
env -i ls -d / env -i ls -d /
Here we want env to process just the '-i', not the '-d'. Here we want env to process just the '-i', not the '-d'.
"!" Report bad option, missing required options,
inconsistent options with all-ones return value (instead of abort).
const char *applet_long_options const char *applet_long_options
This struct allows you to define long options: This struct allows you to define long options:
@ -327,6 +330,7 @@ getopt32(char **argv, const char *applet_opts, ...)
unsigned flags = 0; unsigned flags = 0;
unsigned requires = 0; unsigned requires = 0;
t_complementary complementary[33]; /* last stays zero-filled */ t_complementary complementary[33]; /* last stays zero-filled */
char first_char;
int c; int c;
const unsigned char *s; const unsigned char *s;
t_complementary *on_off; t_complementary *on_off;
@ -357,6 +361,11 @@ getopt32(char **argv, const char *applet_opts, ...)
on_off = complementary; on_off = complementary;
memset(on_off, 0, sizeof(complementary)); memset(on_off, 0, sizeof(complementary));
/* skip bbox extension */
first_char = applet_opts[0];
if (first_char == '!')
applet_opts++;
/* skip GNU extension */ /* skip GNU extension */
s = (const unsigned char *)applet_opts; s = (const unsigned char *)applet_opts;
if (*s == '+' || *s == '-') if (*s == '+' || *s == '-')
@ -549,11 +558,11 @@ getopt32(char **argv, const char *applet_opts, ...)
* is always NULL (see above) */ * is always NULL (see above) */
if (on_off->opt_char == '\0' /* && c != '\0' */) { if (on_off->opt_char == '\0' /* && c != '\0' */) {
/* c is probably '?' - "bad option" */ /* c is probably '?' - "bad option" */
bb_show_usage(); goto error;
} }
} }
if (flags & on_off->incongruously) if (flags & on_off->incongruously)
bb_show_usage(); goto error;
trigger = on_off->switch_on & on_off->switch_off; trigger = on_off->switch_on & on_off->switch_off;
flags &= ~(on_off->switch_off ^ trigger); flags &= ~(on_off->switch_off ^ trigger);
flags |= on_off->switch_on ^ trigger; flags |= on_off->switch_on ^ trigger;
@ -577,16 +586,24 @@ getopt32(char **argv, const char *applet_opts, ...)
/* check depending requires for given options */ /* check depending requires for given options */
for (on_off = complementary; on_off->opt_char; on_off++) { for (on_off = complementary; on_off->opt_char; on_off++) {
if (on_off->requires && (flags & on_off->switch_on) && if (on_off->requires
(flags & on_off->requires) == 0) && (flags & on_off->switch_on)
bb_show_usage(); && (flags & on_off->requires) == 0
) {
goto error;
}
} }
if (requires && (flags & requires) == 0) if (requires && (flags & requires) == 0)
bb_show_usage(); goto error;
argc -= optind; argc -= optind;
if (argc < min_arg || (max_arg >= 0 && argc > max_arg)) if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
bb_show_usage(); goto error;
option_mask32 = flags; option_mask32 = flags;
return flags; return flags;
error:
if (first_char != '!')
bb_show_usage();
return (int32_t)-1;
} }

View File

@ -6451,7 +6451,11 @@ static int builtin_export(char **argv)
} }
#if ENABLE_HUSH_EXPORT_N #if ENABLE_HUSH_EXPORT_N
opt_unexport = getopt32(argv, "+n"); /* "+": stop at 1st non-option */ /* "!": do not abort on errors */
/* "+": stop at 1st non-option */
opt_unexport = getopt32(argv, "!+n");
if (opt_unexport == (unsigned)-1)
return EXIT_FAILURE;
argv += optind; argv += optind;
#else #else
opt_unexport = 0; opt_unexport = 0;
@ -6918,36 +6922,22 @@ static int builtin_umask(char **argv)
static int builtin_unset(char **argv) static int builtin_unset(char **argv)
{ {
int ret; int ret;
char var; unsigned opts;
char *arg;
if (!*++argv) /* "!": do not abort on errors */
return EXIT_SUCCESS; /* "+": stop at 1st non-option */
opts = getopt32(argv, "!+vf");
var = 0; if (opts == (unsigned)-1)
while ((arg = *argv) != NULL && arg[0] == '-') { return EXIT_FAILURE;
arg++; if (opts == 3) {
do { bb_error_msg("unset: -v and -f are exclusive");
switch (*arg) { return EXIT_FAILURE;
case 'v':
case 'f':
if (var == 0 || var == *arg) {
var = *arg;
break;
}
/* else: unset -vf, which is illegal.
* fall through */
default:
bb_error_msg("unset: %s: invalid option", *argv);
return EXIT_FAILURE;
}
} while (*++arg);
argv++;
} }
argv += optind;
ret = EXIT_SUCCESS; ret = EXIT_SUCCESS;
while (*argv) { while (*argv) {
if (var != 'f') { if (!(opts & 2)) { /* not -f */
if (unset_local_var(*argv)) { if (unset_local_var(*argv)) {
/* unset <nonexistent_var> doesn't fail. /* unset <nonexistent_var> doesn't fail.
* Error is when one tries to unset RO var. * Error is when one tries to unset RO var.

View File

@ -1,6 +1,5 @@
hush: unset: -: invalid option 0
1 unset: invalid option -- m
hush: unset: -m: invalid option
1 1
0 0
___ ___