| #include "stdio_impl.h" |
| #include "intscan.h" |
| #include "shgetc.h" |
| #include <inttypes.h> |
| #include <limits.h> |
| #include <ctype.h> |
|
|
| #ifdef __EMSCRIPTEN__ |
| #include <errno.h> |
|
|
| |
| |
| |
| |
| |
| |
| static unsigned long long strtox(const char *s, char **p, int base, unsigned long long lim) { |
| int neg=0; |
| unsigned long long y=0; |
| const char* orig = s; |
|
|
| if (base > 36) { |
| errno = EINVAL; |
| return 0; |
| } |
|
|
| while (*s && isspace(*s)) { s++; }; |
|
|
| |
| if (*s=='+' || *s=='-') { |
| neg = -(*s=='-'); |
| s++; |
| } |
|
|
| int found_digit = 0; |
|
|
| |
| if ((base == 0 || base == 16) && *s=='0') { |
| found_digit = 1; |
| s++; |
| if ((*s|32)=='x') { |
| s++; |
| base = 16; |
| } else if (base == 0) { |
| base = 8; |
| } |
| } else if (base == 0) { |
| base = 10; |
| } |
|
|
| int val; |
| int overflow = 0; |
| for (y=0; ; s++) { |
| if ('0' <= *s && *s <= '9') val = *s -'0'; |
| else if ('a' <= *s && *s <= 'z') val = 10 + *s -'a'; |
| else if ('A' <= *s && *s <= 'Z') val = 10 + *s -'A'; |
| else break; |
| if (val>=base) break; |
| if (y > ULLONG_MAX/base || (base*y>ULLONG_MAX-val)) { |
| overflow = 1; |
| continue; |
| } |
| found_digit = 1; |
| y = y*base + val; |
| } |
| if (p) { |
| if (found_digit) { |
| *p = (char*)s; |
| } else { |
| *p = (char*)orig; |
| } |
| } |
| if (overflow) { |
| |
| errno = ERANGE; |
| y = lim; |
| if (lim&1) neg = 0; |
| } |
| if (y>=lim) { |
| if (!(lim&1) && !neg) { |
| errno = ERANGE; |
| return lim-1; |
| } else if (y>lim) { |
| errno = ERANGE; |
| return lim; |
| } |
| } |
| return (y^neg)-neg; |
| } |
| #else |
| static unsigned long long strtox(const char *s, char **p, int base, unsigned long long lim) |
| { |
| FILE f; |
| sh_fromstring(&f, s); |
| shlim(&f, 0); |
| unsigned long long y = __intscan(&f, base, 1, lim); |
| if (p) { |
| size_t cnt = shcnt(&f); |
| *p = (char *)s + cnt; |
| } |
| return y; |
| } |
| #endif |
|
|
| unsigned long long strtoull(const char *restrict s, char **restrict p, int base) |
| { |
| return strtox(s, p, base, ULLONG_MAX); |
| } |
|
|
| long long strtoll(const char *restrict s, char **restrict p, int base) |
| { |
| return strtox(s, p, base, LLONG_MIN); |
| } |
|
|
| unsigned long strtoul(const char *restrict s, char **restrict p, int base) |
| { |
| return strtox(s, p, base, ULONG_MAX); |
| } |
|
|
| long strtol(const char *restrict s, char **restrict p, int base) |
| { |
| return strtox(s, p, base, 0UL+LONG_MIN); |
| } |
|
|
| intmax_t strtoimax(const char *restrict s, char **restrict p, int base) |
| { |
| return strtoll(s, p, base); |
| } |
|
|
| uintmax_t strtoumax(const char *restrict s, char **restrict p, int base) |
| { |
| return strtoull(s, p, base); |
| } |
|
|
| weak_alias(strtol, __strtol_internal); |
| weak_alias(strtoul, __strtoul_internal); |
| weak_alias(strtoll, __strtoll_internal); |
| weak_alias(strtoull, __strtoull_internal); |
| weak_alias(strtoimax, __strtoimax_internal); |
| weak_alias(strtoumax, __strtoumax_internal); |
|
|