]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add four 'strtoll' variants, which are like 'atoll' but let you detect if
authorNicholas Nethercote <njn@valgrind.org>
Sun, 11 Nov 2007 21:58:21 +0000 (21:58 +0000)
committerNicholas Nethercote <njn@valgrind.org>
Sun, 11 Nov 2007 21:58:21 +0000 (21:58 +0000)
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

coregrind/m_libcbase.c
include/pub_tool_libcbase.h
include/pub_tool_options.h
massif/tests/zero1.post.exp
massif/tests/zero1.vgtest
massif/tests/zero2.post.exp
massif/tests/zero2.vgtest

index 698772839c7d0563d104fd4ab94f7b9e3308d324..6331a7a657838c202b0387caef6636066b1c2745 100644 (file)
@@ -50,76 +50,178 @@ Bool VG_(isdigit) ( Char c )
    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
    ------------------------------------------------------------------ */
index f282bfd755901dec0a2f4a18a02bedf9c1daae4b..0be7534e510048f911aa91823ea6cab05a2d2e9b 100644 (file)
@@ -42,6 +42,27 @@ extern Bool VG_(isdigit) ( Char c );
    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
index 3c50ce69dfef0f3e6dbb03d513fbe7b7da7246ed..e39526047a398a1852434567722e020f589b2b98 100644 (file)
 
 #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
index 9c6c78460023b74aa2015eb51f4f5682bbac4470..d27a8628e090f06845046f9c574b42f836ad8dcc 100644 (file)
@@ -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
 --------------------------------------------------------------------------------
 
index b07738ba6d0383d5e12bbe3353c5db0b80c0b95e..e32c628c14aac3284b1df217983dcb7592932479 100644 (file)
@@ -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
index d8421699d2cc1dd6d9581f64e3775bb9716edf37..244c60a92ede16b4b0d4b8ddac595a4656db9fd0 100644 (file)
@@ -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
 --------------------------------------------------------------------------------
 
index 2044bba4b3fb72859f44d751ff714137fbbcbe91..8cacf37461c750a311aba056f60fb7a5d41af024 100644 (file)
@@ -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