diff options
Diffstat (limited to 'libbb/getopt32.c')
-rw-r--r-- | libbb/getopt32.c | 27 |
1 files changed, 23 insertions, 4 deletions
diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 2452eb0..80d5d28 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -473,11 +473,30 @@ getopt32(char **argv, const char *applet_opts, ...) } } - /* In case getopt32 was already called, reinit some state */ + /* 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? + */ +#ifdef __GLIBC__ + optind = 0; +#else /* BSD style */ optind = 1; - /* optarg = NULL; opterr = 0; optopt = 0; ?? */ + /* optreset = 1; */ +#endif + /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ - /* Note: just "getopt() <= 0" will not work good for + /* 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) */ @@ -487,7 +506,7 @@ getopt32(char **argv, const char *applet_opts, ...) #else while ((c = getopt(argc, argv, applet_opts)) != -1) { #endif - c &= 0xff; /* fight libc's sign extends */ + c &= 0xff; /* fight libc's sign extension */ loop_arg_is_opt: for (on_off = complementary; on_off->opt != c; on_off++) { /* c==0 if long opt have non NULL flag */ |