Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/libbb/getopt32.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/libbb/getopt32.c
r1765 r2725 5 5 * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru> 6 6 * 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 8 */ 9 9 … … 31 31 "r" will add 1 (bit 0) 32 32 "n" will add 2 (bit 1) 33 "u 33 "u" will add 4 (bit 2) 34 34 "g" will add 8 (bit 3) 35 35 … … 73 73 Here we want env to process just the '-i', not the '-d'. 74 74 75 "!" Report bad option, missing required options, 76 inconsistent options with all-ones return value (instead of abort). 77 75 78 const char *applet_long_options 76 79 … … 113 116 114 117 "ww" Adjacent double options have a counter associated which indicates 115 the number of occur ences of the option.118 the number of occurrences of the option. 116 119 For example the ps applet needs: 117 120 if w is given once, GNU ps sets the width to 132, 118 121 if w is given more than once, it is "unlimited" 119 122 120 int w_counter = 0; 123 int w_counter = 0; // must be initialized! 121 124 opt_complementary = "ww"; 122 125 getopt32(argv, "w", &w_counter); … … 138 141 f = getopt32(argv, "vb:c", &my_b, &verbose_level); 139 142 if (f & 2) // -c after -b unsets -b flag 140 while (my_b) { dosomething_with(my_b->data); my_b = my_b->link; }143 while (my_b) dosomething_with(llist_pop(&my_b)); 141 144 if (my_b) // but llist is stored if -b is specified 142 145 free_llist(my_b); … … 145 148 Special characters: 146 149 147 "-" A dash as the first char in a opt_complementary group forces148 all arguments to be treated as options, even if they have149 no leading dashes. Next char in this case can't be a digit (0-9),150 use ':' or end of line. For example:151 152 opt_complementary = "-:w-x:x-w"; 153 getopt32(argv, "wx"); 154 155 Allows any arguments to be givenwithout a dash (./program w x)150 "-" A group consisting of just a dash forces all arguments 151 to be treated as options, even if they have no leading dashes. 152 Next char in this case can't be a digit (0-9), use ':' or end of line. 153 Example: 154 155 opt_complementary = "-:w-x:x-w"; // "-w-x:x-w" would also work, 156 getopt32(argv, "wx"); // but is less readable 157 158 This makes it possible to use options without a dash (./program w x) 156 159 as well as with a dash (./program -x). 160 161 NB: getopt32() will leak a small amount of memory if you use 162 this option! Do not use it if there is a possibility of recursive 163 getopt32() calls. 157 164 158 165 "--" A double dash at the beginning of opt_complementary means the … … 162 169 tar xvf foo.tar 163 170 171 NB: getopt32() will leak a small amount of memory if you use 172 this option! Do not use it if there is a possibility of recursive 173 getopt32() calls. 174 164 175 "-N" A dash as the first char in a opt_complementary group followed 165 176 by a single digit (0-9) means that at least N non-option … … 175 186 176 187 "V-" An option with dash before colon or end-of-line results in 177 bb_show_usage being called if this option is encountered.188 bb_show_usage() being called if this option is encountered. 178 189 This is typically used to implement "print verbose usage message 179 190 and exit" option. 180 191 181 " -"A dash between two options causes the second of the two192 "a-b" A dash between two options causes the second of the two 182 193 to be unset (and ignored) if it is given on the command line. 183 194 … … 205 216 printf("Detected odd -x usage\n"); 206 217 207 " --"A double dash between two options, or between an option and a group218 "a--b" A double dash between two options, or between an option and a group 208 219 of options, means that they are mutually exclusive. Unlike 209 220 the "-" case above, an error will be forced if the options … … 221 232 at most once. 222 233 223 "::" A double colon after a char in opt_complementary means that the 234 "a+" A plus after a char in opt_complementary means that the parameter 235 for this option is a nonnegative integer. It will be processed 236 with xatoi_positive() - allowed range is 0..INT_MAX. 237 238 int param; // "unsigned param;" will also work 239 opt_complementary = "p+"; 240 getopt32(argv, "p:", ¶m); 241 242 "a::" A double colon after a char in opt_complementary means that the 224 243 option can occur multiple times. Each occurrence will be saved as 225 244 a llist_t element instead of char*. … … 241 260 user:x:500:500::/home/user:/bin/bash 242 261 243 " ?" An"?" between an option and a group of options means that262 "a?b" A "?" between an option and a group of options means that 244 263 at least one of them is required to occur if the first option 245 264 occurs in preceding command line arguments. … … 248 267 249 268 // Don't allow -n -r -rn -ug -rug -nug -rnug 250 opt_complementary = "r?ug:n?ug: ?u--g:g--u";269 opt_complementary = "r?ug:n?ug:u--g:g--u"; 251 270 flags = getopt32(argv, "rnug"); 252 271 … … 260 279 261 280 // Don't allow -KS -SK, but -S or -K is required 262 opt_complementary = "K:S: ?K--S:S--K";281 opt_complementary = "K:S:K--S:S--K"; 263 282 flags = getopt32(argv, "KS...); 264 283 … … 269 288 a '-2' option then unset '-3', '-X' and '-a'; if there is 270 289 a '-2' and after it a '-x' then error out. 290 But it's far too obfuscated. Use ':' to separate groups. 271 291 */ 272 292 273 293 /* Code here assumes that 'unsigned' is at least 32 bits wide */ 274 294 295 const char *const bb_argv_dash[] = { "-", NULL }; 296 275 297 const char *opt_complementary; 276 298 299 enum { 300 PARAM_STRING, 301 PARAM_LIST, 302 PARAM_INT, 303 }; 304 277 305 typedef struct { 278 int opt;279 int list_flg;306 unsigned char opt_char; 307 smallint param_type; 280 308 unsigned switch_on; 281 309 unsigned switch_off; 282 310 unsigned incongruously; 283 311 unsigned requires; 284 void **optarg; /* char **optarg or llist_t **optarg*/312 void **optarg; /* char**, llist_t** or int *. */ 285 313 int *counter; 286 314 } t_complementary; 287 315 288 316 /* You can set applet_long_options for parse called long options */ 289 #if ENABLE_ GETOPT_LONG317 #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 290 318 static const struct option bb_null_long_options[1] = { 291 319 { 0, 0, 0, 0 } … … 296 324 uint32_t option_mask32; 297 325 298 uint32_t 326 uint32_t FAST_FUNC 299 327 getopt32(char **argv, const char *applet_opts, ...) 300 328 { … … 302 330 unsigned flags = 0; 303 331 unsigned requires = 0; 304 t_complementary complementary[33]; 332 t_complementary complementary[33]; /* last stays zero-filled */ 333 char first_char; 305 334 int c; 306 335 const unsigned char *s; 307 336 t_complementary *on_off; 308 337 va_list p; 309 #if ENABLE_ GETOPT_LONG338 #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 310 339 const struct option *l_o; 311 340 struct option *long_options = (struct option *) &bb_null_long_options; 312 341 #endif 313 342 unsigned trigger; 314 char **pargv = NULL;343 char **pargv; 315 344 int min_arg = 0; 316 345 int max_arg = -1; … … 319 348 #define ALL_ARGV_IS_OPTS 2 320 349 #define FIRST_ARGV_IS_OPT 4 321 #define FREE_FIRST_ARGV_IS_OPT 8 350 322 351 int spec_flgs = 0; 323 352 324 argc = 0; 353 /* skip 0: some applets cheat: they do not actually HAVE argv[0] */ 354 argc = 1; 325 355 while (argv[argc]) 326 356 argc++; … … 331 361 on_off = complementary; 332 362 memset(on_off, 0, sizeof(complementary)); 363 364 /* skip bbox extension */ 365 first_char = applet_opts[0]; 366 if (first_char == '!') 367 applet_opts++; 333 368 334 369 /* skip GNU extension */ … … 337 372 s++; 338 373 while (*s) { 339 if (c >= 32) break; 340 on_off->opt = *s; 374 if (c >= 32) 375 break; 376 on_off->opt_char = *s; 341 377 on_off->switch_on = (1 << c); 342 378 if (*++s == ':') { 343 379 on_off->optarg = va_arg(p, void **); 344 while (*++s == ':') /* skip */; 380 while (*++s == ':') 381 continue; 345 382 } 346 383 on_off++; … … 348 385 } 349 386 350 #if ENABLE_ GETOPT_LONG387 #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 351 388 if (applet_long_options) { 352 389 const char *optstr; … … 375 412 if (l_o->flag) 376 413 continue; 377 for (on_off = complementary; on_off->opt != 0; on_off++)378 if (on_off->opt == l_o->val)414 for (on_off = complementary; on_off->opt_char; on_off++) 415 if (on_off->opt_char == l_o->val) 379 416 goto next_long; 380 if (c >= 32) break; 381 on_off->opt = l_o->val; 417 if (c >= 32) 418 break; 419 on_off->opt_char = l_o->val; 382 420 on_off->switch_on = (1 << c); 383 421 if (l_o->has_arg != no_argument) … … 386 424 next_long: ; 387 425 } 426 /* Make it unnecessary to clear applet_long_options 427 * by hand after each call to getopt32 428 */ 429 applet_long_options = NULL; 388 430 } 389 #endif /* ENABLE_ GETOPT_LONG */431 #endif /* ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG */ 390 432 for (s = (const unsigned char *)opt_complementary; s && *s; s++) { 391 433 t_complementary *pair; … … 422 464 continue; 423 465 } 424 for (on_off = complementary; on_off->opt ; on_off++)425 if (on_off->opt == *s)466 for (on_off = complementary; on_off->opt_char; on_off++) 467 if (on_off->opt_char == *s) 426 468 break; 427 469 if (c == ':' && s[2] == ':') { 428 on_off->list_flg++; 470 on_off->param_type = PARAM_LIST; 471 continue; 472 } 473 if (c == '+' && (s[2] == ':' || s[2] == '\0')) { 474 on_off->param_type = PARAM_INT; 429 475 continue; 430 476 } … … 444 490 } 445 491 pair = on_off; 446 pair_switch = & (pair->switch_on);492 pair_switch = &pair->switch_on; 447 493 for (s++; *s && *s != ':'; s++) { 448 494 if (*s == '?') { 449 pair_switch = & (pair->requires);495 pair_switch = &pair->requires; 450 496 } else if (*s == '-') { 451 if (pair_switch == & (pair->switch_off))452 pair_switch = & (pair->incongruously);497 if (pair_switch == &pair->switch_off) 498 pair_switch = &pair->incongruously; 453 499 else 454 pair_switch = & (pair->switch_off);500 pair_switch = &pair->switch_off; 455 501 } else { 456 for (on_off = complementary; on_off->opt ; on_off++)457 if (on_off->opt == *s) {502 for (on_off = complementary; on_off->opt_char; on_off++) 503 if (on_off->opt_char == *s) { 458 504 *pair_switch |= on_off->switch_on; 459 505 break; … … 463 509 s--; 464 510 } 511 opt_complementary = NULL; 465 512 va_end(p); 466 513 467 if (spec_flgs & FIRST_ARGV_IS_OPT) { 468 if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') { 469 argv[1] = xasprintf("-%s", argv[1]); 470 if (ENABLE_FEATURE_CLEAN_UP) 471 spec_flgs |= FREE_FIRST_ARGV_IS_OPT; 514 if (spec_flgs & (FIRST_ARGV_IS_OPT | ALL_ARGV_IS_OPTS)) { 515 pargv = argv + 1; 516 while (*pargv) { 517 if (pargv[0][0] != '-' && pargv[0][0] != '\0') { 518 /* Can't use alloca: opts with params will 519 * return pointers to stack! 520 * NB: we leak these allocations... */ 521 char *pp = xmalloc(strlen(*pargv) + 2); 522 *pp = '-'; 523 strcpy(pp + 1, *pargv); 524 *pargv = pp; 525 } 526 if (!(spec_flgs & ALL_ARGV_IS_OPTS)) 527 break; 528 pargv++; 472 529 } 473 530 } 474 531 475 /* In case getopt32 was already called, reinit some state */ 532 /* In case getopt32 was already called: 533 * reset the libc getopt() function, which keeps internal state. 534 * run_nofork_applet_prime() does this, but we might end up here 535 * also via gunzip_main() -> gzip_main(). Play safe. 536 */ 537 #ifdef __GLIBC__ 538 optind = 0; 539 #else /* BSD style */ 476 540 optind = 1; 477 /* optarg = NULL; opterr = 0; optopt = 0; ?? */ 478 479 /* Note: just "getopt() <= 0" will not work good for 541 /* optreset = 1; */ 542 #endif 543 /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ 544 545 pargv = NULL; 546 547 /* Note: just "getopt() <= 0" will not work well for 480 548 * "fake" short options, like this one: 481 549 * wget $'-\203' "Test: test" http://kernel.org/ 482 550 * (supposed to act as --header, but doesn't) */ 483 #if ENABLE_ GETOPT_LONG551 #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG 484 552 while ((c = getopt_long(argc, argv, applet_opts, 485 553 long_options, NULL)) != -1) { … … 487 555 while ((c = getopt(argc, argv, applet_opts)) != -1) { 488 556 #endif 489 c &= 0xff; /* fight libc's sign extends */ 490 loop_arg_is_opt: 491 for (on_off = complementary; on_off->opt != c; on_off++) { 492 /* c==0 if long opt have non NULL flag */ 493 if (on_off->opt == 0 && c != 0) 494 bb_show_usage(); 557 /* getopt prints "option requires an argument -- X" 558 * and returns '?' if an option has no arg, but one is reqd */ 559 c &= 0xff; /* fight libc's sign extension */ 560 for (on_off = complementary; on_off->opt_char != c; on_off++) { 561 /* c can be NUL if long opt has non-NULL ->flag, 562 * but we construct long opts so that flag 563 * is always NULL (see above) */ 564 if (on_off->opt_char == '\0' /* && c != '\0' */) { 565 /* c is probably '?' - "bad option" */ 566 goto error; 567 } 495 568 } 496 569 if (flags & on_off->incongruously) 497 bb_show_usage();570 goto error; 498 571 trigger = on_off->switch_on & on_off->switch_off; 499 572 flags &= ~(on_off->switch_off ^ trigger); … … 502 575 if (on_off->counter) 503 576 (*(on_off->counter))++; 504 if (on_off->list_flg) { 505 llist_add_to_end((llist_t **)(on_off->optarg), optarg); 577 if (on_off->param_type == PARAM_LIST) { 578 if (optarg) 579 llist_add_to_end((llist_t **)(on_off->optarg), optarg); 580 } else if (on_off->param_type == PARAM_INT) { 581 if (optarg) 582 //TODO: xatoi_positive indirectly pulls in printf machinery 583 *(unsigned*)(on_off->optarg) = xatoi_positive(optarg); 506 584 } else if (on_off->optarg) { 507 *(char **)(on_off->optarg) = optarg; 585 if (optarg) 586 *(char **)(on_off->optarg) = optarg; 508 587 } 509 588 if (pargv != NULL) … … 511 590 } 512 591 513 if (spec_flgs & ALL_ARGV_IS_OPTS) {514 /* process argv is option, for example "ps" applet */515 if (pargv == NULL)516 pargv = argv + optind;517 while (*pargv) {518 c = **pargv;519 if (c == '\0') {520 pargv++;521 } else {522 (*pargv)++;523 goto loop_arg_is_opt;524 }525 }526 }527 528 #if (ENABLE_AR || ENABLE_TAR) && ENABLE_FEATURE_CLEAN_UP529 if (spec_flgs & FREE_FIRST_ARGV_IS_OPT)530 free(argv[1]);531 #endif532 592 /* check depending requires for given options */ 533 for (on_off = complementary; on_off->opt; on_off++) { 534 if (on_off->requires && (flags & on_off->switch_on) && 535 (flags & on_off->requires) == 0) 536 bb_show_usage(); 593 for (on_off = complementary; on_off->opt_char; on_off++) { 594 if (on_off->requires 595 && (flags & on_off->switch_on) 596 && (flags & on_off->requires) == 0 597 ) { 598 goto error; 599 } 537 600 } 538 601 if (requires && (flags & requires) == 0) 539 bb_show_usage();602 goto error; 540 603 argc -= optind; 541 604 if (argc < min_arg || (max_arg >= 0 && argc > max_arg)) 542 bb_show_usage();605 goto error; 543 606 544 607 option_mask32 = flags; 545 608 return flags; 609 610 error: 611 if (first_char != '!') 612 bb_show_usage(); 613 return (int32_t)-1; 546 614 }
Note:
See TracChangeset
for help on using the changeset viewer.