diff options
Diffstat (limited to 'src/stdlib/wcstoumax.c')
-rw-r--r-- | src/stdlib/wcstoumax.c | 41 |
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; } |