X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=libbb%2Fgetopt32.c;h=d0e83d88ee4d31090527a7f2f632907e9ebe0312;hb=0b170e6a096b0d5010e29a39f3b270c3a7bc4945;hp=5190fa61a945f288312e4b37bc1267a2978dda88;hpb=fd5a3d28127f051887b6feb3462928aee045c9ef;p=oweals%2Fbusybox.git diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 5190fa61a..d0e83d88e 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -4,10 +4,12 @@ * * Copyright (C) 2003-2005 Vladimir Oleynik * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -#include +#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG +# include +#endif #include "libbb.h" /* Documentation @@ -72,14 +74,17 @@ getopt32(char **argv, const char *applet_opts, ...) 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: static const char applet_longopts[] ALIGN1 = - //"name\0" has_arg val - "verbose\0" No_argument "v" - ; + //"name\0" has_arg val + "verbose\0" No_argument "v" + ; applet_long_options = applet_longopts; The last member of struct option (val) typically is set to @@ -112,7 +117,7 @@ const char *opt_complementary found. "ww" Adjacent double options have a counter associated which indicates - the number of occurences of the option. + the number of occurrences of the option. For example the ps applet needs: if w is given once, GNU ps sets the width to 132, if w is given more than once, it is "unlimited" @@ -144,15 +149,15 @@ const char *opt_complementary 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 @@ -223,14 +228,14 @@ Special characters: if specified together. In this case you must set opt_complementary = "b--cf:c--bf:f--bc". If two of the mutually exclusive options are found, getopt32 will call - bb_show_usage() and die. + bb_show_usage() and die. "x--x" Variation of the above, it means that -x option should occur at most once. "a+" A plus after a char in opt_complementary means that the parameter for this option is a nonnegative integer. It will be processed - with xatoi_u() - allowed range is 0..INT_MAX. + with xatoi_positive() - allowed range is 0..INT_MAX. int param; // "unsigned param;" will also work opt_complementary = "p+"; @@ -311,7 +316,7 @@ typedef struct { } 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 } }; @@ -327,11 +332,12 @@ getopt32(char **argv, const char *applet_opts, ...) 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 @@ -357,6 +363,11 @@ getopt32(char **argv, const char *applet_opts, ...) 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 == '-') @@ -375,7 +386,7 @@ getopt32(char **argv, const char *applet_opts, ...) c++; } -#if ENABLE_GETOPT_LONG +#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG if (applet_long_options) { const char *optstr; unsigned i, count; @@ -414,8 +425,12 @@ getopt32(char **argv, const char *applet_opts, ...) c++; next_long: ; } + /* Make it unnecessary to clear applet_long_options + * by hand after each call to getopt32 + */ + applet_long_options = NULL; } -#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; @@ -452,13 +467,17 @@ getopt32(char **argv, const char *applet_opts, ...) } for (on_off = complementary; on_off->opt_char; on_off++) if (on_off->opt_char == *s) - break; + goto found_opt; + /* Without this, diagnostic of such bugs is not easy */ + bb_error_msg_and_die("NO OPT %c!", *s); + found_opt: if (c == ':' && s[2] == ':') { on_off->param_type = PARAM_LIST; continue; } if (c == '+' && (s[2] == ':' || s[2] == '\0')) { on_off->param_type = PARAM_INT; + s++; continue; } if (c == ':' || c == '\0') { @@ -476,15 +495,15 @@ getopt32(char **argv, const char *applet_opts, ...) s++; } pair = on_off; - pair_switch = &(pair->switch_on); + pair_switch = &pair->switch_on; for (s++; *s && *s != ':'; s++) { if (*s == '?') { - pair_switch = &(pair->requires); + pair_switch = &pair->requires; } else if (*s == '-') { - if (pair_switch == &(pair->switch_off)) - pair_switch = &(pair->incongruously); + if (pair_switch == &pair->switch_off) + pair_switch = &pair->incongruously; else - pair_switch = &(pair->switch_off); + pair_switch = &pair->switch_off; } else { for (on_off = complementary; on_off->opt_char; on_off++) if (on_off->opt_char == *s) { @@ -495,6 +514,7 @@ getopt32(char **argv, const char *applet_opts, ...) } s--; } + opt_complementary = NULL; va_end(p); if (spec_flgs & (FIRST_ARGV_IS_OPT | ALL_ARGV_IS_OPTS)) { @@ -517,7 +537,7 @@ getopt32(char **argv, const char *applet_opts, ...) /* In case getopt32 was already called: * reset the libc getopt() function, which keeps internal state. - * run_nofork_applet_prime() does this, but we might end up here + * run_nofork_applet() does this, but we might end up here * also via gunzip_main() -> gzip_main(). Play safe. */ #ifdef __GLIBC__ @@ -528,13 +548,11 @@ getopt32(char **argv, const char *applet_opts, ...) #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 @@ -549,44 +567,49 @@ getopt32(char **argv, const char *applet_opts, ...) * 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; flags ^= trigger; if (on_off->counter) (*(on_off->counter))++; - if (on_off->param_type == PARAM_LIST) { - if (optarg) + if (optarg) { + if (on_off->param_type == PARAM_LIST) { llist_add_to_end((llist_t **)(on_off->optarg), optarg); - } else if (on_off->param_type == PARAM_INT) { - if (optarg) -//TODO: xatoi_u indirectly pulls in printf machinery - *(unsigned*)(on_off->optarg) = xatoi_u(optarg); - } else if (on_off->optarg) { - if (optarg) + } else if (on_off->param_type == PARAM_INT) { +//TODO: xatoi_positive indirectly pulls in printf machinery + *(unsigned*)(on_off->optarg) = xatoi_positive(optarg); + } else if (on_off->optarg) { *(char **)(on_off->optarg) = optarg; + } } - if (pargv != NULL) - break; } /* 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; }