|
71 | 71 | #endif
|
72 | 72 |
|
73 | 73 | #include <boost/algorithm/string/replace.hpp>
|
| 74 | +#include <optional> |
74 | 75 | #include <thread>
|
75 | 76 | #include <typeinfo>
|
76 | 77 | #include <univalue.h>
|
@@ -182,60 +183,65 @@ static std::string SettingName(const std::string& arg)
|
182 | 183 | return arg.size() > 0 && arg[0] == '-' ? arg.substr(1) : arg;
|
183 | 184 | }
|
184 | 185 |
|
| 186 | +struct KeyInfo { |
| 187 | + std::string name; |
| 188 | + std::string section; |
| 189 | + bool negated{false}; |
| 190 | +}; |
| 191 | + |
185 | 192 | /**
|
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. |
193 | 194 | *
|
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 |
200 | 196 | * IsArgNegated() method. One use case for this is to have a way to disable
|
201 | 197 | * options that are not normally boolean (e.g. using -nodebuglogfile to request
|
202 | 198 | * that debug log output is not sent to any file at all).
|
203 | 199 | */
|
204 |
| - |
205 |
| -static util::SettingsValue InterpretOption(std::string& section, std::string& key, const std::string& value) |
| 200 | +KeyInfo InterpretKey(std::string key) |
206 | 201 | {
|
| 202 | + KeyInfo result; |
207 | 203 | // Split section name from key name for keys like "testnet.foo" or "regtest.bar"
|
208 | 204 | size_t option_index = key.find('.');
|
209 | 205 | if (option_index != std::string::npos) {
|
210 |
| - section = key.substr(0, option_index); |
| 206 | + result.section = key.substr(0, option_index); |
211 | 207 | key.erase(0, option_index + 1);
|
212 | 208 | }
|
213 | 209 | if (key.substr(0, 2) == "no") {
|
214 | 210 | 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; |
221 | 212 | }
|
222 |
| - return value; |
| 213 | + result.name = key; |
| 214 | + return result; |
223 | 215 | }
|
224 | 216 |
|
225 | 217 | /**
|
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 |
227 | 224 | *
|
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 |
231 | 227 | */
|
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 | + } |
236 | 242 | return false;
|
237 | 243 | }
|
238 |
| - return true; |
| 244 | + return value; |
239 | 245 | }
|
240 | 246 |
|
241 | 247 | namespace {
|
@@ -351,21 +357,21 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin
|
351 | 357 |
|
352 | 358 | // Transform -foo to foo
|
353 | 359 | 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); |
357 | 362 |
|
358 | 363 | // 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 |
360 | 365 | // section strings) are not valid.
|
361 |
| - if (!flags || !section.empty()) { |
| 366 | + if (!flags || !keyinfo.section.empty()) { |
362 | 367 | error = strprintf("Invalid parameter %s", argv[i]);
|
363 | 368 | return false;
|
364 | 369 | }
|
365 | 370 |
|
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; |
367 | 373 |
|
368 |
| - m_settings.command_line_options[key].push_back(value); |
| 374 | + m_settings.command_line_options[keyinfo.name].push_back(*value); |
369 | 375 | }
|
370 | 376 |
|
371 | 377 | // we do not allow -includeconf from command line, only -noincludeconf
|
@@ -548,10 +554,8 @@ bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors)
|
548 | 554 | return false;
|
549 | 555 | }
|
550 | 556 | 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)) { |
555 | 559 | LogPrintf("Ignoring unknown rw_settings value %s\n", setting.first);
|
556 | 560 | }
|
557 | 561 | }
|
@@ -870,15 +874,14 @@ bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& file
|
870 | 874 | return false;
|
871 | 875 | }
|
872 | 876 | 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); |
877 | 879 | if (flags) {
|
878 |
| - if (!CheckValid(key, value, *flags, error)) { |
| 880 | + std::optional<util::SettingsValue> value = InterpretValue(key, option.second, *flags, error); |
| 881 | + if (!value) { |
879 | 882 | return false;
|
880 | 883 | }
|
881 |
| - m_settings.ro_config[section][key].push_back(value); |
| 884 | + m_settings.ro_config[key.section][key.name].push_back(*value); |
882 | 885 | } else {
|
883 | 886 | if (ignore_invalid_keys) {
|
884 | 887 | LogPrintf("Ignoring unknown configuration value %s\n", option.first);
|
|
0 commit comments