diff --git a/include/libbb.h b/include/libbb.h index 46180c5aa..bb27c59a1 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1183,7 +1183,9 @@ extern const char *opt_complementary; extern const char *applet_long_options; #endif extern uint32_t option_mask32; -extern uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; +uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; +/* For top, ps. Some argv[i] are replaced by malloced "-opt" strings */ +void make_all_argv_opts(char **argv) FAST_FUNC; /* 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() diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 458973f17..73201a6bd 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -40,7 +40,6 @@ lib-y += full_write.o lib-y += get_console.o lib-y += get_last_path_component.o lib-y += get_line_from_file.o -lib-y += getopt32.o lib-y += getpty.o lib-y += get_volsize.o lib-y += herror_msg.o diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 80f4cc060..129840cea 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -6,12 +6,13 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG # include #endif #include "libbb.h" +//kbuild:lib-y += getopt32.o + /* Documentation uint32_t @@ -170,21 +171,6 @@ const char *opt_complementary Special characters: - "-" 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"; // "-w-x:x-w" would also work, - getopt32(argv, "wx"); // but is less readable - - 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. - "--" 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 prefixed with a "-". This is useful for special syntax in applets @@ -373,8 +359,7 @@ getopt32(char **argv, const char *applet_opts, ...) int max_arg = -1; #define SHOW_USAGE_IF_ERROR 1 -#define ALL_ARGV_IS_OPTS 2 -#define FIRST_ARGV_IS_OPT 4 +#define FIRST_ARGV_IS_OPT 2 int spec_flgs = 0; @@ -486,8 +471,7 @@ getopt32(char **argv, const char *applet_opts, ...) if (c == '-') { spec_flgs |= FIRST_ARGV_IS_OPT; s++; - } else - spec_flgs |= ALL_ARGV_IS_OPTS; + } } else { min_arg = c - '0'; s++; @@ -551,9 +535,9 @@ getopt32(char **argv, const char *applet_opts, ...) opt_complementary = NULL; va_end(p); - if (spec_flgs & (FIRST_ARGV_IS_OPT | ALL_ARGV_IS_OPTS)) { + if (spec_flgs & FIRST_ARGV_IS_OPT) { pargv = argv + 1; - while (*pargv) { + if (*pargv) { if (pargv[0][0] != '-' && pargv[0][0] != '\0') { /* Can't use alloca: opts with params will * return pointers to stack! @@ -563,9 +547,6 @@ getopt32(char **argv, const char *applet_opts, ...) strcpy(pp + 1, *pargv); *pargv = pp; } - if (!(spec_flgs & ALL_ARGV_IS_OPTS)) - break; - pargv++; } } diff --git a/libbb/getopt_allopts.c b/libbb/getopt_allopts.c new file mode 100644 index 000000000..a67d2b70e --- /dev/null +++ b/libbb/getopt_allopts.c @@ -0,0 +1,27 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" + +//kbuild:lib-y += getopt_allopts.o + +void FAST_FUNC make_all_argv_opts(char **argv) +{ + /* Note: we skip argv[0] */ + while (*++argv) { + char *p; + + if (argv[0][0] == '-') + continue; + /* Neither top nor ps care if "" arg turns into "-" */ + /*if (argv[0][0] == '\0') + continue;*/ + p = xmalloc(strlen(*argv) + 2); + *p = '-'; + strcpy(p + 1, *argv); + *argv = p; + } +} diff --git a/procps/ps.c b/procps/ps.c index eb1946d27..081479b33 100644 --- a/procps/ps.c +++ b/procps/ps.c @@ -715,7 +715,8 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) # if ENABLE_FEATURE_PS_WIDE /* -w is a bit complicated */ int w_count = 0; - opt_complementary = "-:ww"; + make_all_argv_opts(argv); + opt_complementary = "ww"; opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l") "w", &w_count); /* if w is given once, GNU ps sets the width to 132, @@ -731,7 +732,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) } # else /* -w is not supported, only -Z and/or -T */ - opt_complementary = "-"; + make_all_argv_opts(argv); opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")); # endif diff --git a/procps/top.c b/procps/top.c index 015d1ab74..1bc432fc9 100644 --- a/procps/top.c +++ b/procps/top.c @@ -1110,15 +1110,14 @@ int top_main(int argc UNUSED_PARAM, char **argv) #endif /* all args are options; -n NUM */ - opt_complementary = "-"; /* options can be specified w/o dash */ + make_all_argv_opts(argv); /* options can be specified w/o dash */ col = getopt32(argv, "d:n:b"IF_FEATURE_TOPMEM("m"), &str_interval, &str_iterations); #if ENABLE_FEATURE_TOPMEM if (col & OPT_m) /* -m (busybox specific) */ scan_mask = TOPMEM_MASK; #endif if (col & OPT_d) { - /* work around for "-d 1" -> "-d -1" done by getopt32 - * (opt_complementary == "-" does this) */ + /* work around for "-d 1" -> "-d -1" done by make_all_argv_opts() */ if (str_interval[0] == '-') str_interval++; /* Need to limit it to not overflow poll timeout */