getopt32: factor out code to treat all args as options
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 4 Aug 2017 14:23:42 +0000 (16:23 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 4 Aug 2017 14:33:23 +0000 (16:33 +0200)
Working towards making getopt32() xmalloc-free

function                                             old     new   delta
make_all_argv_opts                                     -      58     +58
top_main                                             914     912      -2
getopt32                                            1517    1458     -59
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 0/2 up/down: 58/-61)             Total: -3 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
include/libbb.h
libbb/Kbuild.src
libbb/getopt32.c
libbb/getopt_allopts.c [new file with mode: 0644]
procps/ps.c
procps/top.c

index 46180c5aa867bd9e14355425db5807cb9d06bcd8..bb27c59a15f84a2426a8afa8c06a582a27d3c22b 100644 (file)
@@ -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()
index 458973f17afe17bc60dc58a4126d7fde5948701a..73201a6bd5d6428257f78e1d2af4b3efad8271ee 100644 (file)
@@ -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
index 80f4cc060d7ad2d460af2c1c32b3bfd82b1b7568..129840cea3c974b1102297fcf99b4de2cda2ee1c 100644 (file)
@@ -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 <getopt.h>
 #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 (file)
index 0000000..a67d2b7
--- /dev/null
@@ -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;
+       }
+}
index eb1946d27758bf34897a227c0d5b278ffb80d405..081479b33d4e870d587779d3bfa68ddce8b3215f 100644 (file)
@@ -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
 
index 015d1ab74e8cc7c7844f13dc9af22d24a6810e17..1bc432fc9ffbce5d41597cbdf0eb99e509734aa0 100644 (file)
@@ -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 */