void _process_requirements()

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