about summary refs log tree commit diff
path: root/src/stdlib/strtoimax.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdlib/strtoimax.c')
-rw-r--r--src/stdlib/strtoimax.c37
1 files changed, 25 insertions, 12 deletions
diff --git a/src/stdlib/strtoimax.c b/src/stdlib/strtoimax.c
index aeb0397f..247f91d4 100644
--- a/src/stdlib/strtoimax.c
+++ b/src/stdlib/strtoimax.c
@@ -1,25 +1,38 @@
 #include <inttypes.h>
 #include <errno.h>
 #include <ctype.h>
+#include "intparse.h"
 
 intmax_t strtoimax(const char *s1, char **p, int base)
 {
-	const unsigned char *s = (const void *)s1;
-	int sign = 0;
-	uintmax_t x;
+	const unsigned char *s = (void *)s1;
+	struct intparse ip = {0};
+
+	if (p) *p = (char *)s1;
+
+	if (base && base-2U > 34) {
+		errno = EINVAL;
+		return 0;
+	}
 
-	/* Initial whitespace */
 	for (; isspace(*s); s++);
 
-	/* Optional sign */
-	if (*s == '-') sign = *s++;
-	else if (*s == '+') s++;
+	ip.base = base;
+	__intparse(&ip, s, SIZE_MAX);
+
+	if (p && ip.err != EINVAL)
+		*p = (char *)s + ip.cnt;
+
+	if (ip.err) {
+		errno = ip.err;
+		if (ip.err = EINVAL) return 0;
+		return ip.neg ? INTMAX_MIN : INTMAX_MAX;
+	}
 
-	x = strtoumax((const void *)s, p, base);
-	if (x > INTMAX_MAX) {
-		if (!sign || -x != INTMAX_MIN)
+	if (ip.val > INTMAX_MAX) {
+		if (!ip.neg || -ip.val != INTMAX_MIN)
 			errno = ERANGE;
-		return sign ? INTMAX_MIN : INTMAX_MAX;
+		return ip.neg ? INTMAX_MIN : INTMAX_MAX;
 	}
-	return sign ? -x : x;
+	return ip.neg ? -ip.val : ip.val;
 }