Skip to content

Commit 26a50ab

Browse files
ryanofskyajtowns
andcommitted
refactor: Split InterpretOption into Interpret{Key,Value} functions
Co-authored-by: Anthony Towns <[email protected]>
1 parent 22a9018 commit 26a50ab

File tree

1 file changed

+52
-49
lines changed

1 file changed

+52
-49
lines changed

src/util/system.cpp

Lines changed: 52 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
#endif
7272

7373
#include <boost/algorithm/string/replace.hpp>
74+
#include <optional>
7475
#include <thread>
7576
#include <typeinfo>
7677
#include <univalue.h>
@@ -182,60 +183,65 @@ static std::string SettingName(const std::string& arg)
182183
return arg.size() > 0 && arg[0] == '-' ? arg.substr(1) : arg;
183184
}
184185

186+
struct KeyInfo {
187+
std::string name;
188+
std::string section;
189+
bool negated{false};
190+
};
191+
185192
/**
186-
* Interpret -nofoo as if the user supplied -foo=0.
187-
*
188-
* This method also tracks when the -no form was supplied, and if so,
189-
* checks whether there was a double-negative (-nofoo=0 -> -foo=1).
190-
*
191-
* If there was not a double negative, it removes the "no" from the key
192-
* and returns false.
193+
* Parse "name", "section.name", "noname", "section.noname" settings keys.
193194
*
194-
* If there was a double negative, it removes "no" from the key, and
195-
* returns true.
196-
*
197-
* If there was no "no", it returns the string value untouched.
198-
*
199-
* Where an option was negated can be later checked using the
195+
* @note Where an option was negated can be later checked using the
200196
* IsArgNegated() method. One use case for this is to have a way to disable
201197
* options that are not normally boolean (e.g. using -nodebuglogfile to request
202198
* that debug log output is not sent to any file at all).
203199
*/
204-
205-
static util::SettingsValue InterpretOption(std::string& section, std::string& key, const std::string& value)
200+
KeyInfo InterpretKey(std::string key)
206201
{
202+
KeyInfo result;
207203
// Split section name from key name for keys like "testnet.foo" or "regtest.bar"
208204
size_t option_index = key.find('.');
209205
if (option_index != std::string::npos) {
210-
section = key.substr(0, option_index);
206+
result.section = key.substr(0, option_index);
211207
key.erase(0, option_index + 1);
212208
}
213209
if (key.substr(0, 2) == "no") {
214210
key.erase(0, 2);
215-
// Double negatives like -nofoo=0 are supported (but discouraged)
216-
if (!InterpretBool(value)) {
217-
LogPrintf("Warning: parsed potentially confusing double-negative -%s=%s\n", key, value);
218-
return true;
219-
}
220-
return false;
211+
result.negated = true;
221212
}
222-
return value;
213+
result.name = key;
214+
return result;
223215
}
224216

225217
/**
226-
* Check settings value validity according to flags.
218+
* Interpret settings value based on registered flags.
219+
*
220+
* @param[in] key key information to know if key was negated
221+
* @param[in] value string value of setting to be parsed
222+
* @param[in] flags ArgsManager registered argument flags
223+
* @param[out] error Error description if settings value is not valid
227224
*
228-
* TODO: Add more meaningful error checks here in the future
229-
* See "here's how the flags are meant to behave" in
230-
* https://github.com/bitcoin/bitcoin/pull/16097#issuecomment-514627823
225+
* @return parsed settings value if it is valid, otherwise nullopt accompanied
226+
* by a descriptive error string
231227
*/
232-
static bool CheckValid(const std::string& key, const util::SettingsValue& val, unsigned int flags, std::string& error)
233-
{
234-
if (val.isBool() && !(flags & ArgsManager::ALLOW_BOOL)) {
235-
error = strprintf("Negating of -%s is meaningless and therefore forbidden", key);
228+
static std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, const std::string& value,
229+
unsigned int flags, std::string& error)
230+
{
231+
// Return negated settings as false values.
232+
if (key.negated) {
233+
if (!(flags & ArgsManager::ALLOW_BOOL)) {
234+
error = strprintf("Negating of -%s is meaningless and therefore forbidden", key.name);
235+
return std::nullopt;
236+
}
237+
// Double negatives like -nofoo=0 are supported (but discouraged)
238+
if (!InterpretBool(value)) {
239+
LogPrintf("Warning: parsed potentially confusing double-negative -%s=%s\n", key.name, value);
240+
return true;
241+
}
236242
return false;
237243
}
238-
return true;
244+
return value;
239245
}
240246

241247
namespace {
@@ -351,21 +357,21 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin
351357

352358
// Transform -foo to foo
353359
key.erase(0, 1);
354-
std::string section;
355-
util::SettingsValue value = InterpretOption(section, key, val);
356-
std::optional<unsigned int> flags = GetArgFlags('-' + key);
360+
KeyInfo keyinfo = InterpretKey(key);
361+
std::optional<unsigned int> flags = GetArgFlags('-' + keyinfo.name);
357362

358363
// Unknown command line options and command line options with dot
359-
// characters (which are returned from InterpretOption with nonempty
364+
// characters (which are returned from InterpretKey with nonempty
360365
// section strings) are not valid.
361-
if (!flags || !section.empty()) {
366+
if (!flags || !keyinfo.section.empty()) {
362367
error = strprintf("Invalid parameter %s", argv[i]);
363368
return false;
364369
}
365370

366-
if (!CheckValid(key, value, *flags, error)) return false;
371+
std::optional<util::SettingsValue> value = InterpretValue(keyinfo, val, *flags, error);
372+
if (!value) return false;
367373

368-
m_settings.command_line_options[key].push_back(value);
374+
m_settings.command_line_options[keyinfo.name].push_back(*value);
369375
}
370376

371377
// we do not allow -includeconf from command line, only -noincludeconf
@@ -548,10 +554,8 @@ bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors)
548554
return false;
549555
}
550556
for (const auto& setting : m_settings.rw_settings) {
551-
std::string section;
552-
std::string key = setting.first;
553-
(void)InterpretOption(section, key, /* value */ {}); // Split setting key into section and argname
554-
if (!GetArgFlags('-' + key)) {
557+
KeyInfo key = InterpretKey(setting.first); // Split setting key into section and argname
558+
if (!GetArgFlags('-' + key.name)) {
555559
LogPrintf("Ignoring unknown rw_settings value %s\n", setting.first);
556560
}
557561
}
@@ -870,15 +874,14 @@ bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& file
870874
return false;
871875
}
872876
for (const std::pair<std::string, std::string>& option : options) {
873-
std::string section;
874-
std::string key = option.first;
875-
util::SettingsValue value = InterpretOption(section, key, option.second);
876-
std::optional<unsigned int> flags = GetArgFlags('-' + key);
877+
KeyInfo key = InterpretKey(option.first);
878+
std::optional<unsigned int> flags = GetArgFlags('-' + key.name);
877879
if (flags) {
878-
if (!CheckValid(key, value, *flags, error)) {
880+
std::optional<util::SettingsValue> value = InterpretValue(key, option.second, *flags, error);
881+
if (!value) {
879882
return false;
880883
}
881-
m_settings.ro_config[section][key].push_back(value);
884+
m_settings.ro_config[key.section][key.name].push_back(*value);
882885
} else {
883886
if (ignore_invalid_keys) {
884887
LogPrintf("Ignoring unknown configuration value %s\n", option.first);

0 commit comments

Comments
 (0)