summaryrefslogtreecommitdiff
path: root/src/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdlib')
-rw-r--r--src/stdlib/abs.c4
-rw-r--r--src/stdlib/atof.c6
-rw-r--r--src/stdlib/atoi.c15
-rw-r--r--src/stdlib/atol.c16
-rw-r--r--src/stdlib/atoll.c16
-rw-r--r--src/stdlib/bsearch.c20
-rw-r--r--src/stdlib/div.c6
-rw-r--r--src/stdlib/frexp.c23
-rw-r--r--src/stdlib/frexpf.c23
-rw-r--r--src/stdlib/frexpl.c25
-rw-r--r--src/stdlib/imaxabs.c6
-rw-r--r--src/stdlib/imaxdiv.c6
-rw-r--r--src/stdlib/labs.c4
-rw-r--r--src/stdlib/ldiv.c6
-rw-r--r--src/stdlib/llabs.c4
-rw-r--r--src/stdlib/lldiv.c6
-rw-r--r--src/stdlib/qsort.c50
-rw-r--r--src/stdlib/strtod.c6
-rw-r--r--src/stdlib/strtof.c6
-rw-r--r--src/stdlib/strtoimax.c25
-rw-r--r--src/stdlib/strtol.c17
-rw-r--r--src/stdlib/strtold.c93
-rw-r--r--src/stdlib/strtoll.c17
-rw-r--r--src/stdlib/strtoul.c14
-rw-r--r--src/stdlib/strtoull.c14
-rw-r--r--src/stdlib/strtoumax.c123
-rw-r--r--src/stdlib/wcstoimax.c24
-rw-r--r--src/stdlib/wcstol.c18
-rw-r--r--src/stdlib/wcstoll.c18
-rw-r--r--src/stdlib/wcstoul.c15
-rw-r--r--src/stdlib/wcstoull.c15
-rw-r--r--src/stdlib/wcstoumax.c47
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);
+}