about summary refs log tree commit diff
path: root/src/stdlib/wcstoumax.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdlib/wcstoumax.c')
-rw-r--r--src/stdlib/wcstoumax.c41
1 files changed, 14 insertions, 27 deletions
diff --git a/src/stdlib/wcstoumax.c b/src/stdlib/wcstoumax.c
index 86528ef1..e30b0638 100644
--- a/src/stdlib/wcstoumax.c
+++ b/src/stdlib/wcstoumax.c
@@ -3,46 +3,33 @@
 #include <stdlib.h>
 #include <inttypes.h>
 #include <errno.h>
+#include "intparse.h"
 
 uintmax_t wcstoumax(const wchar_t *s, wchar_t **p, int base)
 {
-	/* Large enough for largest value in binary */
-	char buf[sizeof(uintmax_t)*8+2];
-	int sign = 0, skipped=0;
+	struct intparse ip = {0};
+	unsigned char tmp;
 
-	if (!p) p = (wchar_t **)&s;
+	if (p) *p = (wchar_t *)s;
 
-	if (base && (unsigned)base-2 > 36-2) {
-		*p = (wchar_t *)s;
+	if (base && base-2U > 34) {
 		errno = EINVAL;
 		return 0;
 	}
 
-	/* Initial whitespace */
 	for (; iswspace(*s); s++);
 
-	/* Optional sign */
-	if (*s == '-') sign = *s++;
-	else if (*s == '+') s++;
-
-	/* Skip leading zeros but don't allow leading zeros before "0x". */
-	for (; s[0]=='0' && s[1]=='0'; s++) skipped=1;
-	if (skipped && (base==0 || base==16) && (s[1]|32)=='x') {
-		*p = (wchar_t *)(s+1);
-		return 0;
-	}
-
-	/* Convert to normal char string so we can use strtoumax */
-	buf[0] = sign;
-	if (wcstombs(buf+!!sign, s, sizeof buf-1) == -1) return 0;
-	buf[sizeof buf-1]=0;
+	ip.base = base;
+	for (; *s<256 && (tmp=*s, __intparse(&ip, &tmp, 1)); s++);
 
-	/* Compute final position */
-	if (p) {
-		if ((base==0 || base==16) && s[0]=='0' && (s[1]|32)=='x' && iswxdigit(s[2])) s+=2;
-		for(;*s&&((unsigned)*s-'0'<base||((unsigned)*s|32)-'a'<base-10);s++);
+	if (p && ip.err != EINVAL)
 		*p = (wchar_t *)s;
+
+	if (ip.err) {
+		errno = ip.err;
+		if (ip.err = EINVAL) return 0;
+		return UINTMAX_MAX;
 	}
 
-	return strtoumax(buf, 0, base);
+	return ip.neg ? -ip.val : ip.val;
 }