aboutsummaryrefslogtreecommitdiff
path: root/src/util.cpp
diff options
context:
space:
mode:
authorEvan Klitzke <evan@eklitzke.org>2018-03-21 19:24:17 -0700
committerEvan Klitzke <evan@eklitzke.org>2018-03-27 22:12:02 -0700
commitf7683cba7b070b722a2e0641f4d1516112392ed6 (patch)
tree6352a758ef05dc2dc28de2f8f23fa94c656baeee /src/util.cpp
parent4f872b24501f40bd410227b5413bda2f2569af24 (diff)
downloadbitcoin-f7683cba7b070b722a2e0641f4d1516112392ed6.tar.xz
Track negated arguments in the argument paser.
This commit adds tracking for negated arguments. This change will be used in a future commit that allows disabling the debug.log file using -nodebuglogfile.
Diffstat (limited to 'src/util.cpp')
-rw-r--r--src/util.cpp99
1 files changed, 68 insertions, 31 deletions
diff --git a/src/util.cpp b/src/util.cpp
index dbf9065113..490897899b 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -70,8 +70,6 @@
#include <malloc.h>
#endif
-#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
-#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/program_options/detail/config_file.hpp>
#include <boost/thread.hpp>
@@ -432,7 +430,23 @@ bool DirIsWritable(const fs::path& directory)
return true;
}
-/** Interpret string as boolean, for argument parsing */
+/**
+ * Interpret a string argument as a boolean.
+ *
+ * The definition of atoi() requires that non-numeric string values like "foo",
+ * return 0. This means that if a user unintentionally supplies a non-integer
+ * argument here, the return value is always false. This means that -foo=false
+ * does what the user probably expects, but -foo=true is well defined but does
+ * not do what they probably expected.
+ *
+ * The return value of atoi() is undefined when given input not representable as
+ * an int. On most systems this means string value between "-2147483648" and
+ * "2147483647" are well defined (this method will return true). Setting
+ * -txindex=2147483648 on most systems, however, is probably undefined.
+ *
+ * For a more extensive discussion of this topic (and a wide range of opinions
+ * on the Right Way to change this code), see PR12713.
+ */
static bool InterpretBool(const std::string& strValue)
{
if (strValue.empty())
@@ -440,13 +454,30 @@ static bool InterpretBool(const std::string& strValue)
return (atoi(strValue) != 0);
}
-/** Turn -noX into -X=0 */
-static void InterpretNegativeSetting(std::string& strKey, std::string& strValue)
+/**
+ * Interpret -nofoo as if the user supplied -foo=0.
+ *
+ * This method also tracks when the -no form was supplied, and treats "-foo" as
+ * a negated option when this happens. This can be later checked using the
+ * IsArgNegated() method. One use case for this is to have a way to disable
+ * options that are not normally boolean (e.g. using -nodebuglogfile to request
+ * that debug log output is not sent to any file at all).
+ */
+void ArgsManager::InterpretNegatedOption(std::string& key, std::string& val)
{
- if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o')
- {
- strKey = "-" + strKey.substr(3);
- strValue = InterpretBool(strValue) ? "0" : "1";
+ if (key.substr(0, 3) == "-no") {
+ bool bool_val = InterpretBool(val);
+ if (!bool_val ) {
+ // Double negatives like -nofoo=0 are supported (but discouraged)
+ LogPrintf("Warning: parsed potentially confusing double-negative %s=%s\n", key, val);
+ }
+ key.erase(1, 2);
+ m_negated_args.insert(key);
+ val = bool_val ? "0" : "1";
+ } else {
+ // In an invocation like "bitcoind -nofoo -foo" we want to unmark -foo
+ // as negated when we see the second option.
+ m_negated_args.erase(key);
}
}
@@ -455,34 +486,34 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[])
LOCK(cs_args);
mapArgs.clear();
mapMultiArgs.clear();
-
- for (int i = 1; i < argc; i++)
- {
- std::string str(argv[i]);
- std::string strValue;
- size_t is_index = str.find('=');
- if (is_index != std::string::npos)
- {
- strValue = str.substr(is_index+1);
- str = str.substr(0, is_index);
+ m_negated_args.clear();
+
+ for (int i = 1; i < argc; i++) {
+ std::string key(argv[i]);
+ std::string val;
+ size_t is_index = key.find('=');
+ if (is_index != std::string::npos) {
+ val = key.substr(is_index + 1);
+ key.erase(is_index);
}
#ifdef WIN32
- boost::to_lower(str);
- if (boost::algorithm::starts_with(str, "/"))
- str = "-" + str.substr(1);
+ std::transform(key.begin(), key.end(), key.begin(), ::tolower);
+ if (key[0] == '/')
+ key[0] = '-';
#endif
- if (str[0] != '-')
+ if (key[0] != '-')
break;
- // Interpret --foo as -foo.
- // If both --foo and -foo are set, the last takes effect.
- if (str.length() > 1 && str[1] == '-')
- str = str.substr(1);
- InterpretNegativeSetting(str, strValue);
+ // Transform --foo to -foo
+ if (key.length() > 1 && key[1] == '-')
+ key.erase(0, 1);
+
+ // Transform -nofoo to -foo=0
+ InterpretNegatedOption(key, val);
- mapArgs[str] = strValue;
- mapMultiArgs[str].push_back(strValue);
+ mapArgs[key] = val;
+ mapMultiArgs[key].push_back(val);
}
}
@@ -500,6 +531,12 @@ bool ArgsManager::IsArgSet(const std::string& strArg) const
return mapArgs.count(strArg);
}
+bool ArgsManager::IsArgNegated(const std::string& strArg) const
+{
+ LOCK(cs_args);
+ return m_negated_args.find(strArg) != m_negated_args.end();
+}
+
std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const
{
LOCK(cs_args);
@@ -711,7 +748,7 @@ void ArgsManager::ReadConfigFile(const std::string& confPath)
// Don't overwrite existing settings so command line settings override bitcoin.conf
std::string strKey = std::string("-") + it->string_key;
std::string strValue = it->value[0];
- InterpretNegativeSetting(strKey, strValue);
+ InterpretNegatedOption(strKey, strValue);
if (mapArgs.count(strKey) == 0)
mapArgs[strKey] = strValue;
mapMultiArgs[strKey].push_back(strValue);