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:
Special characters:
- "-" A dash as the first char in a opt_complementary group forces
- all arguments to be treated as options, even if they have
- no leading dashes. Next char in this case can't be a digit (0-9),
- use ':' or end of line. For example:
+ "-" A group consisting of just a dash forces all arguments
+ to be treated as options, even if they have no leading dashes.
+ Next char in this case can't be a digit (0-9), use ':' or end of line.
+ Example:
- opt_complementary = "-:w-x:x-w";
- getopt32(argv, "wx");
+ opt_complementary = "-:w-x:x-w"; // "-w-x:x-w" would also work,
+ getopt32(argv, "wx"); // but is less readable
- Allows any arguments to be given without a dash (./program w x)
+ This makes it possible to use options without a dash (./program w x)
as well as with a dash (./program -x).
- NB: getopt32() will leak a small amount of memory if you use
- this option! Do not use it if there is a possibility of recursive
- getopt32() calls.
+ NB: getopt32() will leak a small amount of memory if you use
+ this option! Do not use it if there is a possibility of recursive
+ getopt32() calls.
"--" A double dash at the beginning of opt_complementary means the
argv[1] string should always be treated as options, even if it isn't
such as "ar" and "tar":
tar xvf foo.tar
- NB: getopt32() will leak a small amount of memory if you use
- this option! Do not use it if there is a possibility of recursive
- getopt32() calls.
+ NB: getopt32() will leak a small amount of memory if you use
+ this option! Do not use it if there is a possibility of recursive
+ getopt32() calls.
"-N" A dash as the first char in a opt_complementary group followed
by a single digit (0-9) means that at least N non-option
} t_complementary;
/* You can set applet_long_options for parse called long options */
-#if ENABLE_GETOPT_LONG
+#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
static const struct option bb_null_long_options[1] = {
{ 0, 0, 0, 0 }
};
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;
va_list p;
-#if ENABLE_GETOPT_LONG
+#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
const struct option *l_o;
struct option *long_options = (struct option *) &bb_null_long_options;
#endif
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 == '-')
c++;
}
-#if ENABLE_GETOPT_LONG
+#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
if (applet_long_options) {
const char *optstr;
unsigned i, count;
next_long: ;
}
}
-#endif /* ENABLE_GETOPT_LONG */
+#endif /* ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG */
for (s = (const unsigned char *)opt_complementary; s && *s; s++) {
t_complementary *pair;
unsigned *pair_switch;
*pargv = pp;
}
if (!(spec_flgs & ALL_ARGV_IS_OPTS))
- break;
+ break;
pargv++;
}
}
/* In case getopt32 was already called:
* reset the libc getopt() function, which keeps internal state.
- *
- * BSD-derived getopt() functions require that optind be set to 1 in
- * order to reset getopt() state. This used to be generally accepted
- * way of resetting getopt(). However, glibc's getopt()
- * has additional getopt() state beyond optind, and requires that
- * optind be set to zero to reset its state. So the unfortunate state of
- * affairs is that BSD-derived versions of getopt() misbehave if
- * optind is set to 0 in order to reset getopt(), and glibc's getopt()
- * will core dump if optind is set 1 in order to reset getopt().
- *
- * More modern versions of BSD require that optreset be set to 1 in
- * order to reset getopt(). Sigh. Standards, anyone?
+ * run_nofork_applet_prime() does this, but we might end up here
+ * also via gunzip_main() -> gzip_main(). Play safe.
*/
#ifdef __GLIBC__
optind = 0;
/* optreset = 1; */
#endif
/* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */
+
pargv = NULL;
/* Note: just "getopt() <= 0" will not work well for
* "fake" short options, like this one:
* wget $'-\203' "Test: test" http://kernel.org/
* (supposed to act as --header, but doesn't) */
-#if ENABLE_GETOPT_LONG
+#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
while ((c = getopt_long(argc, argv, applet_opts,
long_options, NULL)) != -1) {
#else
* 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;
}