1/* Getopt for GNU. 2 NOTE: getopt is now part of the C library, so if you don't know what 3 "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu 4 before changing it! 5 6 Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 7 Free Software Foundation, Inc. 8 9 This program is free software; you can redistribute it and/or modify it 10 under the terms of the GNU General Public License as published by the 11 Free Software Foundation; either version 2, or (at your option) any 12 later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 22 23 24#ifndef EOF 25#include <stdio.h> 26#include <string.h> 27#endif 28 29 30#undef PROGNAME 31#define PROGNAME(x) (x) 32 33 34/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a 35 long-named option. Because this is not POSIX.2 compliant, it is 36 being phased out. */ 37/* #define GETOPT_COMPAT */ 38#undef GETOPT_COMPAT 39 40/* This version of `getopt' appears to the caller like standard Unix `getopt' 41 but it behaves differently for the user, since it allows the user 42 to intersperse the options with the other arguments. 43 44 As `getopt' works, it permutes the elements of ARGV so that, 45 when it is done, all the options precede everything else. Thus 46 all application programs are extended to handle flexible argument order. 47 48 Setting the environment variable POSIXLY_CORRECT disables permutation. 49 Then the behavior is completely standard. 50 51 GNU application programs can use a third alternative mode in which 52 they can distinguish the relative order of options and other arguments. */ 53 54#include "mygetopt.h" 55#define option mfx_option 56#define optarg mfx_optarg 57#define optind mfx_optind 58#define opterr mfx_opterr 59#define optopt mfx_optopt 60#undef BAD_OPTION 61 62/* For communication from `getopt' to the caller. 63 When `getopt' finds an option that takes an argument, 64 the argument value is returned here. 65 Also, when `ordering' is RETURN_IN_ORDER, 66 each non-option ARGV-element is returned here. */ 67 68char *optarg = NULL; 69 70/* Index in ARGV of the next element to be scanned. 71 This is used for communication to and from the caller 72 and for communication between successive calls to `getopt'. 73 74 On entry to `getopt', zero means this is the first call; initialize. 75 76 When `getopt' returns EOF, this is the index of the first of the 77 non-option elements that the caller should itself scan. 78 79 Otherwise, `optind' communicates from one call to the next 80 how much of ARGV has been scanned so far. */ 81 82/* XXX 1003.2 says this must be 1 before any call. */ 83int optind = 0; 84 85/* The next char to be scanned in the option-element 86 in which the last option character we returned was found. 87 This allows us to pick up the scan where we left off. 88 89 If this is zero, or a null string, it means resume the scan 90 by advancing to the next ARGV-element. */ 91 92static char *nextchar; 93 94/* Callers store zero here to inhibit the error message 95 for unrecognized options. */ 96 97int opterr = 1; 98 99/* Set to an option character which was unrecognized. 100 This must be initialized on some systems to avoid linking in the 101 system's own getopt implementation. */ 102 103#define BAD_OPTION '\0' 104int optopt = BAD_OPTION; 105 106/* Describe how to deal with options that follow non-option ARGV-elements. 107 108 If the caller did not specify anything, 109 the default is REQUIRE_ORDER if the environment variable 110 POSIXLY_CORRECT is defined, PERMUTE otherwise. 111 112 REQUIRE_ORDER means don't recognize them as options; 113 stop option processing when the first non-option is seen. 114 This is what Unix does. 115 This mode of operation is selected by either setting the environment 116 variable POSIXLY_CORRECT, or using `+' as the first character 117 of the list of option characters. 118 119 PERMUTE is the default. We permute the contents of ARGV as we scan, 120 so that eventually all the non-options are at the end. This allows options 121 to be given in any order, even with programs that were not written to 122 expect this. 123 124 RETURN_IN_ORDER is an option available to programs that were written 125 to expect options and other ARGV-elements in any order and that care about 126 the ordering of the two. We describe each non-option ARGV-element 127 as if it were the argument of an option with character code 1. 128 Using `-' as the first character of the list of option characters 129 selects this mode of operation. 130 131 The special argument `--' forces an end of option-scanning regardless 132 of the value of `ordering'. In the case of RETURN_IN_ORDER, only 133 `--' can cause `getopt' to return EOF with `optind' != ARGC. */ 134 135static enum 136{ 137 REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER 138} ordering; 139 140/* Handle permutation of arguments. */ 141 142/* Describe the part of ARGV that contains non-options that have 143 been skipped. `first_nonopt' is the index in ARGV of the first of them; 144 `last_nonopt' is the index after the last of them. */ 145 146static int first_nonopt; 147static int last_nonopt; 148 149/* Exchange two adjacent subsequences of ARGV. 150 One subsequence is elements [first_nonopt,last_nonopt) 151 which contains all the non-options that have been skipped so far. 152 The other is elements [last_nonopt,optind), which contains all 153 the options processed since those non-options were skipped. 154 155 `first_nonopt' and `last_nonopt' are relocated so that they describe 156 the new indices of the non-options in ARGV after they are moved. 157 158 To perform the swap, we first reverse the order of all elements. So 159 all options now come before all non options, but they are in the 160 wrong order. So we put back the options and non options in original 161 order by reversing them again. For example: 162 original input: a b c -x -y 163 reverse all: -y -x c b a 164 reverse options: -x -y c b a 165 reverse non options: -x -y a b c 166*/ 167 168 169static void exchange (char **argv) 170{ 171 char *temp; char **first, **last; 172 173 /* Reverse all the elements [first_nonopt, optind) */ 174 first = &argv[first_nonopt]; 175 last = &argv[optind-1]; 176 while (first < last) { 177 temp = *first; *first = *last; *last = temp; first++; last--; 178 } 179 /* Put back the options in order */ 180 first = &argv[first_nonopt]; 181 first_nonopt += (optind - last_nonopt); 182 last = &argv[first_nonopt - 1]; 183 while (first < last) { 184 temp = *first; *first = *last; *last = temp; first++; last--; 185 } 186 187 /* Put back the non options in order */ 188 first = &argv[first_nonopt]; 189 last_nonopt = optind; 190 last = &argv[last_nonopt-1]; 191 while (first < last) { 192 temp = *first; *first = *last; *last = temp; first++; last--; 193 } 194} 195 196/* Scan elements of ARGV (whose length is ARGC) for option characters 197 given in OPTSTRING. 198 199 If an element of ARGV starts with '-', and is not exactly "-" or "--", 200 then it is an option element. The characters of this element 201 (aside from the initial '-') are option characters. If `getopt' 202 is called repeatedly, it returns successively each of the option characters 203 from each of the option elements. 204 205 If `getopt' finds another option character, it returns that character, 206 updating `optind' and `nextchar' so that the next call to `getopt' can 207 resume the scan with the following option character or ARGV-element. 208 209 If there are no more option characters, `getopt' returns `EOF'. 210 Then `optind' is the index in ARGV of the first ARGV-element 211 that is not an option. (The ARGV-elements have been permuted 212 so that those that are not options now come last.) 213 214 OPTSTRING is a string containing the legitimate option characters. 215 If an option character is seen that is not listed in OPTSTRING, 216 return BAD_OPTION after printing an error message. If you set `opterr' to 217 zero, the error message is suppressed but we still return BAD_OPTION. 218 219 If a char in OPTSTRING is followed by a colon, that means it wants an arg, 220 so the following text in the same ARGV-element, or the text of the following 221 ARGV-element, is returned in `optarg'. Two colons mean an option that 222 wants an optional arg; if there is text in the current ARGV-element, 223 it is returned in `optarg', otherwise `optarg' is set to zero. 224 225 If OPTSTRING starts with `-' or `+', it requests different methods of 226 handling the non-option ARGV-elements. 227 See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. 228 229 Long-named options begin with `--' instead of `-'. 230 Their names may be abbreviated as long as the abbreviation is unique 231 or is an exact match for some defined option. If they have an 232 argument, it follows the option name in the same ARGV-element, separated 233 from the option name by a `=', or else the in next ARGV-element. 234 When `getopt' finds a long-named option, it returns 0 if that option's 235 `flag' field is nonzero, the value of the option's `val' field 236 if the `flag' field is zero. 237 238 LONGOPTS is a vector of `struct option' terminated by an 239 element containing a name which is zero. 240 241 LONGIND returns the index in LONGOPT of the long-named option found. 242 It is only valid when a long-named option has been found by the most 243 recent call. 244 245 If LONG_ONLY is nonzero, '-' as well as '--' can introduce 246 long-named options. */ 247 248static int _getopt_internal (int argc, char **argv, const char *optstring, 249 const struct option *longopts, int *longind, 250 int long_only) 251{ 252 static char empty_string[1]; 253 int option_index; 254 255 if (longind != NULL) 256 *longind = -1; 257 258 optarg = 0; 259 260 /* Initialize the internal data when the first call is made. 261 Start processing options with ARGV-element 1 (since ARGV-element 0 262 is the program name); the sequence of previously skipped 263 non-option ARGV-elements is empty. */ 264 265 if (optind == 0) 266 { 267 first_nonopt = last_nonopt = optind = 1; 268 269 nextchar = NULL; 270 271 /* Determine how to handle the ordering of options and nonoptions. */ 272 273 if (optstring[0] == '-') 274 { 275 ordering = RETURN_IN_ORDER; 276 ++optstring; 277 } 278 else if (optstring[0] == '+') 279 { 280 ordering = REQUIRE_ORDER; 281 ++optstring; 282 } 283#if 0 284 else if (getenv ("POSIXLY_CORRECT") != NULL) 285 ordering = REQUIRE_ORDER; 286#endif 287 else 288 ordering = PERMUTE; 289 } 290 291 if (nextchar == NULL || *nextchar == '\0') 292 { 293 if (ordering == PERMUTE) 294 { 295 /* If we have just processed some options following some non-options, 296 exchange them so that the options come first. */ 297 298 if (first_nonopt != last_nonopt && last_nonopt != optind) 299 exchange (argv); 300 else if (last_nonopt != optind) 301 first_nonopt = optind; 302 303 /* Now skip any additional non-options 304 and extend the range of non-options previously skipped. */ 305 306 while (optind < argc 307 && (argv[optind][0] != '-' || argv[optind][1] == '\0') 308#ifdef GETOPT_COMPAT 309 && (longopts == NULL 310 || argv[optind][0] != '+' || argv[optind][1] == '\0') 311#endif /* GETOPT_COMPAT */ 312 ) 313 optind++; 314 last_nonopt = optind; 315 } 316 317 /* Special ARGV-element `--' means premature end of options. 318 Skip it like a null option, 319 then exchange with previous non-options as if it were an option, 320 then skip everything else like a non-option. */ 321 322 if (optind != argc && !strcmp (argv[optind], "--")) 323 { 324 optind++; 325 326 if (first_nonopt != last_nonopt && last_nonopt != optind) 327 exchange (argv); 328 else if (first_nonopt == last_nonopt) 329 first_nonopt = optind; 330 last_nonopt = argc; 331 332 optind = argc; 333 } 334 335 /* If we have done all the ARGV-elements, stop the scan 336 and back over any non-options that we skipped and permuted. */ 337 338 if (optind == argc) 339 { 340 /* Set the next-arg-index to point at the non-options 341 that we previously skipped, so the caller will digest them. */ 342 if (first_nonopt != last_nonopt) 343 optind = first_nonopt; 344 return EOF; 345 } 346 347 /* If we have come to a non-option and did not permute it, 348 either stop the scan or describe it to the caller and pass it by. */ 349 350 if ((argv[optind][0] != '-' || argv[optind][1] == '\0') 351#ifdef GETOPT_COMPAT 352 && (longopts == NULL 353 || argv[optind][0] != '+' || argv[optind][1] == '\0') 354#endif /* GETOPT_COMPAT */ 355 ) 356 { 357 if (ordering == REQUIRE_ORDER) 358 return EOF; 359 optarg = argv[optind++]; 360 return 1; 361 } 362 363 /* We have found another option-ARGV-element. 364 Start decoding its characters. */ 365 366 nextchar = (argv[optind] + 1 367 + (longopts != NULL && argv[optind][1] == '-')); 368 } 369 370 if (longopts != NULL 371 && ((argv[optind][0] == '-' 372 && (argv[optind][1] == '-' || long_only)) 373#ifdef GETOPT_COMPAT 374 || argv[optind][0] == '+' 375#endif /* GETOPT_COMPAT */ 376 )) 377 { 378 const struct option *p; 379 char *s = nextchar; 380 int exact = 0; 381 int ambig = 0; 382 const struct option *pfound = NULL; 383 int indfound = 0; 384 int needexact = 0; 385 386 /* allow `--option#value' because you cannout assign a '=' 387 to an environment variable under DOS command.com */ 388 while (*s && *s != '=' && * s != '#') 389 s++; 390 391 /* Test all options for either exact match or abbreviated matches. */ 392 for (p = longopts, option_index = 0; p->name; 393 p++, option_index++) 394 if (!strncmp (p->name, nextchar, (unsigned) (s - nextchar))) 395 { 396 if (p->has_arg & 0x10) 397 needexact = 1; 398 if ((unsigned) (s - nextchar) == strlen (p->name)) 399 { 400 /* Exact match found. */ 401 pfound = p; 402 indfound = option_index; 403 exact = 1; 404 break; 405 } 406 else if (pfound == NULL) 407 { 408 /* First nonexact match found. */ 409 pfound = p; 410 indfound = option_index; 411 } 412 else 413 /* Second nonexact match found. */ 414 ambig = 1; 415 } 416 417 /* don't allow nonexact longoptions */ 418 if (needexact && !exact) 419 { 420 if (opterr) 421 fprintf (stderr, "%s: unrecognized option `%s'\n", 422 PROGNAME(argv[0]), argv[optind]); 423 nextchar += strlen (nextchar); 424 optind++; 425 return BAD_OPTION; 426 } 427 if (ambig && !exact) 428 { 429 if (opterr) 430 fprintf (stderr, "%s: option `%s' is ambiguous\n", 431 PROGNAME(argv[0]), argv[optind]); 432 nextchar += strlen (nextchar); 433 optind++; 434 return BAD_OPTION; 435 } 436 437 if (pfound != NULL) 438 { 439 int have_arg = (s[0] != '\0'); 440 if (have_arg && (pfound->has_arg & 0xf)) 441 have_arg = (s[1] != '\0'); 442 option_index = indfound; 443 optind++; 444 if (have_arg) 445 { 446 /* Don't test has_arg with >, because some C compilers don't 447 allow it to be used on enums. */ 448 if (pfound->has_arg & 0xf) 449 optarg = s + 1; 450 else 451 { 452 if (opterr) 453 { 454 if (argv[optind - 1][1] == '-') 455 /* --option */ 456 fprintf (stderr, 457 "%s: option `--%s' doesn't allow an argument\n", 458 PROGNAME(argv[0]), pfound->name); 459 else 460 /* +option or -option */ 461 fprintf (stderr, 462 "%s: option `%c%s' doesn't allow an argument\n", 463 PROGNAME(argv[0]), argv[optind - 1][0], pfound->name); 464 } 465 nextchar += strlen (nextchar); 466 return BAD_OPTION; 467 } 468 } 469 else if ((pfound->has_arg & 0xf) == 1) 470 { 471#if 0 472 if (optind < argc) 473#else 474 if (optind < argc && (pfound->has_arg & 0x20) == 0) 475#endif 476 optarg = argv[optind++]; 477 else 478 { 479 if (opterr) 480 fprintf (stderr, "%s: option `--%s%s' requires an argument\n", 481 PROGNAME(argv[0]), pfound->name, 482 (pfound->has_arg & 0x20) ? "=" : ""); 483 nextchar += strlen (nextchar); 484 return optstring[0] == ':' ? ':' : BAD_OPTION; 485 } 486 } 487 nextchar += strlen (nextchar); 488 if (longind != NULL) 489 *longind = option_index; 490 if (pfound->flag) 491 { 492 *(pfound->flag) = pfound->val; 493 return 0; 494 } 495 return pfound->val; 496 } 497 /* Can't find it as a long option. If this is not getopt_long_only, 498 or the option starts with '--' or is not a valid short 499 option, then it's an error. 500 Otherwise interpret it as a short option. */ 501 if (!long_only || argv[optind][1] == '-' 502#ifdef GETOPT_COMPAT 503 || argv[optind][0] == '+' 504#endif /* GETOPT_COMPAT */ 505 || strchr (optstring, *nextchar) == NULL) 506 { 507 if (opterr) 508 { 509 if (argv[optind][1] == '-') 510 /* --option */ 511 fprintf (stderr, "%s: unrecognized option `--%s'\n", 512 PROGNAME(argv[0]), nextchar); 513 else 514 /* +option or -option */ 515 fprintf (stderr, "%s: unrecognized option `%c%s'\n", 516 PROGNAME(argv[0]), argv[optind][0], nextchar); 517 } 518 nextchar = empty_string; 519 optind++; 520 return BAD_OPTION; 521 } 522 (void) &ambig; /* UNUSED */ 523 } 524 525 /* Look at and handle the next option-character. */ 526 527 { 528 char c = *nextchar++; 529 const char *temp = strchr (optstring, c); 530 531 /* Increment `optind' when we start to process its last character. */ 532 if (*nextchar == '\0') 533 ++optind; 534 535 if (temp == NULL || c == ':') 536 { 537 if (opterr) 538 { 539#if 0 540 if (c < 040 || c >= 0177) 541 fprintf (stderr, "%s: unrecognized option, character code 0%o\n", 542 PROGNAME(argv[0]), c); 543 else 544 fprintf (stderr, "%s: unrecognized option `-%c'\n", PROGNAME(argv[0]), c); 545#else 546 /* 1003.2 specifies the format of this message. */ 547 fprintf (stderr, "%s: illegal option -- %c\n", PROGNAME(argv[0]), c); 548#endif 549 } 550 optopt = c; 551 return BAD_OPTION; 552 } 553 if (temp[1] == ':') 554 { 555 if (temp[2] == ':') 556 { 557 /* This is an option that accepts an argument optionally. */ 558 if (*nextchar != '\0') 559 { 560 optarg = nextchar; 561 optind++; 562 } 563 else 564 optarg = 0; 565 nextchar = NULL; 566 } 567 else 568 { 569 /* This is an option that requires an argument. */ 570 if (*nextchar != '\0') 571 { 572 optarg = nextchar; 573 /* If we end this ARGV-element by taking the rest as an arg, 574 we must advance to the next element now. */ 575 optind++; 576 } 577 else if (optind == argc) 578 { 579 if (opterr) 580 { 581#if 0 582 fprintf (stderr, "%s: option `-%c' requires an argument\n", 583 PROGNAME(argv[0]), c); 584#else 585 /* 1003.2 specifies the format of this message. */ 586 fprintf (stderr, "%s: option requires an argument -- %c\n", 587 PROGNAME(argv[0]), c); 588#endif 589 } 590 optopt = c; 591 if (optstring[0] == ':') 592 c = ':'; 593 else 594 c = BAD_OPTION; 595 } 596 else 597 /* We already incremented `optind' once; 598 increment it again when taking next ARGV-elt as argument. */ 599 optarg = argv[optind++]; 600 nextchar = NULL; 601 } 602 } 603 return c; 604 } 605} 606 607int mfx_getopt(int argc, char **argv, const char *optstring) 608{ 609 return _getopt_internal (argc, argv, optstring, 610 (const struct option *) 0, 611 (int *) 0, 612 0); 613} 614 615int mfx_getopt_long(int argc, char **argv, const char *options, 616 const struct option *long_options, int *opt_index) 617{ 618 return _getopt_internal (argc, argv, options, long_options, opt_index, 0); 619} 620 621 622#ifdef TEST 623 624/* Compile with -DTEST to make an executable for use in testing 625 the above definition of `getopt'. */ 626 627int 628main (argc, argv) 629 int argc; 630 char **argv; 631{ 632 int c; 633 int digit_optind = 0; 634 635 while (1) 636 { 637 int this_option_optind = optind ? optind : 1; 638 639 c = getopt (argc, argv, "abc:d:0123456789"); 640 if (c == EOF) 641 break; 642 643 switch (c) 644 { 645 case '0': 646 case '1': 647 case '2': 648 case '3': 649 case '4': 650 case '5': 651 case '6': 652 case '7': 653 case '8': 654 case '9': 655 if (digit_optind != 0 && digit_optind != this_option_optind) 656 printf ("digits occur in two different argv-elements.\n"); 657 digit_optind = this_option_optind; 658 printf ("option %c\n", c); 659 break; 660 661 case 'a': 662 printf ("option a\n"); 663 break; 664 665 case 'b': 666 printf ("option b\n"); 667 break; 668 669 case 'c': 670 printf ("option c with value `%s'\n", optarg); 671 break; 672 673 case BAD_OPTION: 674 break; 675 676 default: 677 printf ("?? getopt returned character code 0%o ??\n", c); 678 } 679 } 680 681 if (optind < argc) 682 { 683 printf ("non-option ARGV-elements: "); 684 while (optind < argc) 685 printf ("%s ", argv[optind++]); 686 printf ("\n"); 687 } 688 689 exit (0); 690} 691 692#endif /* TEST */ 693 694 695/* 696vi:ts=4:et:nowrap 697*/ 698 699