Skip to content

Commit 4be2e10

Browse files
ryanofskyajtowns
andcommitted
refactor: Split InterpretOption into Interpret{Key,Value} functions
Co-authored-by: Anthony Towns <[email protected]>
1 parent 825f4a6 commit 4be2e10

File tree

1 file changed

+45
-46
lines changed

1 file changed

+45
-46
lines changed

src/util/system.cpp

Lines changed: 45 additions & 46 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>
@@ -185,59 +186,59 @@ static std::string SettingName(const std::string& arg)
185186
}
186187

187188
/**
188-
* Interpret -nofoo as if the user supplied -foo=0.
189+
* Split up setting key string, removing "section." and "no" prefixes.
189190
*
190-
* This method also tracks when the -no form was supplied, and if so,
191-
* checks whether there was a double-negative (-nofoo=0 -> -foo=1).
192-
*
193-
* If there was not a double negative, it removes the "no" from the key
194-
* and returns false.
195-
*
196-
* If there was a double negative, it removes "no" from the key, and
197-
* returns true.
198-
*
199-
* If there was no "no", it returns the string value untouched.
200-
*
201-
* Where an option was negated can be later checked using the
191+
* @note Where an option was negated can be later checked using the
202192
* IsArgNegated() method. One use case for this is to have a way to disable
203193
* options that are not normally boolean (e.g. using -nodebuglogfile to request
204194
* that debug log output is not sent to any file at all).
205195
*/
206-
207-
static util::SettingsValue InterpretOption(std::string& section, std::string& key, const std::string& value)
196+
struct KeyInfo { std::string section; bool negated{false}; };
197+
KeyInfo InterpretKey(std::string& key)
208198
{
199+
KeyInfo result;
209200
// Split section name from key name for keys like "testnet.foo" or "regtest.bar"
210201
size_t option_index = key.find('.');
211202
if (option_index != std::string::npos) {
212-
section = key.substr(0, option_index);
203+
result.section = key.substr(0, option_index);
213204
key.erase(0, option_index + 1);
214205
}
215206
if (key.substr(0, 2) == "no") {
216207
key.erase(0, 2);
217-
// Double negatives like -nofoo=0 are supported (but discouraged)
218-
if (!InterpretBool(value)) {
219-
LogPrintf("Warning: parsed potentially confusing double-negative -%s=%s\n", key, value);
220-
return true;
221-
}
222-
return false;
208+
result.negated = true;
223209
}
224-
return value;
210+
return result;
225211
}
226212

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

243244
namespace {
@@ -353,21 +354,21 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin
353354

354355
// Transform -foo to foo
355356
key.erase(0, 1);
356-
std::string section;
357-
util::SettingsValue value = InterpretOption(section, key, val);
357+
KeyInfo keyinfo = InterpretKey(key);
358358
std::optional<unsigned int> flags = GetArgFlags('-' + key);
359359

360360
// Unknown command line options and command line options with dot
361-
// characters (which are returned from InterpretOption with nonempty
361+
// characters (which are returned from InterpretKey with nonempty
362362
// section strings) are not valid.
363-
if (!flags || !section.empty()) {
363+
if (!flags || !keyinfo.section.empty()) {
364364
error = strprintf("Invalid parameter %s", argv[i]);
365365
return false;
366366
}
367367

368-
if (!CheckValid(key, value, *flags, error)) return false;
368+
std::optional<util::SettingsValue> value = InterpretValue(key, val, keyinfo.negated, *flags, error);
369+
if (!value) return false;
369370

370-
m_settings.command_line_options[key].push_back(value);
371+
m_settings.command_line_options[key].push_back(*value);
371372
}
372373

373374
// we do not allow -includeconf from command line, only -noincludeconf
@@ -550,9 +551,8 @@ bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors)
550551
return false;
551552
}
552553
for (const auto& setting : m_settings.rw_settings) {
553-
std::string section;
554554
std::string key = setting.first;
555-
(void)InterpretOption(section, key, /* value */ {}); // Split setting key into section and argname
555+
(void)InterpretKey(key); // Split setting key into section and argname
556556
if (!GetArgFlags('-' + key)) {
557557
LogPrintf("Ignoring unknown rw_settings value %s\n", setting.first);
558558
}
@@ -872,15 +872,14 @@ bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& file
872872
return false;
873873
}
874874
for (const std::pair<std::string, std::string>& option : options) {
875-
std::string section;
876875
std::string key = option.first;
877-
util::SettingsValue value = InterpretOption(section, key, option.second);
876+
KeyInfo keyinfo = InterpretKey(key);
878877
std::optional<unsigned int> flags = GetArgFlags('-' + key);
879878
if (flags) {
880-
if (!CheckValid(key, value, *flags, error)) {
881-
return false;
882-
}
883-
m_settings.ro_config[section][key].push_back(value);
879+
std::optional<util::SettingsValue> value =
880+
InterpretValue(key, option.second, keyinfo.negated, *flags, error);
881+
if (!value) return false;
882+
m_settings.ro_config[keyinfo.section][key].push_back(*value);
884883
} else {
885884
if (ignore_invalid_keys) {
886885
LogPrintf("Ignoring unknown configuration value %s\n", option.first);

0 commit comments

Comments
 (0)