getopt32: move support for "always treat first arg as option" to users (tar/ar)
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 4 Aug 2017 14:46:17 +0000 (16:46 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 4 Aug 2017 14:46:17 +0000 (16:46 +0200)
Now getopt() never leaks (and never performs) any xmalloc's.

function                                             old     new   delta
ar_main                                              522     556     +34
tar_main                                             986    1014     +28
getopt32                                            1458    1350    -108
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 62/-108)           Total: -46 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
archival/ar.c
archival/tar.c
libbb/getopt32.c

index 2886d155b66ca37de960284f0be1f62fab20a38c..46c10aad49a6b6f11ce1490e03f2623f8459e855 100644 (file)
@@ -240,10 +240,12 @@ int ar_main(int argc UNUSED_PARAM, char **argv)
 
        archive_handle = init_handle();
 
-       /* --: prepend '-' to the first argument if required */
+       /* prepend '-' to the first argument if required */
+       if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0')
+               argv[1] = xasprintf("-%s", argv[1]);
        /* -1: at least one param is reqd */
        /* one of p,t,x[,r] is required */
-       opt_complementary = "--:-1:p:t:x"IF_FEATURE_AR_CREATE(":r");
+       opt_complementary = "-1:p:t:x"IF_FEATURE_AR_CREATE(":r");
        opt = getopt32(argv, "voc""ptx"IF_FEATURE_AR_CREATE("r"));
        argv += optind;
 
index 280ded4e14e325811e2cf976a050bac6e7ba4b27..f62b330056277c976fa7e38892d30b4db7de1b2b 100644 (file)
@@ -966,7 +966,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
                tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
 
        /* Prepend '-' to the first argument if required */
-       opt_complementary = "--:" // first arg is options
+       if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0')
+               argv[1] = xasprintf("-%s", argv[1]);
+       opt_complementary =
                "tt:vv:" // count -t,-v
 #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
                "\xff::" // --exclude=PATTERN is a list
index 129840cea3c974b1102297fcf99b4de2cda2ee1c..513415894ebd6aa5393106a46868c591e66f91ea 100644 (file)
@@ -171,16 +171,6 @@ const char *opt_complementary
 
 Special characters:
 
- "--"   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
-        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.
-
  "-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
         arguments must be present on the command line
@@ -337,6 +327,8 @@ const char *applet_long_options;
 
 uint32_t option_mask32;
 
+/* Please keep getopt32 free from xmalloc */
+
 uint32_t FAST_FUNC
 getopt32(char **argv, const char *applet_opts, ...)
 {
@@ -354,12 +346,10 @@ getopt32(char **argv, const char *applet_opts, ...)
        struct option *long_options = (struct option *) &bb_null_long_options;
 #endif
        unsigned trigger;
-       char **pargv;
        int min_arg = 0;
        int max_arg = -1;
 
 #define SHOW_USAGE_IF_ERROR     1
-#define FIRST_ARGV_IS_OPT       2
 
        int spec_flgs = 0;
 
@@ -467,12 +457,7 @@ getopt32(char **argv, const char *applet_opts, ...)
                        continue;
                }
                if (*s == '-') {
-                       if (c < '0' || c > '9') {
-                               if (c == '-') {
-                                       spec_flgs |= FIRST_ARGV_IS_OPT;
-                                       s++;
-                               }
-                       } else {
+                       if (c >= '0' && c <= '9') {
                                min_arg = c - '0';
                                s++;
                        }
@@ -535,21 +520,6 @@ getopt32(char **argv, const char *applet_opts, ...)
        opt_complementary = NULL;
        va_end(p);
 
-       if (spec_flgs & FIRST_ARGV_IS_OPT) {
-               pargv = argv + 1;
-               if (*pargv) {
-                       if (pargv[0][0] != '-' && pargv[0][0] != '\0') {
-                               /* Can't use alloca: opts with params will
-                                * return pointers to stack!
-                                * NB: we leak these allocations... */
-                               char *pp = xmalloc(strlen(*pargv) + 2);
-                               *pp = '-';
-                               strcpy(pp + 1, *pargv);
-                               *pargv = pp;
-                       }
-               }
-       }
-
        /* In case getopt32 was already called:
         * reset the libc getopt() function, which keeps internal state.
         * run_nofork_applet() does this, but we might end up here