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 ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ Valgrind-developers mailing list Valgrind-developers@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/valgrind-developers