summaryrefslogtreecommitdiff
path: root/src/stdlib/_strtoi.h
diff options
context:
space:
mode:
authorJakob Kaivo <jkk@ung.org>2019-03-02 15:00:31 -0500
committerJakob Kaivo <jkk@ung.org>2019-03-02 15:00:31 -0500
commit73211ec3e7af1bc7b8123b561535dd9509fc0db1 (patch)
treee411ccf74e7b0c6f4890c50be1a90ec88397e82a /src/stdlib/_strtoi.h
parent59a08ae18e8c8b4b4240af268ce7da585c2fe6ed (diff)
more robust implementation
Diffstat (limited to 'src/stdlib/_strtoi.h')
-rw-r--r--src/stdlib/_strtoi.h88
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;
+ }