|
From: <sv...@va...> - 2007-11-11 21:58:19
|
Author: njn
Date: 2007-11-11 21:58:21 +0000 (Sun, 11 Nov 2007)
New Revision: 7149
Log:
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.
Modified:
trunk/coregrind/m_libcbase.c
trunk/include/pub_tool_libcbase.h
trunk/include/pub_tool_options.h
trunk/massif/tests/zero1.post.exp
trunk/massif/tests/zero1.vgtest
trunk/massif/tests/zero2.post.exp
trunk/massif/tests/zero2.vgtest
Modified: trunk/coregrind/m_libcbase.c
===================================================================
--- trunk/coregrind/m_libcbase.c 2007-11-11 21:12:28 UTC (rev 7148)
+++ trunk/coregrind/m_libcbase.c 2007-11-11 21:58:21 UTC (rev 7149)
@@ -50,76 +50,178 @@
Converting strings to numbers
------------------------------------------------------------------ */
-Long VG_(atoll) ( Char* str )
+static Bool is_oct_digit(Char c, Long* digit)
{
+ if (c >= '0' && c <= '7') { *digit = (Long)(c - '0'); return True; }
+ return False;
+}
+
+static Bool is_dec_digit(Char c, Long* digit)
+{
+ if (c >= '0' && c <= '9') { *digit = (Long)(c - '0'); return True; }
+ return False;
+}
+
+static Bool is_hex_digit(Char c, Long* digit)
+{
+ if (c >= '0' && c <= '9') { *digit = (Long)(c - '0'); return True; }
+ if (c >= 'A' && c <= 'F') { *digit = (Long)((c - 'A') + 10); return True; }
+ if (c >= 'a' && c <= 'f') { *digit = (Long)((c - 'a') + 10); return True; }
+ return False;
+}
+
+static Bool is_base36_digit(Char c, Long* digit)
+{
+ if (c >= '0' && c <= '9') { *digit = (Long)(c - '0'); return True; }
+ if (c >= 'A' && c <= 'Z') { *digit = (Long)((c - 'A') + 10); return True; }
+ if (c >= 'a' && c <= 'z') { *digit = (Long)((c - 'a') + 10); return True; }
+ return False;
+}
+
+Long VG_(strtoll8) ( Char* str, Char** endptr )
+{
Bool neg = False;
- Long n = 0;
- if (*str == '-') { str++; neg = True; };
- while (*str >= '0' && *str <= '9') {
- n = 10*n + (Long)(*str - '0');
+ Long n = 0, digit;
+
+ // Skip leading whitespace.
+ while (VG_(isspace)(*str)) str++;
+
+ // Allow a leading '-' or '+'.
+ if (*str == '-') { str++; neg = True; }
+ else if (*str == '+') { str++; }
+
+ while (is_oct_digit(*str, &digit)) {
+ n = 8*n + digit;
str++;
}
+
if (neg) n = -n;
+ if (endptr) *endptr = str; // Record first failing character.
return n;
}
-Long VG_(atoll16) ( Char* str )
+Long VG_(strtoll10) ( Char* str, Char** endptr )
{
Bool neg = False;
- Long n = 0;
- if (*str == '-') { str++; neg = True; };
- if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) {
+ Long n = 0, digit;
+
+ // Skip leading whitespace.
+ while (VG_(isspace)(*str)) str++;
+
+ // Allow a leading '-' or '+'.
+ if (*str == '-') { str++; neg = True; }
+ else if (*str == '+') { str++; }
+
+ while (is_dec_digit(*str, &digit)) {
+ n = 10*n + digit;
+ str++;
+ }
+
+ if (neg) n = -n;
+ if (endptr) *endptr = str; // Record first failing character.
+ return n;
+}
+
+Long VG_(strtoll16) ( Char* str, Char** endptr )
+{
+ Bool neg = False;
+ Long n = 0, digit;
+
+ // Skip leading whitespace.
+ while (VG_(isspace)(*str)) str++;
+
+ // Allow a leading '-' or '+'.
+ if (*str == '-') { str++; neg = True; }
+ else if (*str == '+') { str++; }
+
+ // Allow leading "0x", but only if there's a hex digit
+ // following it.
+ if (*str == '0'
+ && (*(str+1) == 'x' || *(str+1) == 'X')
+ && is_hex_digit( *(str+2), &digit )) {
str += 2;
}
- while (True) {
- Char c = *str;
- if (c >= '0' && c <= (Char)'9') {
- n = 16*n + (Long)(c - '0');
- }
- else
- if (c >= 'A' && c <= (Char)'F') {
- n = 16*n + (Long)((c - 'A') + 10);
- }
- else
- if (c >= 'a' && c <= (Char)'f') {
- n = 16*n + (Long)((c - 'a') + 10);
- }
- else {
- break;
- }
+
+ while (is_hex_digit(*str, &digit)) {
+ n = 16*n + digit;
str++;
}
+
if (neg) n = -n;
+ if (endptr) *endptr = str; // Record first failing character.
return n;
}
-Long VG_(atoll36) ( Char* str )
+Long VG_(strtoll36) ( Char* str, Char** endptr )
{
Bool neg = False;
- Long n = 0;
- if (*str == '-') { str++; neg = True; };
- while (True) {
- Char c = *str;
- if (c >= '0' && c <= (Char)'9') {
- n = 36*n + (Long)(c - '0');
- }
- else
- if (c >= 'A' && c <= (Char)'Z') {
- n = 36*n + (Long)((c - 'A') + 10);
- }
- else
- if (c >= 'a' && c <= (Char)'z') {
- n = 36*n + (Long)((c - 'a') + 10);
- }
- else {
- break;
- }
+ Long n = 0, digit;
+
+ // Skip leading whitespace.
+ while (VG_(isspace)(*str)) str++;
+
+ // Allow a leading '-' or '+'.
+ if (*str == '-') { str++; neg = True; }
+ else if (*str == '+') { str++; }
+
+ while (is_base36_digit(*str, &digit)) {
+ n = 36*n + digit;
str++;
}
+
if (neg) n = -n;
+ if (endptr) *endptr = str; // Record first failing character.
return n;
}
+double VG_(strtod) ( Char* str, Char** endptr )
+{
+ Bool neg = False;
+ Long digit;
+ double n = 0, frac = 0, x = 0.1;
+
+ // Skip leading whitespace.
+ while (VG_(isspace)(*str)) str++;
+
+ // Allow a leading '-' or '+'.
+ if (*str == '-') { str++; neg = True; }
+ else if (*str == '+') { str++; }
+
+ while (is_dec_digit(*str, &digit)) {
+ n = 10*n + digit;
+ str++;
+ }
+
+ if (*str == '.') {
+ str++;
+ while (is_dec_digit(*str, &digit)) {
+ frac += x*digit;
+ x /= 10;
+ str++;
+ }
+ }
+
+ n += frac;
+ if (neg) n = -n;
+ if (endptr) *endptr = str; // Record first failing character.
+ return n;
+}
+
+Long VG_(atoll) ( Char* str )
+{
+ return VG_(strtoll10)(str, NULL);
+}
+
+Long VG_(atoll16) ( Char* str )
+{
+ return VG_(strtoll16)(str, NULL);
+}
+
+Long VG_(atoll36) ( Char* str )
+{
+ return VG_(strtoll36)(str, NULL);
+}
+
/* ---------------------------------------------------------------------
String functions
------------------------------------------------------------------ */
Modified: trunk/include/pub_tool_libcbase.h
===================================================================
--- trunk/include/pub_tool_libcbase.h 2007-11-11 21:12:28 UTC (rev 7148)
+++ trunk/include/pub_tool_libcbase.h 2007-11-11 21:58:21 UTC (rev 7149)
@@ -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
Modified: trunk/include/pub_tool_options.h
===================================================================
--- trunk/include/pub_tool_options.h 2007-11-11 21:12:28 UTC (rev 7148)
+++ trunk/include/pub_tool_options.h 2007-11-11 21:58:21 UTC (rev 7149)
@@ -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
Modified: trunk/massif/tests/zero1.post.exp
===================================================================
--- trunk/massif/tests/zero1.post.exp 2007-11-11 21:12:28 UTC (rev 7148)
+++ trunk/massif/tests/zero1.post.exp 2007-11-11 21:58:21 UTC (rev 7149)
@@ -1,6 +1,6 @@
--------------------------------------------------------------------------------
Command: ./zero
-Massif arguments: --stacks=no --heap-admin=no --time-unit=B
+Massif arguments: --stacks=no --heap-admin=0 --time-unit=B
ms_print arguments: --threshold=0 massif.out
--------------------------------------------------------------------------------
Modified: trunk/massif/tests/zero1.vgtest
===================================================================
--- trunk/massif/tests/zero1.vgtest 2007-11-11 21:12:28 UTC (rev 7148)
+++ trunk/massif/tests/zero1.vgtest 2007-11-11 21:58:21 UTC (rev 7149)
@@ -1,4 +1,4 @@
prog: zero
-vgopts: --stacks=no --heap-admin=no --time-unit=B
+vgopts: --stacks=no --heap-admin=0 --time-unit=B
post: perl ../../massif/ms_print --threshold=0 massif.out | ../../tests/filter_addresses
cleanup: rm massif.out
Modified: trunk/massif/tests/zero2.post.exp
===================================================================
--- trunk/massif/tests/zero2.post.exp 2007-11-11 21:12:28 UTC (rev 7148)
+++ trunk/massif/tests/zero2.post.exp 2007-11-11 21:58:21 UTC (rev 7149)
@@ -1,6 +1,6 @@
--------------------------------------------------------------------------------
Command: ./zero
-Massif arguments: --stacks=no --heap-admin=no --time-unit=B
+Massif arguments: --stacks=no --heap-admin=0 --time-unit=B
ms_print arguments: massif.out
--------------------------------------------------------------------------------
Modified: trunk/massif/tests/zero2.vgtest
===================================================================
--- trunk/massif/tests/zero2.vgtest 2007-11-11 21:12:28 UTC (rev 7148)
+++ trunk/massif/tests/zero2.vgtest 2007-11-11 21:58:21 UTC (rev 7149)
@@ -1,4 +1,4 @@
prog: zero
-vgopts: --stacks=no --heap-admin=no --time-unit=B
+vgopts: --stacks=no --heap-admin=0 --time-unit=B
post: perl ../../massif/ms_print massif.out | ../../tests/filter_addresses
cleanup: rm massif.out
|