From ba9ad29fdbfda3836bb06b35817f08fd10beaa22 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 13 Apr 2017 20:53:23 +0200 Subject: Convert Settings to the new config system This makes all config options self-documenting. Unknown or unparseable config settings and --option flags now cause a warning. --- src/libutil/config.cc | 104 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 21 deletions(-) (limited to 'src/libutil/config.cc') diff --git a/src/libutil/config.cc b/src/libutil/config.cc index c05a3253bc..85e5ce330b 100644 --- a/src/libutil/config.cc +++ b/src/libutil/config.cc @@ -11,7 +11,7 @@ void Config::set(const std::string & name, const std::string & value) i->second.setting->set(value); } -void Config::add(AbstractSetting * setting) +void Config::addSetting(AbstractSetting * setting) { _settings.emplace(setting->name, Config::SettingData{false, setting}); for (auto & alias : setting->aliases) @@ -41,21 +41,59 @@ void Config::add(AbstractSetting * setting) } } -void Config::warnUnused() +void Config::warnUnknownSettings() { for (auto & i : initials) warn("unknown setting '%s'", i.first); } -std::string Config::dump() +StringMap Config::getSettings() { - std::string res; + StringMap res; for (auto & opt : _settings) if (!opt.second.isAlias) - res += opt.first + " = " + opt.second.setting->to_string() + "\n"; + res.emplace(opt.first, opt.second.setting->to_string()); return res; } +void Config::applyConfigFile(const Path & path, bool fatal) +{ + try { + string contents = readFile(path); + + unsigned int pos = 0; + + while (pos < contents.size()) { + string line; + while (pos < contents.size() && contents[pos] != '\n') + line += contents[pos++]; + pos++; + + string::size_type hash = line.find('#'); + if (hash != string::npos) + line = string(line, 0, hash); + + vector tokens = tokenizeString >(line); + if (tokens.empty()) continue; + + if (tokens.size() < 2 || tokens[1] != "=") + throw UsageError("illegal configuration line ‘%1%’ in ‘%2%’", line, path); + + string name = tokens[0]; + + vector::iterator i = tokens.begin(); + advance(i, 2); + + try { + set(name, concatStringsSep(" ", Strings(i, tokens.end()))); // FIXME: slow + } catch (UsageError & e) { + if (fatal) throw; + warn("in configuration file '%s': %s", path, e.what()); + } + }; + } catch (SysError &) { } +} + AbstractSetting::AbstractSetting( const std::string & name, const std::string & description, @@ -74,41 +112,65 @@ template<> std::string Setting::to_string() return value; } -template -void Setting::set(const std::string & str) +template +void Setting::set(const std::string & str) { static_assert(std::is_integral::value, "Integer required."); - try { - auto i = std::stoll(str); - if (i < std::numeric_limits::min() || - i > std::numeric_limits::max()) - throw UsageError("setting '%s' has out-of-range value %d", name, i); - value = i; - } catch (std::logic_error&) { + if (!string2Int(str, value)) throw UsageError("setting '%s' has invalid value '%s'", name, str); - } } -template -std::string Setting::to_string() +template +std::string Setting::to_string() { static_assert(std::is_integral::value, "Integer required."); return std::to_string(value); } -template<> void Setting::set(const std::string & str) +bool AbstractSetting::parseBool(const std::string & str) { if (str == "true" || str == "yes" || str == "1") - value = true; + return true; else if (str == "false" || str == "no" || str == "0") - value = false; + return false; else throw UsageError("Boolean setting '%s' has invalid value '%s'", name, str); } +template<> void Setting::set(const std::string & str) +{ + value = parseBool(str); +} + +std::string AbstractSetting::printBool(bool b) +{ + return b ? "true" : "false"; +} + + template<> std::string Setting::to_string() { - return value ? "true" : "false"; + return printBool(value); +} + +template<> void Setting::set(const std::string & str) +{ + value = tokenizeString(str); +} + +template<> std::string Setting::to_string() +{ + return concatStringsSep(" ", value); +} + +template<> void Setting::set(const std::string & str) +{ + value = tokenizeString(str); +} + +template<> std::string Setting::to_string() +{ + return concatStringsSep(" ", value); } template class Setting; -- cgit 1.4.1