Add four 'strtoll' variants, which are like 'atoll' but let you detect if
the string converted wasn't entirely numeric. Using them for numeric
command-line options -- previously if you had a option "--foo=<n>", where
<n> is supposed to be an integer, then "--foo=blah" would be interpreted as
"--foo=0", because the "blah" would be converted to zero and the remaining
chars wouldn't be noticed.
Fixed an incorrect command-line option in two massif tests that this change
exposed.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7149 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/include/pub_tool_libcbase.h b/include/pub_tool_libcbase.h
index f282bfd..0be7534 100644
--- a/include/pub_tool_libcbase.h
+++ b/include/pub_tool_libcbase.h
@@ -42,6 +42,27 @@
Converting strings to numbers
------------------------------------------------------------------ */
+// Convert strings to numbers according to various bases. Leading
+// whitespace is ignored. A subsequent '-' or '+' is accepted. For strtoll16,
+// accepts an initial "0x" or "0X" prefix, but only if it's followed by a
+// hex digit (if not, the '0' will be read and then it will stop on the
+// "x"/"X".) If 'endptr' isn't NULL, it gets filled in with the first
+// non-digit char. None of them test that the number fits into 64 bits.
+//
+// Nb: if you're wondering why we don't just have a single VG_(strtol) which
+// takes a base, it's because I wanted it to assert if it was given a bogus
+// base (the standard glibc one sets 'errno' in this case). But
+// m_libcbase.c doesn't import any code, not even vg_assert. --njn
+extern Long VG_(strtoll8) ( Char* str, Char** endptr );
+extern Long VG_(strtoll10) ( Char* str, Char** endptr );
+extern Long VG_(strtoll16) ( Char* str, Char** endptr );
+extern Long VG_(strtoll36) ( Char* str, Char** endptr );
+
+ // Convert a string to a double. After leading whitespace is ignored,
+ // it accepts a non-empty sequence of decimal digits possibly containing
+ // a '.'.
+extern double VG_(strtod) ( Char* str, Char** endptr );
+
extern Long VG_(atoll) ( Char* str ); // base 10
extern Long VG_(atoll16) ( Char* str ); // base 16; leading 0x accepted
extern Long VG_(atoll36) ( Char* str ); // base 36
diff --git a/include/pub_tool_options.h b/include/pub_tool_options.h
index 3c50ce6..e395260 100644
--- a/include/pub_tool_options.h
+++ b/include/pub_tool_options.h
@@ -52,7 +52,11 @@
#define VG_NUM_CLO(qq_arg, qq_option, qq_var) \
if (VG_CLO_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) { \
- (qq_var) = (Int)VG_(atoll)( &qq_arg[ VG_(strlen)(qq_option)+1 ] ); \
+ Char* s; \
+ Long n = VG_(strtoll10)( &qq_arg[ VG_(strlen)(qq_option)+1 ], &s );\
+ (qq_var) = n; \
+ /* Check for non-numeralness, or overflow */ \
+ if ('\0' != s[0] || (qq_var) != n) VG_(err_bad_option)(qq_arg); \
}
/* Same as VG_NUM_CLO but does not coerce the result value to 32 bits