env -i ls -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
This struct allows you to define long options:
unsigned flags = 0;
unsigned requires = 0;
t_complementary complementary[33]; /* last stays zero-filled */
+ char first_char;
int c;
const unsigned char *s;
t_complementary *on_off;
on_off = complementary;
memset(on_off, 0, sizeof(complementary));
+ /* skip bbox extension */
+ first_char = applet_opts[0];
+ if (first_char == '!')
+ applet_opts++;
+
/* skip GNU extension */
s = (const unsigned char *)applet_opts;
if (*s == '+' || *s == '-')
* is always NULL (see above) */
if (on_off->opt_char == '\0' /* && c != '\0' */) {
/* c is probably '?' - "bad option" */
- bb_show_usage();
+ goto error;
}
}
if (flags & on_off->incongruously)
- bb_show_usage();
+ goto error;
trigger = on_off->switch_on & on_off->switch_off;
flags &= ~(on_off->switch_off ^ trigger);
flags |= on_off->switch_on ^ trigger;
/* check depending requires for given options */
for (on_off = complementary; on_off->opt_char; on_off++) {
- if (on_off->requires && (flags & on_off->switch_on) &&
- (flags & on_off->requires) == 0)
- bb_show_usage();
+ if (on_off->requires
+ && (flags & on_off->switch_on)
+ && (flags & on_off->requires) == 0
+ ) {
+ goto error;
+ }
}
if (requires && (flags & requires) == 0)
- bb_show_usage();
+ goto error;
argc -= optind;
if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
- bb_show_usage();
+ goto error;
option_mask32 = flags;
return flags;
+
+ error:
+ if (first_char != '!')
+ bb_show_usage();
+ return (int32_t)-1;
}
}
#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;
#else
opt_unexport = 0;
static int builtin_unset(char **argv)
{
int ret;
- char var;
- char *arg;
-
- if (!*++argv)
- return EXIT_SUCCESS;
+ unsigned opts;
- var = 0;
- while ((arg = *argv) != NULL && arg[0] == '-') {
- arg++;
- do {
- switch (*arg) {
- 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++;
+ /* "!": do not abort on errors */
+ /* "+": stop at 1st non-option */
+ opts = getopt32(argv, "!+vf");
+ if (opts == (unsigned)-1)
+ return EXIT_FAILURE;
+ if (opts == 3) {
+ bb_error_msg("unset: -v and -f are exclusive");
+ return EXIT_FAILURE;
}
+ argv += optind;
ret = EXIT_SUCCESS;
while (*argv) {
- if (var != 'f') {
+ if (!(opts & 2)) { /* not -f */
if (unset_local_var(*argv)) {
/* unset <nonexistent_var> doesn't fail.
* Error is when one tries to unset RO var.