bool _parse_arg()

in fboss/cli/fboss2/CLI11/App.hpp [2600:2742]


    bool _parse_arg(std::vector<std::string> &args, detail::Classifier current_type) {

        std::string current = args.back();

        std::string arg_name;
        std::string value;
        std::string rest;

        switch(current_type) {
        case detail::Classifier::LONG:
            if(!detail::split_long(current, arg_name, value))
                throw HorribleError("Long parsed but missing (you should not see this):" + args.back());
            break;
        case detail::Classifier::SHORT:
            if(!detail::split_short(current, arg_name, rest))
                throw HorribleError("Short parsed but missing! You should not see this");
            break;
        case detail::Classifier::WINDOWS:
            if(!detail::split_windows_style(current, arg_name, value))
                throw HorribleError("windows option parsed but missing! You should not see this");
            break;
        case detail::Classifier::SUBCOMMAND:
        case detail::Classifier::SUBCOMMAND_TERMINATOR:
        case detail::Classifier::POSITIONAL_MARK:
        case detail::Classifier::NONE:
        default:
            throw HorribleError("parsing got called with invalid option! You should not see this");
        }

        auto op_ptr =
            std::find_if(std::begin(options_), std::end(options_), [arg_name, current_type](const Option_p &opt) {
                if(current_type == detail::Classifier::LONG)
                    return opt->check_lname(arg_name);
                if(current_type == detail::Classifier::SHORT)
                    return opt->check_sname(arg_name);
                // this will only get called for detail::Classifier::WINDOWS
                return opt->check_lname(arg_name) || opt->check_sname(arg_name);
            });

        // Option not found
        if(op_ptr == std::end(options_)) {
            for(auto &subc : subcommands_) {
                if(subc->name_.empty() && !subc->disabled_) {
                    if(subc->_parse_arg(args, current_type)) {
                        if(!subc->pre_parse_called_) {
                            subc->_trigger_pre_parse(args.size());
                        }
                        return true;
                    }
                }
            }
            // If a subcommand, try the master command
            if(parent_ != nullptr && fallthrough_)
                return _get_fallthrough_parent()->_parse_arg(args, current_type);
            // don't capture missing if this is a nameless subcommand
            if(parent_ != nullptr && name_.empty()) {
                return false;
            }
            // Otherwise, add to missing
            args.pop_back();
            _move_to_missing(current_type, current);
            return true;
        }

        args.pop_back();

        // Get a reference to the pointer to make syntax bearable
        Option_p &op = *op_ptr;

        int min_num = (std::min)(op->get_type_size_min(), op->get_items_expected_min());
        int max_num = op->get_items_expected_max();

        // Make sure we always eat the minimum for unlimited vectors
        int collected = 0;     // total number of arguments collected
        int result_count = 0;  // local variable for number of results in a single arg string
        // deal with purely flag like things
        if(max_num == 0) {
            auto res = op->get_flag_value(arg_name, value);
            op->add_result(res);
            parse_order_.push_back(op.get());
        } else if(!value.empty()) {  // --this=value
            op->add_result(value, result_count);
            parse_order_.push_back(op.get());
            collected += result_count;
            // -Trest
        } else if(!rest.empty()) {
            op->add_result(rest, result_count);
            parse_order_.push_back(op.get());
            rest = "";
            collected += result_count;
        }

        // gather the minimum number of arguments
        while(min_num > collected && !args.empty()) {
            std::string current_ = args.back();
            args.pop_back();
            op->add_result(current_, result_count);
            parse_order_.push_back(op.get());
            collected += result_count;
        }

        if(min_num > collected) {  // if we have run out of arguments and the minimum was not met
            throw ArgumentMismatch::TypedAtLeast(op->get_name(), min_num, op->get_type_name());
        }

        if(max_num > collected || op->get_allow_extra_args()) {  // we allow optional arguments
            auto remreqpos = _count_remaining_positionals(true);
            // we have met the minimum now optionally check up to the maximum
            while((collected < max_num || op->get_allow_extra_args()) && !args.empty() &&
                  _recognize(args.back(), false) == detail::Classifier::NONE) {
                // If any required positionals remain, don't keep eating
                if(remreqpos >= args.size()) {
                    break;
                }

                op->add_result(args.back(), result_count);
                parse_order_.push_back(op.get());
                args.pop_back();
                collected += result_count;
            }

            // Allow -- to end an unlimited list and "eat" it
            if(!args.empty() && _recognize(args.back()) == detail::Classifier::POSITIONAL_MARK)
                args.pop_back();
            // optional flag that didn't receive anything now get the default value
            if(min_num == 0 && max_num > 0 && collected == 0) {
                auto res = op->get_flag_value(arg_name, std::string{});
                op->add_result(res);
                parse_order_.push_back(op.get());
            }
        }

        // if we only partially completed a type then add an empty string for later processing
        if(min_num > 0 && op->get_type_size_max() != min_num && collected % op->get_type_size_max() != 0) {
            op->add_result(std::string{});
        }

        if(!rest.empty()) {
            rest = "-" + rest;
            args.push_back(rest);
        }
        return true;
    }