From cd7b3de1b36eefea7ead0a401018e0ea8fde3624 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 12 Oct 2025 15:50:33 +0200 Subject: [PATCH] Finally add support for setting the default option. --- lib/config/config.cc | 54 ++++++++++++++++++++++++++++++++++++++------ lib/config/config.h | 1 + lib/config/flags.cc | 1 + 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/lib/config/config.cc b/lib/config/config.cc index cec45b20..c96fbe44 100644 --- a/lib/config/config.cc +++ b/lib/config/config.cc @@ -211,6 +211,13 @@ void Config::clear() _appliedOptions.clear(); } +static std::string getValidValues(const OptionGroupProto& group) +{ + return fmt::format("{}", + fmt::join( + std::views::transform(group.option(), &OptionProto::name), ", ")); +} + std::vector Config::validate() { std::vector results; @@ -218,7 +225,7 @@ std::vector Config::validate() /* Ensure that only one item in each group is set. */ std::map optionsByGroup; - for (auto [group, option, hasArgument] : _appliedOptions) + for (auto& [group, option, hasArgument] : _appliedOptions) if (group) { auto& o = optionsByGroup[group]; @@ -227,12 +234,23 @@ std::vector Config::validate() fmt::format("multiple mutually exclusive values set for " "group '{}': valid values are: {}", group->comment(), - fmt::join(std::views::transform( - group->option(), &OptionProto::name), - ", "))); + getValidValues(*group))); o = option; } + /* Ensure that every group has an option set. */ + + for (const auto& group : base()->option_group()) + { + if (!optionsByGroup.contains(&group)) + { + results.push_back( + fmt::format("no value set for group '{}': valid values are: {}", + group.comment(), + getValidValues(group))); + } + } + /* Check option requirements. */ for (auto [group, option, hasArgument] : _appliedOptions) @@ -357,7 +375,7 @@ Config::OptionInfo Config::findOption( { if (optionGroup.name().empty()) if (searchOptionList(optionGroup.option(), name)) - return {nullptr, found, false}; + return {&optionGroup, found, false}; } throw OptionNotFoundException(fmt::format("option {} not found", name)); @@ -395,8 +413,7 @@ void Config::checkOptionValid(const OptionProto& option) ss << ']'; throw InapplicableOptionException( - fmt::format("option '{}' is inapplicable to this " - "configuration " + fmt::format("option '{}' is inapplicable to this configuration " "because {}={} could not be met", option.name(), req.key(), @@ -434,6 +451,29 @@ bool Config::applyOption(const std::string& name, const std::string value) return optionInfo.usesValue; } +void Config::applyDefaultOptions() +{ + std::set appliedOptionGroups; + for (auto& [group, option, hasArgument] : _appliedOptions) + if (group) + appliedOptionGroups.insert(group); + + /* For every group which doesn't have an option set, find the default and + * set it. */ + + for (const auto& group : base()->option_group()) + { + if (!appliedOptionGroups.contains(&group)) + { + for (const auto& option : group.option()) + { + if (option.set_by_default()) + applyOption({&group, &option, false}); + } + } + } +} + void Config::clearOptions() { _appliedOptions.clear(); diff --git a/lib/config/config.h b/lib/config/config.h index e3026336..c31b9772 100644 --- a/lib/config/config.h +++ b/lib/config/config.h @@ -142,6 +142,7 @@ public: bool isOptionValid(const OptionProto& option); void applyOption(const OptionInfo& optionInfo); bool applyOption(const std::string& name, const std::string value = ""); + void applyDefaultOptions(); void clearOptions(); /* Adjust overall inputs and outputs. */ diff --git a/lib/config/flags.cc b/lib/config/flags.cc index f61b0dac..1017b900 100644 --- a/lib/config/flags.cc +++ b/lib/config/flags.cc @@ -174,6 +174,7 @@ std::vector FlagGroup::parseFlagsWithFilenames(int argc, index++; } + globalConfig().applyDefaultOptions(); globalConfig().validateAndThrow(); return filenames; }