in dep/CLI11/CLI11.hpp [7734:7885]
void _process_requirements()
{
// check excludes
bool excluded{ false };
std::string excluder;
for (auto& opt : exclude_options_)
{
if (opt->count() > 0)
{
excluded = true;
excluder = opt->get_name();
}
}
for (auto& subc : exclude_subcommands_)
{
if (subc->count_all() > 0)
{
excluded = true;
excluder = subc->get_display_name();
}
}
if (excluded)
{
if (count_all() > 0)
{
throw ExcludesError(get_display_name(), excluder);
}
// if we are excluded but didn't receive anything, just return
return;
}
// check excludes
bool missing_needed{ false };
std::string missing_need;
for (auto& opt : need_options_)
{
if (opt->count() == 0)
{
missing_needed = true;
missing_need = opt->get_name();
}
}
for (auto& subc : need_subcommands_)
{
if (subc->count_all() == 0)
{
missing_needed = true;
missing_need = subc->get_display_name();
}
}
if (missing_needed)
{
if (count_all() > 0)
{
throw RequiresError(get_display_name(), missing_need);
}
// if we missing something but didn't have any options, just return
return;
}
std::size_t used_options = 0;
for (const Option_p& opt : options_)
{
if (opt->count() != 0)
{
++used_options;
}
// Required but empty
if (opt->get_required() && opt->count() == 0)
{
throw RequiredError(opt->get_name());
}
// Requires
for (const Option* opt_req : opt->needs_)
if (opt->count() > 0 && opt_req->count() == 0)
throw RequiresError(opt->get_name(), opt_req->get_name());
// Excludes
for (const Option* opt_ex : opt->excludes_)
if (opt->count() > 0 && opt_ex->count() != 0)
throw ExcludesError(opt->get_name(), opt_ex->get_name());
}
// check for the required number of subcommands
if (require_subcommand_min_ > 0)
{
auto selected_subcommands = get_subcommands();
if (require_subcommand_min_ > selected_subcommands.size())
throw RequiredError::Subcommand(require_subcommand_min_);
}
// Max error cannot occur, the extra subcommand will parse as an ExtrasError or a remaining item.
// run this loop to check how many unnamed subcommands were actually used since they are considered options
// from the perspective of an App
for (App_p& sub : subcommands_)
{
if (sub->disabled_)
continue;
if (sub->name_.empty() && sub->count_all() > 0)
{
++used_options;
}
}
if (require_option_min_ > used_options || (require_option_max_ > 0 && require_option_max_ < used_options))
{
auto option_list = detail::join(options_, [](const Option_p& ptr) { return ptr->get_name(false, true); });
if (option_list.compare(0, 10, "-h,--help,") == 0)
{
option_list.erase(0, 10);
}
auto subc_list = get_subcommands([](App* app) { return ((app->get_name().empty()) && (!app->disabled_)); });
if (!subc_list.empty())
{
option_list += "," + detail::join(subc_list, [](const App* app) { return app->get_display_name(); });
}
throw RequiredError::Option(require_option_min_, require_option_max_, used_options, option_list);
}
// now process the requirements for subcommands if needed
for (App_p& sub : subcommands_)
{
if (sub->disabled_)
continue;
if (sub->name_.empty() && sub->required_ == false)
{
if (sub->count_all() == 0)
{
if (require_option_min_ > 0 && require_option_min_ <= used_options)
{
continue;
// if we have met the requirement and there is nothing in this option group skip checking
// requirements
}
if (require_option_max_ > 0 && used_options >= require_option_min_)
{
continue;
// if we have met the requirement and there is nothing in this option group skip checking
// requirements
}
}
}
if (sub->count() > 0 || sub->name_.empty())
{
sub->_process_requirements();
}
if (sub->required_ && sub->count_all() == 0)
{
throw(CLI::RequiredError(sub->get_display_name()));
}
}
}