diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-08-20 00:12:22 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-08-20 00:12:22 +0000 |
commit | 1c45a505eb109af13e5399c2b016acec4ad10421 (patch) | |
tree | 589faea46f22af74b5ac7e4cc31e1ddae6f7d0c7 | |
parent | 6c4eb4411305f61b3f96eefe0ebb147c7f8e6c6d (diff) | |
download | busybox-w32-1c45a505eb109af13e5399c2b016acec4ad10421.tar.gz busybox-w32-1c45a505eb109af13e5399c2b016acec4ad10421.tar.bz2 busybox-w32-1c45a505eb109af13e5399c2b016acec4ad10421.zip |
libbb: fix mishandling of "all argv are opts" in getopt32()
function old new delta
top_main 1100 1095 -5
getopt32 1398 1361 -37
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-42) Total: -42 bytes
-rw-r--r-- | libbb/getopt32.c | 64 | ||||
-rw-r--r-- | procps/top.c | 3 |
2 files changed, 25 insertions, 42 deletions
diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 9dba44db2..611333c66 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c | |||
@@ -174,7 +174,7 @@ Special characters: | |||
174 | on the command line. | 174 | on the command line. |
175 | 175 | ||
176 | "V-" An option with dash before colon or end-of-line results in | 176 | "V-" An option with dash before colon or end-of-line results in |
177 | bb_show_usage being called if this option is encountered. | 177 | bb_show_usage() being called if this option is encountered. |
178 | This is typically used to implement "print verbose usage message | 178 | This is typically used to implement "print verbose usage message |
179 | and exit" option. | 179 | and exit" option. |
180 | 180 | ||
@@ -285,10 +285,6 @@ const char *const bb_argv_dash[] = { "-", NULL }; | |||
285 | 285 | ||
286 | const char *opt_complementary; | 286 | const char *opt_complementary; |
287 | 287 | ||
288 | /* Many small applets don't want to suck in stdio.h only because | ||
289 | * they need to parse options by calling us */ | ||
290 | #define DONT_USE_PRINTF 1 | ||
291 | |||
292 | enum { | 288 | enum { |
293 | PARAM_STRING, | 289 | PARAM_STRING, |
294 | PARAM_LIST, | 290 | PARAM_LIST, |
@@ -322,7 +318,7 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
322 | int argc; | 318 | int argc; |
323 | unsigned flags = 0; | 319 | unsigned flags = 0; |
324 | unsigned requires = 0; | 320 | unsigned requires = 0; |
325 | t_complementary complementary[33]; | 321 | t_complementary complementary[33]; /* last stays zero-filled */ |
326 | int c; | 322 | int c; |
327 | const unsigned char *s; | 323 | const unsigned char *s; |
328 | t_complementary *on_off; | 324 | t_complementary *on_off; |
@@ -332,14 +328,13 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
332 | struct option *long_options = (struct option *) &bb_null_long_options; | 328 | struct option *long_options = (struct option *) &bb_null_long_options; |
333 | #endif | 329 | #endif |
334 | unsigned trigger; | 330 | unsigned trigger; |
335 | char **pargv = NULL; | 331 | char **pargv; |
336 | int min_arg = 0; | 332 | int min_arg = 0; |
337 | int max_arg = -1; | 333 | int max_arg = -1; |
338 | 334 | ||
339 | #define SHOW_USAGE_IF_ERROR 1 | 335 | #define SHOW_USAGE_IF_ERROR 1 |
340 | #define ALL_ARGV_IS_OPTS 2 | 336 | #define ALL_ARGV_IS_OPTS 2 |
341 | #define FIRST_ARGV_IS_OPT 4 | 337 | #define FIRST_ARGV_IS_OPT 4 |
342 | #define FREE_FIRST_ARGV_IS_OPT (8 * !DONT_USE_PRINTF) | ||
343 | 338 | ||
344 | int spec_flgs = 0; | 339 | int spec_flgs = 0; |
345 | 340 | ||
@@ -493,17 +488,18 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
493 | } | 488 | } |
494 | va_end(p); | 489 | va_end(p); |
495 | 490 | ||
496 | if (spec_flgs & FIRST_ARGV_IS_OPT) { | 491 | if (spec_flgs & (FIRST_ARGV_IS_OPT | ALL_ARGV_IS_OPTS)) { |
497 | if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') { | 492 | pargv = argv + 1; |
498 | #if DONT_USE_PRINTF | 493 | while (*pargv) { |
499 | char *pp = alloca(strlen(argv[1]) + 2); | 494 | if (pargv[0][0] != '-' && pargv[0][0] != '\0') { |
500 | *pp = '-'; | 495 | char *pp = alloca(strlen(*pargv) + 2); |
501 | strcpy(pp + 1, argv[1]); | 496 | *pp = '-'; |
502 | argv[1] = pp; | 497 | strcpy(pp + 1, *pargv); |
503 | #else | 498 | *pargv = pp; |
504 | argv[1] = xasprintf("-%s", argv[1]); | 499 | } |
505 | spec_flgs |= FREE_FIRST_ARGV_IS_OPT; | 500 | if (!(spec_flgs & ALL_ARGV_IS_OPTS)) |
506 | #endif | 501 | break; |
502 | pargv++; | ||
507 | } | 503 | } |
508 | } | 504 | } |
509 | 505 | ||
@@ -529,6 +525,7 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
529 | /* optreset = 1; */ | 525 | /* optreset = 1; */ |
530 | #endif | 526 | #endif |
531 | /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ | 527 | /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ |
528 | pargv = NULL; | ||
532 | 529 | ||
533 | /* Note: just "getopt() <= 0" will not work well for | 530 | /* Note: just "getopt() <= 0" will not work well for |
534 | * "fake" short options, like this one: | 531 | * "fake" short options, like this one: |
@@ -540,12 +537,17 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
540 | #else | 537 | #else |
541 | while ((c = getopt(argc, argv, applet_opts)) != -1) { | 538 | while ((c = getopt(argc, argv, applet_opts)) != -1) { |
542 | #endif | 539 | #endif |
540 | /* getopt prints "option requires an argument -- X" | ||
541 | * and returns '?' if an option has no arg, but one is reqd */ | ||
543 | c &= 0xff; /* fight libc's sign extension */ | 542 | c &= 0xff; /* fight libc's sign extension */ |
544 | loop_arg_is_opt: | ||
545 | for (on_off = complementary; on_off->opt_char != c; on_off++) { | 543 | for (on_off = complementary; on_off->opt_char != c; on_off++) { |
546 | /* c==0 if long opt have non NULL flag */ | 544 | /* c can be NUL if long opt has non-NULL ->flag, |
547 | if (on_off->opt_char == '\0' && c != '\0') | 545 | * but we construct long opts so that flag |
546 | * is always NULL (see above) */ | ||
547 | if (on_off->opt_char == '\0' /* && c != '\0' */) { | ||
548 | /* c is probably '?' - "bad option" */ | ||
548 | bb_show_usage(); | 549 | bb_show_usage(); |
550 | } | ||
549 | } | 551 | } |
550 | if (flags & on_off->incongruously) | 552 | if (flags & on_off->incongruously) |
551 | bb_show_usage(); | 553 | bb_show_usage(); |
@@ -570,24 +572,6 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
570 | break; | 572 | break; |
571 | } | 573 | } |
572 | 574 | ||
573 | if (spec_flgs & ALL_ARGV_IS_OPTS) { | ||
574 | /* process argv is option, for example "ps" applet */ | ||
575 | if (pargv == NULL) | ||
576 | pargv = argv + optind; | ||
577 | while (*pargv) { | ||
578 | c = **pargv; | ||
579 | if (c == '\0') { | ||
580 | pargv++; | ||
581 | } else { | ||
582 | (*pargv)++; | ||
583 | goto loop_arg_is_opt; | ||
584 | } | ||
585 | } | ||
586 | } | ||
587 | |||
588 | if (spec_flgs & FREE_FIRST_ARGV_IS_OPT) | ||
589 | free(argv[1]); | ||
590 | |||
591 | /* check depending requires for given options */ | 575 | /* check depending requires for given options */ |
592 | for (on_off = complementary; on_off->opt_char; on_off++) { | 576 | for (on_off = complementary; on_off->opt_char; on_off++) { |
593 | if (on_off->requires && (flags & on_off->switch_on) && | 577 | if (on_off->requires && (flags & on_off->switch_on) && |
diff --git a/procps/top.c b/procps/top.c index 1f1415f83..663eac674 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -763,8 +763,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
763 | 763 | ||
764 | /* all args are options; -n NUM */ | 764 | /* all args are options; -n NUM */ |
765 | opt_complementary = "-:n+"; | 765 | opt_complementary = "-:n+"; |
766 | getopt32(argv, "d:n:b", &sinterval, &iterations); | 766 | if (getopt32(argv, "d:n:b", &sinterval, &iterations) & OPT_d) { |
767 | if (option_mask32 & OPT_d) { | ||
768 | /* Need to limit it to not overflow poll timeout */ | 767 | /* Need to limit it to not overflow poll timeout */ |
769 | interval = xatou16(sinterval); // -d | 768 | interval = xatou16(sinterval); // -d |
770 | } | 769 | } |