diff options
Diffstat (limited to 'src/stdlib')
32 files changed, 688 insertions, 0 deletions
diff --git a/src/stdlib/abs.c b/src/stdlib/abs.c new file mode 100644 index 00000000..4806d629 --- /dev/null +++ b/src/stdlib/abs.c @@ -0,0 +1,4 @@ +int abs(int a) +{ + return a>0 ? a : -a; +} diff --git a/src/stdlib/atof.c b/src/stdlib/atof.c new file mode 100644 index 00000000..f7fcd826 --- /dev/null +++ b/src/stdlib/atof.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +double atof(const char *s) +{ + return strtod(s, 0); +} diff --git a/src/stdlib/atoi.c b/src/stdlib/atoi.c new file mode 100644 index 00000000..648b154f --- /dev/null +++ b/src/stdlib/atoi.c @@ -0,0 +1,15 @@ +#include <stdlib.h> +#include <ctype.h> + +int atoi(const char *s) +{ + int n=0, neg=0; + while (isspace(*s)) s++; + switch (*s) { + case '-': neg=1; + case '+': s++; + } + while (isdigit(*s)) + n = 10*n + *s++ - '0'; + return neg ? -n : n; +} diff --git a/src/stdlib/atol.c b/src/stdlib/atol.c new file mode 100644 index 00000000..9c91bba9 --- /dev/null +++ b/src/stdlib/atol.c @@ -0,0 +1,16 @@ +#include <stdlib.h> +#include <ctype.h> + +long atol(const char *s) +{ + long n=0; + int neg=0; + while (isspace(*s)) s++; + switch (*s) { + case '-': neg=1; + case '+': s++; + } + while (isdigit(*s)) + n = 10*n + *s++ - '0'; + return neg ? -n : n; +} diff --git a/src/stdlib/atoll.c b/src/stdlib/atoll.c new file mode 100644 index 00000000..0e03e0a1 --- /dev/null +++ b/src/stdlib/atoll.c @@ -0,0 +1,16 @@ +#include <stdlib.h> +#include <ctype.h> + +long long atoll(const char *s) +{ + long long n=0; + int neg=0; + while (isspace(*s)) s++; + switch (*s) { + case '-': neg=1; + case '+': s++; + } + while (isdigit(*s)) + n = 10*n + *s++ - '0'; + return neg ? -n : n; +} diff --git a/src/stdlib/bsearch.c b/src/stdlib/bsearch.c new file mode 100644 index 00000000..61d89367 --- /dev/null +++ b/src/stdlib/bsearch.c @@ -0,0 +1,20 @@ +#include <stdlib.h> + +void *bsearch(const void *key, const void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *)) +{ + void *try; + int sign; + while (nel > 0) { + try = (char *)base + width*(nel/2); + sign = cmp(key, try); + if (!sign) return try; + else if (nel == 1) break; + else if (sign < 0) + nel /= 2; + else { + base = try; + nel -= nel/2; + } + } + return NULL; +} diff --git a/src/stdlib/div.c b/src/stdlib/div.c new file mode 100644 index 00000000..e42c1f14 --- /dev/null +++ b/src/stdlib/div.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +div_t div(int num, int den) +{ + return (div_t){ num/den, num%den }; +} diff --git a/src/stdlib/frexp.c b/src/stdlib/frexp.c new file mode 100644 index 00000000..ae82cb30 --- /dev/null +++ b/src/stdlib/frexp.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <inttypes.h> + +double frexp(double x, int *e) +{ + union { double d; uint64_t i; } y = { x }; + int ee = y.i>>52 & 0x7ff; + + if (!ee) { + if (x) { + x = frexp(x*0x1p64, e); + *e -= 64; + } else *e = 0; + return x; + } else if (ee == 0x7ff) { + return x; + } + + *e = ee - 0x3fe; + y.i &= 0x800fffffffffffffull; + y.i |= 0x3fe0000000000000ull; + return y.d; +} diff --git a/src/stdlib/frexpf.c b/src/stdlib/frexpf.c new file mode 100644 index 00000000..ee5e910a --- /dev/null +++ b/src/stdlib/frexpf.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <inttypes.h> + +float frexpf(float x, int *e) +{ + union { float f; uint32_t i; } y = { x }; + int ee = y.i>>23 & 0xff; + + if (!ee) { + if (x) { + x = frexpf(x*0x1p64, e); + *e -= 64; + } else *e = 0; + return x; + } else if (ee == 0xff) { + return x; + } + + *e = ee - 0x7e; + y.i &= 0x807ffffful; + y.i |= 0x3f000000ul; + return y.f; +} diff --git a/src/stdlib/frexpl.c b/src/stdlib/frexpl.c new file mode 100644 index 00000000..ecfff007 --- /dev/null +++ b/src/stdlib/frexpl.c @@ -0,0 +1,25 @@ +#include <math.h> +#include <inttypes.h> + +/* This version is for 80-bit little endian long double */ + +long double frexpl(long double x, int *e) +{ + union { long double ld; uint16_t hw[5]; } y = { x }; + int ee = y.hw[4]&0x7fff; + + if (!ee) { + if (x) { + x = frexpl(x*0x1p64, e); + *e -= 64; + } else *e = 0; + return x; + } else if (ee == 0x7fff) { + return x; + } + + *e = ee - 0x3ffe; + y.hw[4] &= 0x8000; + y.hw[4] |= 0x3ffe; + return y.ld; +} diff --git a/src/stdlib/imaxabs.c b/src/stdlib/imaxabs.c new file mode 100644 index 00000000..81001819 --- /dev/null +++ b/src/stdlib/imaxabs.c @@ -0,0 +1,6 @@ +#include <inttypes.h> + +intmax_t imaxabs(intmax_t a) +{ + return a>0 ? a : -a; +} diff --git a/src/stdlib/imaxdiv.c b/src/stdlib/imaxdiv.c new file mode 100644 index 00000000..b2ce821f --- /dev/null +++ b/src/stdlib/imaxdiv.c @@ -0,0 +1,6 @@ +#include <inttypes.h> + +imaxdiv_t imaxdiv(intmax_t num, intmax_t den) +{ + return (imaxdiv_t){ num/den, num%den }; +} diff --git a/src/stdlib/labs.c b/src/stdlib/labs.c new file mode 100644 index 00000000..675b95b8 --- /dev/null +++ b/src/stdlib/labs.c @@ -0,0 +1,4 @@ +long labs(long a) +{ + return a>0 ? a : -a; +} diff --git a/src/stdlib/ldiv.c b/src/stdlib/ldiv.c new file mode 100644 index 00000000..36eb960b --- /dev/null +++ b/src/stdlib/ldiv.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +ldiv_t ldiv(long num, long den) +{ + return (ldiv_t){ num/den, num%den }; +} diff --git a/src/stdlib/llabs.c b/src/stdlib/llabs.c new file mode 100644 index 00000000..bec4a03d --- /dev/null +++ b/src/stdlib/llabs.c @@ -0,0 +1,4 @@ +long long llabs(long long a) +{ + return a>0 ? a : -a; +} diff --git a/src/stdlib/lldiv.c b/src/stdlib/lldiv.c new file mode 100644 index 00000000..7aaf7a0e --- /dev/null +++ b/src/stdlib/lldiv.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +lldiv_t lldiv(long long num, long long den) +{ + return (lldiv_t){ num/den, num%den }; +} diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c new file mode 100644 index 00000000..f5bf3d02 --- /dev/null +++ b/src/stdlib/qsort.c @@ -0,0 +1,50 @@ +#include <stdlib.h> +#include <string.h> + +/* A simple heap sort implementation.. only in-place O(nlogn) sort I know. */ + +#define MIN(a, b) ((a)<(b) ? (a) : (b)) + +static void swap(char *a, char *b, size_t len) +{ + char tmp[256]; + size_t l; + while (len) { + l = MIN(sizeof tmp, len); + memcpy(tmp, a, l); + memcpy(a, b, l); + memcpy(b, tmp, l); + a += l; + b += l; + len -= l; + } +} + +static void sift(char *base, size_t root, size_t nel, size_t width, int (*cmp)(const void *, const void *)) +{ + size_t max; + + while (2*root <= nel) { + max = 2*root; + if (max < nel && cmp(base+max*width, base+(max+1)*width) < 0) + max++; + if (cmp(base+root*width, base+max*width) < 0) { + swap(base+root*width, base+max*width, width); + root = max; + } else break; + } +} + +void qsort(void *_base, size_t nel, size_t width, int (*cmp)(const void *, const void *)) +{ + char *base = _base; + size_t i; + + if (!nel) return; + for (i=(nel+1)/2; i; i--) + sift(base, i-1, nel-1, width, cmp); + for (i=nel-1; i; i--) { + swap(base, base+i*width, width); + sift(base, 0, i-1, width, cmp); + } +} diff --git a/src/stdlib/strtod.c b/src/stdlib/strtod.c new file mode 100644 index 00000000..388058fe --- /dev/null +++ b/src/stdlib/strtod.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +double strtod(const char *s, char **p) +{ + return strtold(s, p); +} diff --git a/src/stdlib/strtof.c b/src/stdlib/strtof.c new file mode 100644 index 00000000..07b32df4 --- /dev/null +++ b/src/stdlib/strtof.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +float strtof(const char *s, char **p) +{ + return strtold(s, p); +} diff --git a/src/stdlib/strtoimax.c b/src/stdlib/strtoimax.c new file mode 100644 index 00000000..19691091 --- /dev/null +++ b/src/stdlib/strtoimax.c @@ -0,0 +1,25 @@ +#include <inttypes.h> +#include <errno.h> +#include <ctype.h> + +intmax_t strtoimax(const char *s1, char **p, int base) +{ + const unsigned char *s = s1; + int sign = 0; + uintmax_t x; + + /* Initial whitespace */ + for (; isspace(*s); s++); + + /* Optional sign */ + if (*s == '-') sign = *s++; + else if (*s == '+') s++; + + x = strtoumax(s, p, base); + if (x > INTMAX_MAX) { + if (!sign || -x != INTMAX_MIN) + errno = ERANGE; + return sign ? INTMAX_MIN : INTMAX_MAX; + } + return sign ? -x : x; +} diff --git a/src/stdlib/strtol.c b/src/stdlib/strtol.c new file mode 100644 index 00000000..ace820af --- /dev/null +++ b/src/stdlib/strtol.c @@ -0,0 +1,17 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long strtol(const char *s, char **p, int base) +{ + intmax_t x = strtoimax(s, p, base); + if (x > LONG_MAX) { + errno = ERANGE; + return LONG_MAX; + } else if (x < LONG_MIN) { + errno = ERANGE; + return LONG_MIN; + } + return x; +} diff --git a/src/stdlib/strtold.c b/src/stdlib/strtold.c new file mode 100644 index 00000000..54f80469 --- /dev/null +++ b/src/stdlib/strtold.c @@ -0,0 +1,93 @@ +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> + +long double strtold(const char *s1, char **p) +{ + const unsigned char *s = s1; + long double x = 0; + long double frac; + int sign = 0; + int nonzero = 0; + int radix = '.'; + long e; + + if (!p) p = (char **)&s1; + + /* Initial whitespace */ + for (; isspace(*s); s++); + + /* Optional sign */ + if (*s == '-') sign = *s++; + else if (*s == '+') s++; + + /* Handle infinities and NaNs. */ + if ((s[0]|32)=='i' && (s[1]|32)=='n' && (s[2]|32)=='f') { + *p = (char *)s + 3; + return sign ? -1.0/0.0 : 1.0/0.0; + } else if ((s[0]|32)=='n' && (s[1]|32)=='a' && (s[2]|32)=='n') { + *p = (char *)s + 3; + return 0.0/0.0; + } + + /* Possible hex float */ + if (s[0]=='0' && (s[1]|32)=='x') { + /* Mantissa must be non-degenerate */ + if (!isxdigit(s[2]) && (s[2]!=radix || !isxdigit(s[3]))) { + /* Decimal float 0, 'x' extraneous */ + *p = (char *)++s; + return 0; + } + /* We have a real hex float */ + s += 2; + for (; isxdigit(*s); s++) { + x = 16*x + (isdigit(*s)?*s-'0':(*s|32)-'a'); + if (*s!='0') nonzero=1; + } + if (*s == radix) { + frac = 1.0/16.0; + for (s++; isxdigit(*s); s++) { + x += frac * (isdigit(*s)?*s-'0':(*s|32)-'a'); + frac *= 1.0/16.0; + if (*s!='0') nonzero=1; + } + } + if ((*s|32) == 'p') { + e = strtol(s+1, (void *)&s, 10); + for (; e>0; e--) x *= 2.0; + for (; e<0; e++) x *= 0.5; + } + if ((nonzero && !x) || !(1.0/x)) + errno = ERANGE; + *p = (char *)s; + return sign ? -x : x; + } + + /* Mantissa must be non-degenerate */ + if (!isdigit(s[0]) && (s[0]!=radix || !isdigit(s[1]))) { + *p = (char *)s1; + return 0; + } + + for (; isdigit(*s); s++) { + x = 10*x + *s-'0'; + if (*s!='0') nonzero=1; + } + if (*s == radix) { + frac = 10.0; + for (s++; isdigit(*s); s++) { + x += (*s-'0') / frac; + frac *= 10.0; + if (*s!='0') nonzero=1; + } + } + if ((*s|32)=='e') { + e = strtol(++s, (void *)&s, 10); + for (; e>0; e--) x *= 10.0; + for (; e<0; e++) x /= 10.0; + } + if ((nonzero && !x) || !(1.0/x)) + errno = ERANGE; + *p = (char*)s; + return sign ? -x : x; +} diff --git a/src/stdlib/strtoll.c b/src/stdlib/strtoll.c new file mode 100644 index 00000000..9ab66fd9 --- /dev/null +++ b/src/stdlib/strtoll.c @@ -0,0 +1,17 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long long strtoll(const char *s, char **p, int base) +{ + intmax_t x = strtoimax(s, p, base); + if (x > LLONG_MAX) { + errno = ERANGE; + return LLONG_MAX; + } else if (x < LLONG_MIN) { + errno = ERANGE; + return LLONG_MIN; + } + return x; +} diff --git a/src/stdlib/strtoul.c b/src/stdlib/strtoul.c new file mode 100644 index 00000000..951d5e8c --- /dev/null +++ b/src/stdlib/strtoul.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long strtoul(const char *s, char **p, int base) +{ + uintmax_t x = strtoumax(s, p, base); + if (x > ULONG_MAX) { + errno = ERANGE; + return ULONG_MAX; + } + return x; +} diff --git a/src/stdlib/strtoull.c b/src/stdlib/strtoull.c new file mode 100644 index 00000000..20aa7bde --- /dev/null +++ b/src/stdlib/strtoull.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long long strtoull(const char *s, char **p, int base) +{ + uintmax_t x = strtoumax(s, p, base); + if (x > ULLONG_MAX) { + errno = ERANGE; + return ULLONG_MAX; + } + return x; +} diff --git a/src/stdlib/strtoumax.c b/src/stdlib/strtoumax.c new file mode 100644 index 00000000..a529f6e8 --- /dev/null +++ b/src/stdlib/strtoumax.c @@ -0,0 +1,123 @@ +#include <inttypes.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <stdio.h> + +/* Lookup table for digit values. -1==255>=36 -> invalid */ +static const unsigned char digits[] = { +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, +-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, +25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, +-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, +25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +}; + +uintmax_t strtoumax(const char *s1, char **p, int base) +{ + const unsigned char *s = s1; + size_t x1, z1; + uintmax_t x, z=0; + int sign = 0; + int shift; + + if (!p) p = (char **)&s1; + + /* Initial whitespace */ + for (; isspace(*s); s++); + + /* Optional sign */ + if (*s == '-') sign = *s++; + else if (*s == '+') s++; + + /* Default base 8, 10, or 16 depending on prefix */ + if (base == 0) { + if (s[0] == '0') { + if ((s[1]|32) == 'x') base = 16; + else base = 8; + } else { + base = 10; + } + } + + if ((unsigned)base-2 > 36-2 || digits[*s]>=base) { + *p = (char *)s1; + errno = EINVAL; + return 0; + } + + /* Main loops. Only use big types if we have to. */ + if (base == 10) { + for (x1=0; isdigit(*s) && x1<=SIZE_MAX/10-10; s++) + x1 = 10*x1 + *s-'0'; + for (x=x1; isdigit(*s) && x<=UINTMAX_MAX/10-10; s++) + x = 10*x + *s-'0'; + if (isdigit(*s)) { + if (isdigit(s[1]) || 10*x>UINTMAX_MAX-(*s-'0')) + goto overflow; + x = 10*x + *s-'0'; + } + } else if (!(base & base/2)) { + if (base == 16) { + if (s[0]=='0' && (s[1]|32)=='x' && digits[s[2]]<16) + s+=2; + shift=4; + z1 = SIZE_MAX/16; + z = UINTMAX_MAX/16; + } else if (base == 8) { + shift=3; + z1 = SIZE_MAX/8; + z = UINTMAX_MAX/8; + } else if (base == 2) { + shift=1; + z1 = SIZE_MAX/2; + z = UINTMAX_MAX/2; + } else if (base == 4) { + shift=2; + z1 = SIZE_MAX/4; + z = UINTMAX_MAX/4; + } else /* if (base == 32) */ { + shift=5; + z1 = SIZE_MAX/32; + z = UINTMAX_MAX/32; + } + for (x1=0; digits[*s]<base && x1<=z1; s++) + x1 = (x1<<shift) + digits[*s]; + for (x=x1; digits[*s]<base && x<=z; s++) + x = (x<<shift) + digits[*s]; + if (digits[*s] < base) goto overflow; + } else { + z1 = SIZE_MAX/base-base; + for (x1=0; digits[*s]<base && x1<=z1; s++) + x1 = x1*base + digits[*s]; + if (digits[*s]<base) + z = UINTMAX_MAX/base-base; + for (x=x1; digits[*s]<base && x<=z; s++) + x = x*base + digits[*s]; + if (digits[*s] < base) { + if (digits[s[1]]<base || x*base>UINTMAX_MAX-digits[*s]) + goto overflow; + x = x*base + digits[*s]; + } + } + + *p = (char *)s; + return sign ? -x : x; + +overflow: + for (; digits[*s] < base; s++); + *p = (char *)s; + errno = ERANGE; + return UINTMAX_MAX; +} diff --git a/src/stdlib/wcstoimax.c b/src/stdlib/wcstoimax.c new file mode 100644 index 00000000..861fcb54 --- /dev/null +++ b/src/stdlib/wcstoimax.c @@ -0,0 +1,24 @@ +#include <wchar.h> +#include <inttypes.h> +#include <errno.h> + +intmax_t wcstoimax(const wchar_t *s, wchar_t **p, int base) +{ + int sign = 0; + uintmax_t x; + + /* Initial whitespace */ + for (; iswspace(*s); s++); + + /* Optional sign */ + if (*s == '-') sign = *s++; + else if (*s == '+') s++; + + x = wcstoumax(s, p, base); + if (x > INTMAX_MAX) { + if (!sign || -x != INTMAX_MIN) + errno = ERANGE; + return sign ? INTMAX_MIN : INTMAX_MAX; + } + return sign ? -x : x; +} diff --git a/src/stdlib/wcstol.c b/src/stdlib/wcstol.c new file mode 100644 index 00000000..aad62e5b --- /dev/null +++ b/src/stdlib/wcstol.c @@ -0,0 +1,18 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long wcstol(const wchar_t *s, wchar_t **p, int base) +{ + intmax_t x = wcstoimax(s, p, base); + if (x > LONG_MAX) { + errno = ERANGE; + return LONG_MAX; + } else if (x < LONG_MIN) { + errno = ERANGE; + return LONG_MIN; + } + return x; +} diff --git a/src/stdlib/wcstoll.c b/src/stdlib/wcstoll.c new file mode 100644 index 00000000..ddfea74b --- /dev/null +++ b/src/stdlib/wcstoll.c @@ -0,0 +1,18 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long long wcstoll(const wchar_t *s, wchar_t **p, int base) +{ + intmax_t x = wcstoimax(s, p, base); + if (x > LLONG_MAX) { + errno = ERANGE; + return LLONG_MAX; + } else if (x < LLONG_MIN) { + errno = ERANGE; + return LLONG_MIN; + } + return x; +} diff --git a/src/stdlib/wcstoul.c b/src/stdlib/wcstoul.c new file mode 100644 index 00000000..e39faafe --- /dev/null +++ b/src/stdlib/wcstoul.c @@ -0,0 +1,15 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long wcstoul(const wchar_t *s, wchar_t **p, int base) +{ + uintmax_t x = wcstoumax(s, p, base); + if (x > ULONG_MAX) { + errno = ERANGE; + return ULONG_MAX; + } + return x; +} diff --git a/src/stdlib/wcstoull.c b/src/stdlib/wcstoull.c new file mode 100644 index 00000000..e324dfb2 --- /dev/null +++ b/src/stdlib/wcstoull.c @@ -0,0 +1,15 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long long wcstoull(const wchar_t *s, wchar_t **p, int base) +{ + uintmax_t x = wcstoumax(s, p, base); + if (x > ULLONG_MAX) { + errno = ERANGE; + return ULLONG_MAX; + } + return x; +} diff --git a/src/stdlib/wcstoumax.c b/src/stdlib/wcstoumax.c new file mode 100644 index 00000000..a8f4680f --- /dev/null +++ b/src/stdlib/wcstoumax.c @@ -0,0 +1,47 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.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; + + if (!p) p = (wchar_t **)&s; + + if (base && (unsigned)base-2 > 36-2) { + *p = (wchar_t *)s; + 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) < 0) return 0; + buf[sizeof buf-1]=0; + + /* 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++); + *p = (wchar_t *)s; + } + + return strtoumax(buf, 0, base); +} |