Exemple #1
0
// 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 the option characters from each of
// the option elements.
//
// If `getopt' finds another option character, it returns that character, updating `woptind' 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 `woptind' 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. If an option character is seen
// that is not listed in OPTSTRING, return '?' after printing an error message.  If you set
// `wopterr' 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 `w.woptarg', otherwise `w.woptarg' is set to zero.
//
// If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option
// ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
//
// Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the
// abbreviation is unique or is an exact match for some defined option.  If they have an argument,
// it follows the option name in the same ARGV-element, separated from the option name by a `=', or
// else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that
// option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is
// zero.
//
// LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero.
//
// LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a
// long-named option has been found by the most recent call.
//
// If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options.
int wgetopter_t::_wgetopt_internal(int argc, wchar_t **argv, const wchar_t *optstring,
                                   const struct woption *longopts, int *longind, int long_only) {
    if (!initialized) _wgetopt_initialize(optstring);
    woptarg = NULL;

    if (nextchar == NULL || *nextchar == '\0') {
        int retval = _advance_to_next_argv(argc, argv, longopts);
        if (retval != 0) return retval;
    }

    // Decode the current option-ARGV-element.

    // Check whether the ARGV-element is a long option.
    //
    // If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't
    // consider it an abbreviated form of a long option that starts with f.  Otherwise there would
    // be no way to give the -f short option.
    //
    // On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do
    // consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg
    // "u".
    //
    // This distinction seems to be the most useful approach.
    if (longopts != NULL &&
        (argv[woptind][1] == '-' ||
         (long_only && (argv[woptind][2] || !wcschr(shortopts, argv[woptind][1]))))) {
        int retval;
        if (_handle_long_opt(argc, argv, longopts, longind, long_only, &retval)) return retval;
    }

    return _handle_short_opt(argc, argv);
}
// 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 the option characters from each of
// the option elements.
//
// If `getopt' finds another option character, it returns that character, updating `woptind' 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 `woptind' 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. If an option character is seen
// that is not listed in OPTSTRING, return '?' after printing an error message.  If you set
// `wopterr' 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 `w.woptarg', otherwise `w.woptarg' is set to zero.
//
// If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option
// ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
//
// Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the
// abbreviation is unique or is an exact match for some defined option.  If they have an argument,
// it follows the option name in the same ARGV-element, separated from the option name by a `=', or
// else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that
// option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is
// zero.
//
// LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero.
//
// LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a
// long-named option has been found by the most recent call.
//
// If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options.
int wgetopter_t::_wgetopt_internal(int argc, wchar_t **argv, const wchar_t *optstring,
                                   const struct woption *longopts, int *longind, int long_only) {
    woptarg = NULL;

    if (woptind == 0) optstring = _wgetopt_initialize(optstring);

    if (nextchar == NULL || *nextchar == '\0') {
        // Advance to the next ARGV-element.
        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 != woptind)
                exchange(argv);
            else if (last_nonopt != woptind)
                first_nonopt = woptind;

            // Skip any additional non-options and extend the range of non-options previously
            // skipped.
            while (woptind < argc && (argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
                woptind++;
            last_nonopt = woptind;
        }

        // The 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 (woptind != argc && !wcscmp(argv[woptind], L"--")) {
            woptind++;

            if (first_nonopt != last_nonopt && last_nonopt != woptind)
                exchange(argv);
            else if (first_nonopt == last_nonopt)
                first_nonopt = woptind;
            last_nonopt = argc;

            woptind = argc;
        }

        // If we have done all the ARGV-elements, stop the scan and back over any non-options that
        // we skipped and permuted.

        if (woptind == 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) woptind = 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 ((argv[woptind][0] != '-' || argv[woptind][1] == '\0')) {
            if (ordering == REQUIRE_ORDER) return EOF;
            woptarg = argv[woptind++];
            return 1;
        }

        // We have found another option-ARGV-element. Skip the initial punctuation.
        nextchar = (argv[woptind] + 1 + (longopts != NULL && argv[woptind][1] == '-'));
    }

    // Decode the current option-ARGV-element.

    // Check whether the ARGV-element is a long option.
    //
    // If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't
    // consider it an abbreviated form of a long option that starts with f.  Otherwise there would
    // be no way to give the -f short option.
    //
    // On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do
    // consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg
    // "u".
    //
    // This distinction seems to be the most useful approach.
    if (longopts != NULL &&
            (argv[woptind][1] == '-' ||
             (long_only && (argv[woptind][2] || !my_index(optstring, argv[woptind][1]))))) {
        wchar_t *nameend;
        const struct woption *p;
        const struct woption *pfound = NULL;
        int exact = 0;
        int ambig = 0;
        int indfound = 0;  // set to zero by Anton
        int option_index;

        for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
            ;  //!OCLINT(empty body)

        // Test all long options for either exact match or abbreviated matches.
        for (p = longopts, option_index = 0; p->name; p++, option_index++)
            if (!wcsncmp(p->name, nextchar, nameend - nextchar)) {
                if ((unsigned int)(nameend - nextchar) == (unsigned int)wcslen(p->name)) {
                    // Exact match found.
                    pfound = p;
                    indfound = option_index;
                    exact = 1;
                    break;
                } else if (pfound == NULL) {
                    // First nonexact match found.
                    pfound = p;
                    indfound = option_index;
                } else
                    // Second or later nonexact match found.
                    ambig = 1;
            }

        if (ambig && !exact) {
            if (wopterr)
                fwprintf(stderr, _(L"%ls: Option '%ls' is ambiguous\n"), argv[0], argv[woptind]);
            nextchar += wcslen(nextchar);
            woptind++;
            return '?';
        }

        if (pfound != NULL) {
            option_index = indfound;
            woptind++;
            if (*nameend) {
                // Don't test has_arg with >, because some C compilers don't allow it to be used on
                // enums.
                if (pfound->has_arg)
                    woptarg = nameend + 1;
                else {
                    if (wopterr) {
                        if (argv[woptind - 1][1] == '-')  // --option
                            fwprintf(stderr, _(L"%ls: Option '--%ls' doesn't allow an argument\n"),
                                     argv[0], pfound->name);
                        else
                            // +option or -option
                            fwprintf(stderr, _(L"%ls: Option '%lc%ls' doesn't allow an argument\n"),
                                     argv[0], argv[woptind - 1][0], pfound->name);
                    }
                    nextchar += wcslen(nextchar);
                    return '?';
                }
            } else if (pfound->has_arg == 1) {
                if (woptind < argc)
                    woptarg = argv[woptind++];
                else {
                    if (wopterr)
                        fwprintf(stderr, _(L"%ls: Option '%ls' requires an argument\n"), argv[0],
                                 argv[woptind - 1]);
                    nextchar += wcslen(nextchar);
                    return optstring[0] == ':' ? ':' : '?';
                }
            }
            nextchar += wcslen(nextchar);
            if (longind != NULL) *longind = option_index;
            if (pfound->flag) {
                *(pfound->flag) = pfound->val;
                return 0;
            }
            return pfound->val;
        }

        // Can't find it as a long option.  If this is not getopt_long_only, or the option starts
        // with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a
        // short option.
        if (!long_only || argv[woptind][1] == '-' || my_index(optstring, *nextchar) == NULL) {
            if (wopterr) {
                if (argv[woptind][1] == '-')  // --option
                    fwprintf(stderr, _(L"%ls: Unrecognized option '--%ls'\n"), argv[0], nextchar);
                else
                    // +option or -option
                    fwprintf(stderr, _(L"%ls: Unrecognized option '%lc%ls'\n"), argv[0],
                             argv[woptind][0], nextchar);
            }
            nextchar = (wchar_t *)L"";
            woptind++;
            return '?';
        }
    }

    // Look at and handle the next short option-character.
    {
        wchar_t c = *nextchar++;
        wchar_t *temp = const_cast<wchar_t *>(my_index(optstring, c));

        // Increment `woptind' when we start to process its last character.
        if (*nextchar == '\0') ++woptind;

        if (temp == NULL || c == ':') {
            if (wopterr) {
                fwprintf(stderr, _(L"%ls: Invalid option -- %lc\n"), argv[0], (wint_t)c);
            }
            woptopt = c;

            if (*nextchar != '\0') woptind++;

            return '?';
        }
        if (temp[1] == ':') {
            if (temp[2] == ':') {
                // This is an option that accepts an argument optionally.
                if (*nextchar != '\0') {
                    woptarg = nextchar;
                    woptind++;
                } else
                    woptarg = NULL;
                nextchar = NULL;
            } else {
                // This is an option that requires an argument.
                if (*nextchar != '\0') {
                    woptarg = nextchar;
                    // If we end this ARGV-element by taking the rest as an arg, we must advance to
                    // the next element now.
                    woptind++;
                } else if (woptind == argc) {
                    if (wopterr) {
                        // 1003.2 specifies the format of this message.
                        fwprintf(stderr, _(L"%ls: Option requires an argument -- %lc\n"), argv[0],
                                 (wint_t)c);
                    }
                    woptopt = c;
                    if (optstring[0] == ':')
                        c = ':';
                    else
                        c = '?';
                } else
                    // We already incremented `woptind' once; increment it again when taking next
                    // ARGV-elt as argument.
                    woptarg = argv[woptind++];
                nextchar = NULL;
            }
        }
        return c;
    }
}