bool _parse_arg()

in dep/CLI11/CLI11.hpp [8354:8516]


        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;
        }