home *** CD-ROM | disk | FTP | other *** search
- /*
- * GNU getopt, hacked for MSDOS and Microsoft C 5.1 and QuickC.
- *
- * Barry Schwartz, Dec. 1989
- *
- * New compile-time defs:
- * MSDOS Defined by Microsoft compilers
- * MSDOS_FLAGS Allow "/" as a synonym for "-"
- * and "/-" as a synonym for "--"
- * PROTO ANSI-style parameters
- */
-
- #define PROTO
- /*#define MSDOS_FLAGS*/
-
- /*
- * This version of `getopt' appears to the caller like standard Unix
- * `getopt' but it behaves differently for the user, since it allows the
- * user to intersperse the options with the other arguments.
- *
- * As `getopt' works, it permutes the elements of `argv' so that, when it is
- * done, all the options precede everything else. Thus all application
- * programs are extended to handle flexible argument order.
- *
- * Setting the environment variable _POSIX_OPTION_ORDER disables permutation.
- * Then the behavior is completely standard.
- *
- * GNU application programs can use a third alternative mode in which they
- * can distinguish the relative order of options and other arguments.
- */
-
- #include <stdio.h>
- #if defined(MSDOS)
- #include <malloc.h>
- #include <string.h>
- extern char *getenv(char *);
- #endif
-
- #if defined(sparc)
- #include <alloca.h>
- #endif
- #if defined(USG) || defined(MSDOS)
- #define bcopy(s, d, l) memcpy((d), (s), (l))
- #define index strchr
- #endif
-
- /*
- * For communication from `getopt' to the caller. When `getopt' finds an
- * option that takes an argument, the argument value is returned here.
- * Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element
- * is returned here.
- */
-
- char *optarg = 0;
-
- /*
- * Index in ARGV of the next element to be scanned. This is used for
- * communication to and from the caller and for communication between
- * successive calls to `getopt'.
- *
- * On entry to `getopt', zero means this is the first call; initialize.
- *
- * When `getopt' returns EOF, this is the index of the first of the
- * non-option elements that the caller should itself scan.
- *
- * Otherwise, `optind' communicates from one call to the next how much of
- * ARGV has been scanned so far.
- */
-
- int optind = 0;
-
- /*
- * The next char to be scanned in the option-element in which the last
- * option character we returned was found. This allows us to pick up the
- * scan where we left off.
- *
- * If this is zero, or a null string, it means resume the scan by advancing
- * to the next ARGV-element.
- */
-
- static char *nextchar;
-
- /*
- * Callers store zero here to inhibit the error message for unrecognized
- * options.
- */
-
- int opterr = 1;
-
- /*
- * Describe how to deal with options that follow non-option ARGV-elements.
- *
- * UNSPECIFIED means the caller did not specify anything; the default is then
- * REQUIRE_ORDER if the environment variable _OPTIONS_FIRST is defined,
- * PERMUTE otherwise.
- *
- * REQUIRE_ORDER means don't recognize them as options. Stop option
- * processing when the first non-option is seen. This is what Unix does.
- *
- * PERMUTE is the default. We permute the contents of `argv' as we scan, so
- * that eventually all the options are at the end. This allows options to
- * be given in any order, even with programs that were not written to
- * expect this.
- *
- * RETURN_IN_ORDER is an option available to programs that were written to
- * expect options and other ARGV-elements in any order and that care about
- * the ordering of the two. We describe each non-option ARGV-element as
- * if it were the argument of an option with character code zero. Using
- * `-' as the first character of the list of option characters requests
- * this mode of operation.
- *
- * The special argument `--' forces an end of option-scanning regardless of
- * the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can
- * cause `getopt' to return EOF with `optind' != ARGC.
- */
-
- static enum
- {
- REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
- } ordering;
-
-
- /* Handle permutation of arguments. */
-
- /*
- * Describe the part of ARGV that contains non-options that have been
- * skipped. `first_nonopt' is the index in ARGV of the first of them;
- * `last_nonopt' is the index after the last of them.
- */
-
- static int first_nonopt;
- static int last_nonopt;
-
- /*
- * Exchange two adjacent subsequences of ARGV. One subsequence is elements
- * [first_nonopt,last_nonopt) which contains all the non-options that have
- * been skipped so far. The other is elements [last_nonopt,optind), which
- * contains all the options processed since those non-options were
- * skipped.
- *
- * `first_nonopt' and `last_nonopt' are relocated so that they describe the
- * new indices of the non-options in ARGV after they are moved.
- */
-
- #if defined(PROTO)
-
- static void
- exchange(char **argv)
-
- #else
-
- static void
- exchange(argv)
- char **argv;
-
- #endif
- {
- int nonopts_size
- = (last_nonopt - first_nonopt) * sizeof(char *);
- char **temp = (char **) alloca(nonopts_size);
-
- /* Interchange the two blocks of data in argv. */
-
- bcopy(&argv[first_nonopt], temp, nonopts_size);
- bcopy(&argv[last_nonopt], &argv[first_nonopt],
- (optind - last_nonopt) * sizeof(char *));
- bcopy(temp, &argv[first_nonopt + optind - last_nonopt],
- nonopts_size);
-
- /* Update records for the slots the non-options now occupy. */
-
- first_nonopt += (optind - last_nonopt);
- last_nonopt = optind;
- }
-
-
- /*
- * Scan elements of ARGV (whose length is ARGC) for option characters
- * given in OPTSTRING.
- *
- * If an element of ARGV starts with '-', and is not exactly "-" or "--",
- * then it is an option element. The characters of this element (aside
- * from the initial '-') are option characters. If `getopt' is called
- * repeatedly, it returns successively each of theoption characters from
- * each of the option elements.
- *
- * If `getopt' finds another option character, it returns that character,
- * updating `optind' and `nextchar' so that the next call to `getopt' can
- * resume the scan with the following option character or ARGV-element.
- *
- * If there are no more option characters, `getopt' returns `EOF'. Then
- * `optind' is the index in ARGV of the first ARGV-element that is not an
- * option. (The ARGV-elements have been permuted so that those that are
- * not options now come last.)
- *
- * OPTSTRING is a string containing the legitimate option characters. A colon
- * in OPTSTRING means that the previous character is an option that wants
- * an argument. The argument is taken from the rest of the current
- * ARGV-element, or from the following ARGV-element, and returned in
- * `optarg'.
- *
- * If an option character is seen that is not listed in OPTSTRING, return '?'
- * after printing an error message. If you set `opterr' to zero, the
- * error message is suppressed but we still return '?'.
- *
- * If a char in OPTSTRING is followed by a colon, that means it wants an arg,
- * so the following text in the same ARGV-element, or the text of the
- * following ARGV-element, is returned in `optarg. Two colons mean an
- * option that wants an optional arg; if there is text in the current
- * ARGV-element, it is returned in `optarg'.
- *
- * If OPTSTRING starts with `-', it requests a different method of handling
- * the non-option ARGV-elements. See the comments about RETURN_IN_ORDER,
- * above.
- */
-
- #if defined(PROTO)
-
- int
- getopt(int argc, char **argv, char *optstring)
-
- #else
-
- int
- getopt(argc, argv, optstring)
- int argc;
- char **argv;
- char *optstring;
-
- #endif
- {
- /*
- * Initialize the internal data when the first call is made. Start
- * processing options with ARGV-element 1 (since ARGV-element 0 is the
- * program name); the sequence of previously skipped non-option
- * ARGV-elements is empty.
- */
-
- if (optind == 0)
- {
- first_nonopt = last_nonopt = optind = 1;
-
- nextchar = 0;
-
- /*
- * Determine how to handle the ordering of options and nonoptions.
- */
-
- if (optstring[0] == '-')
- ordering = RETURN_IN_ORDER;
- else
- if (getenv("_POSIX_OPTION_ORDER") != 0)
- ordering = REQUIRE_ORDER;
- else
- ordering = PERMUTE;
- }
-
- if (nextchar == 0 || *nextchar == 0)
- {
- if (ordering == PERMUTE)
- {
- /*
- * If we have just processed some options following some
- * non-options, exchange them so that the options come first.
- */
-
- if (first_nonopt != last_nonopt && last_nonopt != optind)
- exchange(argv);
- else
- if (last_nonopt != optind)
- first_nonopt = optind;
-
- /*
- * Now skip any additional non-options and extend the range of
- * non-options previously skipped.
- */
-
- while (optind < argc
- #if !defined(MSDOS_FLAGS)
- && (argv[optind][0] != '-'
- #else
- && ((argv[optind][0] != '-' && argv[optind][0] != '/')
- #endif
- || argv[optind][1] == 0))
- optind++;
- last_nonopt = optind;
- }
-
- /*
- * Special ARGV-element `--' means premature end of options. Skip
- * it like a null option, then exchange with previous non-options
- * as if it were an option, then skip everything else like a
- * non-option.
- */
-
- #if !defined(MSDOS_FLAGS)
- if (optind != argc && !strcmp(argv[optind], "--"))
- #else
- if (optind != argc &&
- !(strcmp(argv[optind], "--") && strcmp(argv[optind], "/-")))
- #endif
- {
- optind++;
-
- if (first_nonopt != last_nonopt && last_nonopt != optind)
- exchange(argv);
- else
- if (first_nonopt == last_nonopt)
- first_nonopt = optind;
- last_nonopt = argc;
-
- optind = argc;
- }
-
- /*
- * If we have done all the ARGV-elements, stop the scan and back
- * over any non-options that we skipped and permuted.
- */
-
- if (optind == argc)
- {
- /*
- * Set the next-arg-index to point at the non-options that we
- * previously skipped, so the caller will digest them.
- */
- if (first_nonopt != last_nonopt)
- optind = first_nonopt;
- return EOF;
- }
-
- /*
- * If we have come to a non-option and did not permute it, either
- * stop the scan or describe it to the caller and pass it by.
- */
-
- #if !defined(MSDOS_FLAGS)
- if (argv[optind][0] != '-' || argv[optind][1] == 0)
- #else
- if ((argv[optind][0] != '-' && argv[optind][0] != '/')
- || argv[optind][1] == 0)
- #endif
- {
- if (ordering == REQUIRE_ORDER)
- return EOF;
- optarg = argv[optind++];
- return 0;
- }
-
- /*
- * We have found another option-ARGV-element. Start decoding its
- * characters.
- */
-
- nextchar = argv[optind] + 1;
- }
-
- /* Look at and handle the next option-character. */
-
- {
- char c = *nextchar++;
- char *temp = (char *) index(optstring, c);
-
- /*
- * Increment `optind' when we start to process its last character.
- */
- if (*nextchar == 0)
- optind++;
-
- if (temp == 0 || c == ':')
- {
- if (opterr != 0)
- {
- if (c < 040 || c >= 0177)
- fprintf(stderr, "\n%s: unrecognized option, character code 0%o\n",
- argv[0], c);
- else
- fprintf(stderr, "\n%s: unrecognized option `-%c'\n",
- argv[0], c);
- }
- return '?';
- }
- if (temp[1] == ':')
- {
- if (temp[2] == ':')
- {
- /*
- * This is an option that accepts an argument optionally.
- */
- if (*nextchar != 0)
- {
- optarg = nextchar;
- optind++;
- }
- else
- optarg = 0;
- nextchar = 0;
- }
- else
- {
- /*
- * This is an option that requires an argument.
- */
- if (*nextchar != 0)
- {
- optarg = nextchar;
- /*
- * If we end this ARGV-element by taking the rest as
- * an arg, we must advance to the next element now.
- */
- optind++;
- }
- else
- if (optind == argc)
- {
- if (opterr != 0)
- fprintf(stderr, "\n%s: no argument for `-%c' option\n",
- argv[0], c);
- c = '?';
- }
- else
- /*
- * We already incremented `optind' once; increment it
- * again when taking next ARGV-elt as argument.
- */
- optarg = argv[optind++];
- nextchar = 0;
- }
- }
- return c;
- }
- }
-
-
- #if defined(TEST)
-
- /*
- * Compile with -DTEST to make an executable for use in testing the above
- * definition of `getopt'.
- */
-
- int
- main(argc, argv)
- int argc;
- char **argv;
- {
- char c;
- int digit_optind = 0;
-
- while (1)
- {
- int this_option_optind = optind;
- if ((c = getopt(argc, argv, "abc:d:0123456789")) == EOF)
- break;
-
- switch (c)
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (digit_optind != 0 && digit_optind != this_option_optind)
- printf("digits occur in two different argv-elements.\n");
- digit_optind = this_option_optind;
- printf("option %c\n", c);
- break;
-
- case 'a':
- printf("option a\n");
- break;
-
- case 'b':
- printf("option b\n");
- break;
-
- case 'c':
- printf("option c with value `%s'\n", optarg);
- break;
-
- case '?':
- break;
-
- default:
- printf("?? getopt returned character code 0%o ??\n", c);
- }
- }
-
- if (optind < argc)
- {
- printf("non-option ARGV-elements: ");
- while (optind < argc)
- printf("%s ", argv[optind++]);
- printf("\n");
- }
-
- return 0;
- }
-
- #endif
-