diff options
author | Daniel Jacobowitz <drow@false.org> | 2006-09-21 13:50:51 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@false.org> | 2006-09-21 13:50:51 +0000 |
commit | 253c8abb67a72cdfcdb2be4b92e2dba8689e6554 (patch) | |
tree | 7d79e3725009992103877706f6e2317a558a663c /gdb/utils.c | |
parent | c96fc75e9e90e0781789095b842495bbcdbb037a (diff) | |
download | gdb-253c8abb67a72cdfcdb2be4b92e2dba8689e6554.zip gdb-253c8abb67a72cdfcdb2be4b92e2dba8689e6554.tar.gz gdb-253c8abb67a72cdfcdb2be4b92e2dba8689e6554.tar.bz2 |
* ada-lex.l (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int)
(strtoulst): Moved to ...
* utils.c (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int)
(strtoulst): ... here. Enhanced to behave more similarly
to strtoul.
* defs.h (strtoulst): New prototype.
Diffstat (limited to 'gdb/utils.c')
-rw-r--r-- | gdb/utils.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/gdb/utils.c b/gdb/utils.c index 6c4afb7..cf5ef19 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -3139,3 +3139,102 @@ dummy_obstack_deallocate (void *object, void *data) { return; } + +/* The bit offset of the highest byte in a ULONGEST, for overflow + checking. */ + +#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT) + +/* True (non-zero) iff DIGIT is a valid digit in radix BASE, + where 2 <= BASE <= 36. */ + +static int +is_digit_in_base (unsigned char digit, int base) +{ + if (!isalnum (digit)) + return 0; + if (base <= 10) + return (isdigit (digit) && digit < base + '0'); + else + return (isdigit (digit) || tolower (digit) < base - 10 + 'a'); +} + +static int +digit_to_int (unsigned char c) +{ + if (isdigit (c)) + return c - '0'; + else + return tolower (c) - 'a' + 10; +} + +/* As for strtoul, but for ULONGEST results. */ + +ULONGEST +strtoulst (const char *num, const char **trailer, int base) +{ + unsigned int high_part; + ULONGEST result; + int minus = 0; + int i = 0; + + /* Skip leading whitespace. */ + while (isspace (num[i])) + i++; + + /* Handle prefixes. */ + if (num[i] == '+') + i++; + else if (num[i] == '-') + { + minus = 1; + i++; + } + + if (base == 0 || base == 16) + { + if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X')) + { + i += 2; + if (base == 0) + base = 16; + } + } + + if (base == 0 && num[i] == '0') + base = 8; + + if (base == 0) + base = 10; + + if (base < 2 || base > 36) + { + errno = EINVAL; + return 0; + } + + result = high_part = 0; + for (; is_digit_in_base (num[i], base); i += 1) + { + result = result * base + digit_to_int (num[i]); + high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN); + result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1; + if (high_part > 0xff) + { + errno = ERANGE; + result = ~ (ULONGEST) 0; + high_part = 0; + minus = 0; + break; + } + } + + if (trailer != NULL) + *trailer = &num[i]; + + result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN); + if (minus) + return -result; + else + return result; +} |