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