aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2014-05-03 10:20:58 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2014-05-09 16:45:56 +0200
commit0d4ea1cf8a349cf59795ac68645afe70e98c6b3a (patch)
tree10aaa665a70c821e0f9773c190e47fa330adcc11
parente443ed2462b706650f51f08c8760dbf5047aa77f (diff)
util: add parseint32 function with strict error reporting
None of the current integer parsing functions in util check whether the result is valid and fits in the range of the type. This is required for less sloppy error reporting.
-rw-r--r--src/test/util_tests.cpp22
-rw-r--r--src/util.cpp14
-rw-r--r--src/util.h7
3 files changed, 43 insertions, 0 deletions
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index b8f107f644..7e7c05a59d 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -342,4 +342,26 @@ BOOST_AUTO_TEST_CASE(gettime)
BOOST_CHECK((GetTime() & ~0xFFFFFFFFLL) == 0);
}
+BOOST_AUTO_TEST_CASE(test_ParseInt32)
+{
+ int32_t n;
+ // Valid values
+ BOOST_CHECK(ParseInt32("1234", NULL));
+ BOOST_CHECK(ParseInt32("0", &n) && n == 0);
+ BOOST_CHECK(ParseInt32("1234", &n) && n == 1234);
+ BOOST_CHECK(ParseInt32("01234", &n) && n == 1234); // no octal
+ BOOST_CHECK(ParseInt32("2147483647", &n) && n == 2147483647);
+ BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648);
+ BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234);
+ // Invalid values
+ BOOST_CHECK(!ParseInt32("1a", &n));
+ BOOST_CHECK(!ParseInt32("aap", &n));
+ BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
+ // Overflow and underflow
+ BOOST_CHECK(!ParseInt32("-2147483649", NULL));
+ BOOST_CHECK(!ParseInt32("2147483648", NULL));
+ BOOST_CHECK(!ParseInt32("-32482348723847471234", NULL));
+ BOOST_CHECK(!ParseInt32("32482348723847471234", NULL));
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/util.cpp b/src/util.cpp
index a919b4b854..36ac23b1d5 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1427,3 +1427,17 @@ void RenameThread(const char* name)
#endif
}
+bool ParseInt32(const std::string& str, int32_t *out)
+{
+ char *endp = NULL;
+ errno = 0; // strtol will not set errno if valid
+ long int n = strtol(str.c_str(), &endp, 10);
+ if(out) *out = (int)n;
+ // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
+ // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
+ // platforms the size of these types may be different.
+ return endp && *endp == 0 && !errno &&
+ n >= std::numeric_limits<int32_t>::min() &&
+ n <= std::numeric_limits<int32_t>::max();
+}
+
diff --git a/src/util.h b/src/util.h
index fbd841f7a8..fa1e664c92 100644
--- a/src/util.h
+++ b/src/util.h
@@ -256,6 +256,13 @@ inline int atoi(const std::string& str)
return atoi(str.c_str());
}
+/**
+ * Convert string to signed 32-bit integer with strict parse error feedback.
+ * @returns true if the entire string could be parsed as valid integer,
+ * false if not the entire string could be parsed or when overflow or underflow occured.
+ */
+bool ParseInt32(const std::string& str, int32_t *out);
+
inline int roundint(double d)
{
return (int)(d > 0 ? d + 0.5 : d - 0.5);