diff options
author | Jakob Kaivo <jkk@ung.org> | 2019-03-02 15:00:31 -0500 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2019-03-02 15:00:31 -0500 |
commit | 73211ec3e7af1bc7b8123b561535dd9509fc0db1 (patch) | |
tree | e411ccf74e7b0c6f4890c50be1a90ec88397e82a /src/stdlib | |
parent | 59a08ae18e8c8b4b4240af268ce7da585c2fe6ed (diff) |
more robust implementation
Diffstat (limited to 'src/stdlib')
-rw-r--r-- | src/stdlib/_strtoi.h | 88 |
1 files changed, 82 insertions, 6 deletions
diff --git a/src/stdlib/_strtoi.h b/src/stdlib/_strtoi.h index 7a2d5cdf..a46d6c0c 100644 --- a/src/stdlib/_strtoi.h +++ b/src/stdlib/_strtoi.h @@ -1,12 +1,56 @@ /* int iswide = (sizeof(*nptr) == sizeof(wchar_t)); */ - (void)max; + void *start = (void*)nptr; + int sign = 0; + int overflow = 0; + + /* skip leading whitespace */ + while (isspace(*nptr)) { + nptr++; + } + + /* get sign, if any */ + if (*nptr == '+') { + sign = 1; + nptr++; + } else if (*nptr == '-') { + sign = -1; + nptr++; + } + + /* fail if sign is negative but we are doing unsigned conversion */ + if (min == 0 && sign == -1) { + if (endptr) { + *endptr = start; + } + return 0; + } else if (sign == 0) { + sign = 1; + } + /* determine base */ if (base == 0) { - /* determine base from prefix */ + if (nptr[0] == '0') { + if (nptr[1] == 'x' || nptr[1] == 'X') { + base = 16; + } else { + base = 8; + } + } else { + base = 10; + } + } + + /* verify valid base */ + if (base < 2 || base > 36) { + if (endptr) { + *endptr = start; + } + return 0; } - if (min == 0) { - /* unsigned */ + /* skip leading 0x if appropriate */ + if (base == 16 && nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X')) { + nptr += 2; } while (*nptr) { @@ -30,14 +74,46 @@ case 'd': case 'D': n = 0xd; break; case 'e': case 'E': n = 0xe; break; case 'f': case 'F': n = 0xf; break; + case 'g': case 'G': n = 0x10; break; + case 'h': case 'H': n = 0x11; break; + case 'i': case 'I': n = 0x12; break; + case 'j': case 'J': n = 0x13; break; + case 'k': case 'K': n = 0x14; break; + case 'l': case 'L': n = 0x15; break; + case 'm': case 'M': n = 0x16; break; + case 'n': case 'N': n = 0x17; break; + case 'o': case 'O': n = 0x18; break; + case 'p': case 'P': n = 0x19; break; + case 'q': case 'Q': n = 0x1a; break; + case 'r': case 'R': n = 0x1b; break; + case 's': case 'S': n = 0x1c; break; + case 't': case 'T': n = 0x1d; break; + case 'u': case 'U': n = 0x1e; break; + case 'v': case 'V': n = 0x1f; break; + case 'w': case 'W': n = 0x20; break; + case 'x': case 'X': n = 0x21; break; + case 'y': case 'Y': n = 0x22; break; + case 'z': case 'Z': n = 0x23; break; default: n = -1; break; } if (n >= base || n < 0) { - *endptr = (void*)nptr; + if (endptr) { + *endptr = (void*)nptr; + } break; } - ret = (ret * base) + n; + if (ret > max / base) { + overflow = 1; + } else { + ret = (ret * base) + n; + } nptr++; } + + if (overflow) { + ret = (sign == 1) ? max : min; + } else { + ret *= sign; + } |