diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2017-04-13T18·53+0200 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2017-04-13T18·53+0200 |
commit | ba9ad29fdbfda3836bb06b35817f08fd10beaa22 (patch) | |
tree | 565646143793af4e91ee88630e667bb7976e8686 /src/libutil/config.cc | |
parent | 6bd9576aeb55927cb551736a47b4e8e3fd1063bb (diff) |
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.
Diffstat (limited to 'src/libutil/config.cc')
-rw-r--r-- | src/libutil/config.cc | 104 |
1 files changed, 83 insertions, 21 deletions
diff --git a/src/libutil/config.cc b/src/libutil/config.cc index c05a3253bce6..85e5ce330bee 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<string> tokens = tokenizeString<vector<string> >(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<string>::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<std::string>::to_string() return value; } -template<typename T> -void Setting<T>::set(const std::string & str) +template<typename T, typename Tag> +void Setting<T, Tag>::set(const std::string & str) { static_assert(std::is_integral<T>::value, "Integer required."); - try { - auto i = std::stoll(str); - if (i < std::numeric_limits<T>::min() || - i > std::numeric_limits<T>::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<typename T> -std::string Setting<T>::to_string() +template<typename T, typename Tag> +std::string Setting<T, Tag>::to_string() { static_assert(std::is_integral<T>::value, "Integer required."); return std::to_string(value); } -template<> void Setting<bool>::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<bool>::set(const std::string & str) +{ + value = parseBool(str); +} + +std::string AbstractSetting::printBool(bool b) +{ + return b ? "true" : "false"; +} + + template<> std::string Setting<bool>::to_string() { - return value ? "true" : "false"; + return printBool(value); +} + +template<> void Setting<Strings>::set(const std::string & str) +{ + value = tokenizeString<Strings>(str); +} + +template<> std::string Setting<Strings>::to_string() +{ + return concatStringsSep(" ", value); +} + +template<> void Setting<StringSet>::set(const std::string & str) +{ + value = tokenizeString<StringSet>(str); +} + +template<> std::string Setting<StringSet>::to_string() +{ + return concatStringsSep(" ", value); } template class Setting<int>; |