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 <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2017-08-04 16:46:17 +02:00
parent 727948e585
commit dd5a40246b
3 changed files with 10 additions and 36 deletions

View File

@ -240,10 +240,12 @@ int ar_main(int argc UNUSED_PARAM, char **argv)
archive_handle = init_handle(); 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 */ /* -1: at least one param is reqd */
/* one of p,t,x[,r] is required */ /* 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")); opt = getopt32(argv, "voc""ptx"IF_FEATURE_AR_CREATE("r"));
argv += optind; argv += optind;

View File

@ -966,7 +966,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM; tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
/* Prepend '-' to the first argument if required */ /* 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 "tt:vv:" // count -t,-v
#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
"\xff::" // --exclude=PATTERN is a list "\xff::" // --exclude=PATTERN is a list

View File

@ -171,16 +171,6 @@ const char *opt_complementary
Special characters: 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 "-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 by a single digit (0-9) means that at least N non-option
arguments must be present on the command line arguments must be present on the command line
@ -337,6 +327,8 @@ const char *applet_long_options;
uint32_t option_mask32; uint32_t option_mask32;
/* Please keep getopt32 free from xmalloc */
uint32_t FAST_FUNC uint32_t FAST_FUNC
getopt32(char **argv, const char *applet_opts, ...) 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; struct option *long_options = (struct option *) &bb_null_long_options;
#endif #endif
unsigned trigger; unsigned trigger;
char **pargv;
int min_arg = 0; int min_arg = 0;
int max_arg = -1; int max_arg = -1;
#define SHOW_USAGE_IF_ERROR 1 #define SHOW_USAGE_IF_ERROR 1
#define FIRST_ARGV_IS_OPT 2
int spec_flgs = 0; int spec_flgs = 0;
@ -467,12 +457,7 @@ getopt32(char **argv, const char *applet_opts, ...)
continue; continue;
} }
if (*s == '-') { if (*s == '-') {
if (c < '0' || c > '9') { if (c >= '0' && c <= '9') {
if (c == '-') {
spec_flgs |= FIRST_ARGV_IS_OPT;
s++;
}
} else {
min_arg = c - '0'; min_arg = c - '0';
s++; s++;
} }
@ -535,21 +520,6 @@ getopt32(char **argv, const char *applet_opts, ...)
opt_complementary = NULL; opt_complementary = NULL;
va_end(p); 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: /* In case getopt32 was already called:
* reset the libc getopt() function, which keeps internal state. * reset the libc getopt() function, which keeps internal state.
* run_nofork_applet() does this, but we might end up here * run_nofork_applet() does this, but we might end up here