From dd5a40246b91bd5d3d165998e6ac3cc4f7083f63 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 16:46:17 +0200 Subject: [PATCH] getopt32: move support for "always treat first arg as option" to users (tar/ar) 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 --- archival/ar.c | 6 ++++-- archival/tar.c | 4 +++- libbb/getopt32.c | 36 +++--------------------------------- 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/archival/ar.c b/archival/ar.c index 2886d155b..46c10aad4 100644 --- a/archival/ar.c +++ b/archival/ar.c @@ -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; diff --git a/archival/tar.c b/archival/tar.c index 280ded4e1..f62b33005 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -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 diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 129840cea..513415894 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -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 -- 2.25.1