unzip: make options parsing more robust on getopt w/o gnu extensions

Also, code shrank:

function                                             old     new   delta
static.extn                                           15      10      -5
packed_usage                                       29231   29217     -14
unzip_main                                          2388    2291     -97
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-116)           Total: -116 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2012-06-15 16:43:26 +02:00
parent 604499e5a9
commit c5b01016e6

View File

@ -20,11 +20,11 @@
*/ */
//usage:#define unzip_trivial_usage //usage:#define unzip_trivial_usage
//usage: "[-opts[modifiers]] FILE[.zip] [LIST] [-x XLIST] [-d DIR]" //usage: "[-lnopq] FILE[.zip] [LIST] [-x XLIST] [-d DIR]"
//usage:#define unzip_full_usage "\n\n" //usage:#define unzip_full_usage "\n\n"
//usage: "Extract files from ZIP archives\n" //usage: "Extract files from ZIP archives\n"
//usage: "\n -l List archive contents (with -q for short form)" //usage: "\n -l List archive contents (with -q for short form)"
//usage: "\n -n Never overwrite files (default)" //usage: "\n -n Never overwrite files (default: ask)"
//usage: "\n -o Overwrite" //usage: "\n -o Overwrite"
//usage: "\n -p Send output to stdout" //usage: "\n -p Send output to stdout"
//usage: "\n -q Quiet" //usage: "\n -q Quiet"
@ -277,6 +277,7 @@ int unzip_main(int argc, char **argv)
IF_NOT_DESKTOP(const) smallint verbose = 0; IF_NOT_DESKTOP(const) smallint verbose = 0;
smallint listing = 0; smallint listing = 0;
smallint overwrite = O_PROMPT; smallint overwrite = O_PROMPT;
smallint x_opt_seen;
#if ENABLE_DESKTOP #if ENABLE_DESKTOP
uint32_t cdf_offset; uint32_t cdf_offset;
#endif #endif
@ -290,7 +291,6 @@ int unzip_main(int argc, char **argv)
llist_t *zreject = NULL; llist_t *zreject = NULL;
char *base_dir = NULL; char *base_dir = NULL;
int i, opt; int i, opt;
int opt_range = 0;
char key_buf[80]; char key_buf[80];
struct stat stat_buf; struct stat stat_buf;
@ -335,81 +335,81 @@ int unzip_main(int argc, char **argv)
* 204372 1 file * 204372 1 file
*/ */
x_opt_seen = 0;
/* '-' makes getopt return 1 for non-options */ /* '-' makes getopt return 1 for non-options */
while ((opt = getopt(argc, argv, "-d:lnopqxv")) != -1) { while ((opt = getopt(argc, argv, "-d:lnopqxv")) != -1) {
switch (opt_range) { switch (opt) {
case 0: /* Options */ case 'd': /* Extract to base directory */
switch (opt) { base_dir = optarg;
case 'l': /* List */ break;
listing = 1;
break;
case 'n': /* Never overwrite existing files */ case 'l': /* List */
overwrite = O_NEVER; listing = 1;
break; break;
case 'o': /* Always overwrite existing files */ case 'n': /* Never overwrite existing files */
overwrite = O_ALWAYS; overwrite = O_NEVER;
break; break;
case 'p': /* Extract files to stdout and fall through to set verbosity */ case 'o': /* Always overwrite existing files */
dst_fd = STDOUT_FILENO; overwrite = O_ALWAYS;
break;
case 'q': /* Be quiet */ case 'p': /* Extract files to stdout and fall through to set verbosity */
quiet++; dst_fd = STDOUT_FILENO;
break;
case 'v': /* Verbose list */ case 'q': /* Be quiet */
IF_DESKTOP(verbose++;) quiet++;
listing = 1; break;
break;
case 1: /* The zip file */ case 'v': /* Verbose list */
IF_DESKTOP(verbose++;)
listing = 1;
break;
case 'x':
x_opt_seen = 1;
break;
case 1:
if (!src_fn) {
/* The zip file */
/* +5: space for ".zip" and NUL */ /* +5: space for ".zip" and NUL */
src_fn = xmalloc(strlen(optarg) + 5); src_fn = xmalloc(strlen(optarg) + 5);
strcpy(src_fn, optarg); strcpy(src_fn, optarg);
opt_range++; } else if (!x_opt_seen) {
break; /* Include files */
llist_add_to(&zaccept, optarg);
default: } else {
bb_show_usage(); /* Exclude files */
llist_add_to(&zreject, optarg);
} }
break; break;
case 1: /* Include files */
if (opt == 1) {
llist_add_to(&zaccept, optarg);
break;
}
if (opt == 'd') {
base_dir = optarg;
opt_range += 2;
break;
}
if (opt == 'x') {
opt_range++;
break;
}
bb_show_usage();
case 2 : /* Exclude files */
if (opt == 1) {
llist_add_to(&zreject, optarg);
break;
}
if (opt == 'd') { /* Extract to base directory */
base_dir = optarg;
opt_range++;
break;
}
/* fall through */
default: default:
bb_show_usage(); bb_show_usage();
} }
} }
if (src_fn == NULL) { #ifndef __GLIBC__
/*
* This code is needed for non-GNU getopt
* which doesn't understand "-" in option string.
* The -x option won't work properly in this case:
* "unzip a.zip q -x w e" will be interpreted as
* "unzip a.zip q w e -x" = "unzip a.zip q w e"
*/
argv += optind;
if (argv[0]) {
/* +5: space for ".zip" and NUL */
src_fn = xmalloc(strlen(argv[0]) + 5);
strcpy(src_fn, argv[0]);
while (*++argv)
llist_add_to(&zaccept, *argv);
}
#endif
if (!src_fn) {
bb_show_usage(); bb_show_usage();
} }
@ -420,17 +420,20 @@ int unzip_main(int argc, char **argv)
if (overwrite == O_PROMPT) if (overwrite == O_PROMPT)
overwrite = O_NEVER; overwrite = O_NEVER;
} else { } else {
static const char extn[][5] = {"", ".zip", ".ZIP"}; static const char extn[][5] = { ".zip", ".ZIP" };
int orig_src_fn_len = strlen(src_fn); char *ext = src_fn + strlen(src_fn);
int src_fd = -1; int src_fd;
for (i = 0; (i < 3) && (src_fd == -1); i++) { i = 0;
strcpy(src_fn + orig_src_fn_len, extn[i]); for (;;) {
src_fd = open(src_fn, O_RDONLY); src_fd = open(src_fn, O_RDONLY);
} if (src_fd >= 0)
if (src_fd == -1) { break;
src_fn[orig_src_fn_len] = '\0'; if (++i > 2) {
bb_error_msg_and_die("can't open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn); *ext = '\0';
bb_error_msg_and_die("can't open %s[.zip]", src_fn);
}
strcpy(ext, extn[i - 1]);
} }
xmove_fd(src_fd, zip_fd); xmove_fd(src_fd, zip_fd);
} }