summaryrefslogtreecommitdiffstats
path: root/libc-top-half/musl/src/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'libc-top-half/musl/src/stdlib')
-rw-r--r--libc-top-half/musl/src/stdlib/abs.c6
-rw-r--r--libc-top-half/musl/src/stdlib/atof.c6
-rw-r--r--libc-top-half/musl/src/stdlib/atoi.c16
-rw-r--r--libc-top-half/musl/src/stdlib/atol.c17
-rw-r--r--libc-top-half/musl/src/stdlib/atoll.c17
-rw-r--r--libc-top-half/musl/src/stdlib/bsearch.c20
-rw-r--r--libc-top-half/musl/src/stdlib/div.c6
-rw-r--r--libc-top-half/musl/src/stdlib/ecvt.c20
-rw-r--r--libc-top-half/musl/src/stdlib/fcvt.c25
-rw-r--r--libc-top-half/musl/src/stdlib/gcvt.c9
-rw-r--r--libc-top-half/musl/src/stdlib/imaxabs.c6
-rw-r--r--libc-top-half/musl/src/stdlib/imaxdiv.c6
-rw-r--r--libc-top-half/musl/src/stdlib/labs.c6
-rw-r--r--libc-top-half/musl/src/stdlib/ldiv.c6
-rw-r--r--libc-top-half/musl/src/stdlib/llabs.c6
-rw-r--r--libc-top-half/musl/src/stdlib/lldiv.c6
-rw-r--r--libc-top-half/musl/src/stdlib/qsort.c221
-rw-r--r--libc-top-half/musl/src/stdlib/qsort_nr.c14
-rw-r--r--libc-top-half/musl/src/stdlib/strtod.c48
-rw-r--r--libc-top-half/musl/src/stdlib/strtol.c56
-rw-r--r--libc-top-half/musl/src/stdlib/wcstod.c82
-rw-r--r--libc-top-half/musl/src/stdlib/wcstol.c83
22 files changed, 682 insertions, 0 deletions
diff --git a/libc-top-half/musl/src/stdlib/abs.c b/libc-top-half/musl/src/stdlib/abs.c
new file mode 100644
index 0000000..e721fdc
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/abs.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+int abs(int a)
+{
+ return a>0 ? a : -a;
+}
diff --git a/libc-top-half/musl/src/stdlib/atof.c b/libc-top-half/musl/src/stdlib/atof.c
new file mode 100644
index 0000000..f7fcd82
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/atof.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+double atof(const char *s)
+{
+ return strtod(s, 0);
+}
diff --git a/libc-top-half/musl/src/stdlib/atoi.c b/libc-top-half/musl/src/stdlib/atoi.c
new file mode 100644
index 0000000..9baca7b
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/atoi.c
@@ -0,0 +1,16 @@
+#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++;
+ }
+ /* Compute n as a negative number to avoid overflow on INT_MIN */
+ while (isdigit(*s))
+ n = 10*n - (*s++ - '0');
+ return neg ? n : -n;
+}
diff --git a/libc-top-half/musl/src/stdlib/atol.c b/libc-top-half/musl/src/stdlib/atol.c
new file mode 100644
index 0000000..140ea3e
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/atol.c
@@ -0,0 +1,17 @@
+#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++;
+ }
+ /* Compute n as a negative number to avoid overflow on LONG_MIN */
+ while (isdigit(*s))
+ n = 10*n - (*s++ - '0');
+ return neg ? n : -n;
+}
diff --git a/libc-top-half/musl/src/stdlib/atoll.c b/libc-top-half/musl/src/stdlib/atoll.c
new file mode 100644
index 0000000..b693048
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/atoll.c
@@ -0,0 +1,17 @@
+#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++;
+ }
+ /* Compute n as a negative number to avoid overflow on LLONG_MIN */
+ while (isdigit(*s))
+ n = 10*n - (*s++ - '0');
+ return neg ? n : -n;
+}
diff --git a/libc-top-half/musl/src/stdlib/bsearch.c b/libc-top-half/musl/src/stdlib/bsearch.c
new file mode 100644
index 0000000..fe050ea
--- /dev/null
+++ b/libc-top-half/musl/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 < 0) {
+ nel /= 2;
+ } else if (sign > 0) {
+ base = (char *)try + width;
+ nel -= nel/2+1;
+ } else {
+ return try;
+ }
+ }
+ return NULL;
+}
diff --git a/libc-top-half/musl/src/stdlib/div.c b/libc-top-half/musl/src/stdlib/div.c
new file mode 100644
index 0000000..e42c1f1
--- /dev/null
+++ b/libc-top-half/musl/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/libc-top-half/musl/src/stdlib/ecvt.c b/libc-top-half/musl/src/stdlib/ecvt.c
new file mode 100644
index 0000000..797b664
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/ecvt.c
@@ -0,0 +1,20 @@
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+
+char *ecvt(double x, int n, int *dp, int *sign)
+{
+ static char buf[16];
+ char tmp[32];
+ int i, j;
+
+ if (n-1U > 15) n = 15;
+ sprintf(tmp, "%.*e", n-1, x);
+ i = *sign = (tmp[0]=='-');
+ for (j=0; tmp[i]!='e'; j+=(tmp[i++]!='.'))
+ buf[j] = tmp[i];
+ buf[j] = 0;
+ *dp = atoi(tmp+i+1)+1;
+
+ return buf;
+}
diff --git a/libc-top-half/musl/src/stdlib/fcvt.c b/libc-top-half/musl/src/stdlib/fcvt.c
new file mode 100644
index 0000000..f90928f
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/fcvt.c
@@ -0,0 +1,25 @@
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+char *fcvt(double x, int n, int *dp, int *sign)
+{
+ char tmp[1500];
+ int i, lz;
+
+ if (n > 1400U) n = 1400;
+ sprintf(tmp, "%.*f", n, x);
+ i = (tmp[0] == '-');
+ if (tmp[i] == '0') lz = strspn(tmp+i+2, "0");
+ else lz = -(int)strcspn(tmp+i, ".");
+
+ if (n<=lz) {
+ *sign = i;
+ *dp = 1;
+ if (n>14U) n = 14;
+ return "000000000000000"+14-n;
+ }
+
+ return ecvt(x, n-lz, dp, sign);
+}
diff --git a/libc-top-half/musl/src/stdlib/gcvt.c b/libc-top-half/musl/src/stdlib/gcvt.c
new file mode 100644
index 0000000..f29bc30
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/gcvt.c
@@ -0,0 +1,9 @@
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+
+char *gcvt(double x, int n, char *b)
+{
+ sprintf(b, "%.*g", n, x);
+ return b;
+}
diff --git a/libc-top-half/musl/src/stdlib/imaxabs.c b/libc-top-half/musl/src/stdlib/imaxabs.c
new file mode 100644
index 0000000..8100181
--- /dev/null
+++ b/libc-top-half/musl/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/libc-top-half/musl/src/stdlib/imaxdiv.c b/libc-top-half/musl/src/stdlib/imaxdiv.c
new file mode 100644
index 0000000..b2ce821
--- /dev/null
+++ b/libc-top-half/musl/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/libc-top-half/musl/src/stdlib/labs.c b/libc-top-half/musl/src/stdlib/labs.c
new file mode 100644
index 0000000..83ddb14
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/labs.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+long labs(long a)
+{
+ return a>0 ? a : -a;
+}
diff --git a/libc-top-half/musl/src/stdlib/ldiv.c b/libc-top-half/musl/src/stdlib/ldiv.c
new file mode 100644
index 0000000..36eb960
--- /dev/null
+++ b/libc-top-half/musl/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/libc-top-half/musl/src/stdlib/llabs.c b/libc-top-half/musl/src/stdlib/llabs.c
new file mode 100644
index 0000000..9dfaf5c
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/llabs.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+long long llabs(long long a)
+{
+ return a>0 ? a : -a;
+}
diff --git a/libc-top-half/musl/src/stdlib/lldiv.c b/libc-top-half/musl/src/stdlib/lldiv.c
new file mode 100644
index 0000000..7aaf7a0
--- /dev/null
+++ b/libc-top-half/musl/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/libc-top-half/musl/src/stdlib/qsort.c b/libc-top-half/musl/src/stdlib/qsort.c
new file mode 100644
index 0000000..314ddc2
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/qsort.c
@@ -0,0 +1,221 @@
+/* Copyright (C) 2011 by Valentin Ochs
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Minor changes by Rich Felker for integration in musl, 2011-04-27. */
+
+/* Smoothsort, an adaptive variant of Heapsort. Memory usage: O(1).
+ Run time: Worst case O(n log n), close to O(n) in the mostly-sorted case. */
+
+#define _BSD_SOURCE
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "atomic.h"
+#define ntz(x) a_ctz_l((x))
+
+typedef int (*cmpfun)(const void *, const void *, void *);
+
+static inline int pntz(size_t p[2]) {
+ int r = ntz(p[0] - 1);
+ if(r != 0 || (r = 8*sizeof(size_t) + ntz(p[1])) != 8*sizeof(size_t)) {
+ return r;
+ }
+ return 0;
+}
+
+static void cycle(size_t width, unsigned char* ar[], int n)
+{
+ unsigned char tmp[256];
+ size_t l;
+ int i;
+
+ if(n < 2) {
+ return;
+ }
+
+ ar[n] = tmp;
+ while(width) {
+ l = sizeof(tmp) < width ? sizeof(tmp) : width;
+ memcpy(ar[n], ar[0], l);
+ for(i = 0; i < n; i++) {
+ memcpy(ar[i], ar[i + 1], l);
+ ar[i] += l;
+ }
+ width -= l;
+ }
+}
+
+/* shl() and shr() need n > 0 */
+static inline void shl(size_t p[2], int n)
+{
+ if(n >= 8 * sizeof(size_t)) {
+ n -= 8 * sizeof(size_t);
+ p[1] = p[0];
+ p[0] = 0;
+ }
+ p[1] <<= n;
+ p[1] |= p[0] >> (sizeof(size_t) * 8 - n);
+ p[0] <<= n;
+}
+
+static inline void shr(size_t p[2], int n)
+{
+ if(n >= 8 * sizeof(size_t)) {
+ n -= 8 * sizeof(size_t);
+ p[0] = p[1];
+ p[1] = 0;
+ }
+ p[0] >>= n;
+ p[0] |= p[1] << (sizeof(size_t) * 8 - n);
+ p[1] >>= n;
+}
+
+static void sift(unsigned char *head, size_t width, cmpfun cmp, void *arg, int pshift, size_t lp[])
+{
+ unsigned char *rt, *lf;
+ unsigned char *ar[14 * sizeof(size_t) + 1];
+ int i = 1;
+
+ ar[0] = head;
+ while(pshift > 1) {
+ rt = head - width;
+ lf = head - width - lp[pshift - 2];
+
+ if(cmp(ar[0], lf, arg) >= 0 && cmp(ar[0], rt, arg) >= 0) {
+ break;
+ }
+ if(cmp(lf, rt, arg) >= 0) {
+ ar[i++] = lf;
+ head = lf;
+ pshift -= 1;
+ } else {
+ ar[i++] = rt;
+ head = rt;
+ pshift -= 2;
+ }
+ }
+ cycle(width, ar, i);
+}
+
+static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg, size_t pp[2], int pshift, int trusty, size_t lp[])
+{
+ unsigned char *stepson,
+ *rt, *lf;
+ size_t p[2];
+ unsigned char *ar[14 * sizeof(size_t) + 1];
+ int i = 1;
+ int trail;
+
+ p[0] = pp[0];
+ p[1] = pp[1];
+
+ ar[0] = head;
+ while(p[0] != 1 || p[1] != 0) {
+ stepson = head - lp[pshift];
+ if(cmp(stepson, ar[0], arg) <= 0) {
+ break;
+ }
+ if(!trusty && pshift > 1) {
+ rt = head - width;
+ lf = head - width - lp[pshift - 2];
+ if(cmp(rt, stepson, arg) >= 0 || cmp(lf, stepson, arg) >= 0) {
+ break;
+ }
+ }
+
+ ar[i++] = stepson;
+ head = stepson;
+ trail = pntz(p);
+ shr(p, trail);
+ pshift += trail;
+ trusty = 0;
+ }
+ if(!trusty) {
+ cycle(width, ar, i);
+ sift(head, width, cmp, arg, pshift, lp);
+ }
+}
+
+void __qsort_r(void *base, size_t nel, size_t width, cmpfun cmp, void *arg)
+{
+ size_t lp[12*sizeof(size_t)];
+ size_t i, size = width * nel;
+ unsigned char *head, *high;
+ size_t p[2] = {1, 0};
+ int pshift = 1;
+ int trail;
+
+ if (!size) return;
+
+ head = base;
+ high = head + size - width;
+
+ /* Precompute Leonardo numbers, scaled by element width */
+ for(lp[0]=lp[1]=width, i=2; (lp[i]=lp[i-2]+lp[i-1]+width) < size; i++);
+
+ while(head < high) {
+ if((p[0] & 3) == 3) {
+ sift(head, width, cmp, arg, pshift, lp);
+ shr(p, 2);
+ pshift += 2;
+ } else {
+ if(lp[pshift - 1] >= high - head) {
+ trinkle(head, width, cmp, arg, p, pshift, 0, lp);
+ } else {
+ sift(head, width, cmp, arg, pshift, lp);
+ }
+
+ if(pshift == 1) {
+ shl(p, 1);
+ pshift = 0;
+ } else {
+ shl(p, pshift - 1);
+ pshift = 1;
+ }
+ }
+
+ p[0] |= 1;
+ head += width;
+ }
+
+ trinkle(head, width, cmp, arg, p, pshift, 0, lp);
+
+ while(pshift != 1 || p[0] != 1 || p[1] != 0) {
+ if(pshift <= 1) {
+ trail = pntz(p);
+ shr(p, trail);
+ pshift += trail;
+ } else {
+ shl(p, 2);
+ pshift -= 2;
+ p[0] ^= 7;
+ shr(p, 1);
+ trinkle(head - lp[pshift] - width, width, cmp, arg, p, pshift + 1, 1, lp);
+ shl(p, 1);
+ p[0] |= 1;
+ trinkle(head - width, width, cmp, arg, p, pshift, 1, lp);
+ }
+ head -= width;
+ }
+}
+
+weak_alias(__qsort_r, qsort_r);
diff --git a/libc-top-half/musl/src/stdlib/qsort_nr.c b/libc-top-half/musl/src/stdlib/qsort_nr.c
new file mode 100644
index 0000000..efe7cce
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/qsort_nr.c
@@ -0,0 +1,14 @@
+#define _BSD_SOURCE
+#include <stdlib.h>
+
+typedef int (*cmpfun)(const void *, const void *);
+
+static int wrapper_cmp(const void *v1, const void *v2, void *cmp)
+{
+ return ((cmpfun)cmp)(v1, v2);
+}
+
+void qsort(void *base, size_t nel, size_t width, cmpfun cmp)
+{
+ __qsort_r(base, nel, width, wrapper_cmp, cmp);
+}
diff --git a/libc-top-half/musl/src/stdlib/strtod.c b/libc-top-half/musl/src/stdlib/strtod.c
new file mode 100644
index 0000000..184bca4
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/strtod.c
@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#ifdef __wasilibc_unmodified_upstream // Changes to optimize printf/scanf when long double isn't needed
+#else
+#include "printscan.h"
+#define __NEED_locale_t
+#include <bits/alltypes.h>
+#endif
+#include "shgetc.h"
+#include "floatscan.h"
+#include "stdio_impl.h"
+
+#if defined(__wasilibc_printscan_no_long_double)
+static long_double strtox(const char *s, char **p, int prec)
+#else
+static long double strtox(const char *s, char **p, int prec)
+#endif
+{
+ FILE f;
+ sh_fromstring(&f, s);
+ shlim(&f, 0);
+#if defined(__wasilibc_printscan_no_long_double)
+ long_double y = __floatscan(&f, prec, 1);
+#else
+ long double y = __floatscan(&f, prec, 1);
+#endif
+ off_t cnt = shcnt(&f);
+ if (p) *p = cnt ? (char *)s + cnt : (char *)s;
+ return y;
+}
+
+float strtof(const char *restrict s, char **restrict p)
+{
+ return strtox(s, p, 0);
+}
+
+double strtod(const char *restrict s, char **restrict p)
+{
+ return strtox(s, p, 1);
+}
+
+long double strtold(const char *restrict s, char **restrict p)
+{
+#if defined(__wasilibc_printscan_no_long_double)
+ long_double_not_supported();
+#else
+ return strtox(s, p, 2);
+#endif
+}
diff --git a/libc-top-half/musl/src/stdlib/strtol.c b/libc-top-half/musl/src/stdlib/strtol.c
new file mode 100644
index 0000000..bfefea6
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/strtol.c
@@ -0,0 +1,56 @@
+#include "stdio_impl.h"
+#include "intscan.h"
+#include "shgetc.h"
+#include <inttypes.h>
+#include <limits.h>
+#include <ctype.h>
+
+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;
+}
+
+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);
diff --git a/libc-top-half/musl/src/stdlib/wcstod.c b/libc-top-half/musl/src/stdlib/wcstod.c
new file mode 100644
index 0000000..97b894e
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/wcstod.c
@@ -0,0 +1,82 @@
+#ifdef __wasilibc_unmodified_upstream // Changes to optimize printf/scanf when long double isn't needed
+#else
+#include "printscan.h"
+#endif
+#include "shgetc.h"
+#include "floatscan.h"
+#include "stdio_impl.h"
+#include <wchar.h>
+#include <wctype.h>
+
+/* This read function heavily cheats. It knows:
+ * (1) len will always be 1
+ * (2) non-ascii characters don't matter */
+
+static size_t do_read(FILE *f, unsigned char *buf, size_t len)
+{
+ size_t i;
+ const wchar_t *wcs = f->cookie;
+
+ if (!wcs[0]) wcs=L"@";
+ for (i=0; i<f->buf_size && wcs[i]; i++)
+ f->buf[i] = wcs[i] < 128 ? wcs[i] : '@';
+ f->rpos = f->buf;
+ f->rend = f->buf + i;
+ f->cookie = (void *)(wcs+i);
+
+ if (i && len) {
+ *buf = *f->rpos++;
+ return 1;
+ }
+ return 0;
+}
+
+#if defined(__wasilibc_printscan_no_long_double)
+static long_double wcstox(const wchar_t *s, wchar_t **p, int prec)
+#else
+static long double wcstox(const wchar_t *s, wchar_t **p, int prec)
+#endif
+{
+ wchar_t *t = (wchar_t *)s;
+ unsigned char buf[64];
+ FILE f = {0};
+ f.flags = 0;
+ f.rpos = f.rend = f.buf = buf + 4;
+ f.buf_size = sizeof buf - 4;
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ f.lock = -1;
+#endif
+ f.read = do_read;
+ while (iswspace(*t)) t++;
+ f.cookie = (void *)t;
+ shlim(&f, 0);
+#if defined(__wasilibc_printscan_no_long_double)
+ long_double y = __floatscan(&f, prec, 1);
+#else
+ long double y = __floatscan(&f, prec, 1);
+#endif
+ if (p) {
+ size_t cnt = shcnt(&f);
+ *p = cnt ? t + cnt : (wchar_t *)s;
+ }
+ return y;
+}
+
+float wcstof(const wchar_t *restrict s, wchar_t **restrict p)
+{
+ return wcstox(s, p, 0);
+}
+
+double wcstod(const wchar_t *restrict s, wchar_t **restrict p)
+{
+ return wcstox(s, p, 1);
+}
+
+long double wcstold(const wchar_t *restrict s, wchar_t **restrict p)
+{
+#if defined(__wasilibc_printscan_no_long_double)
+ long_double_not_supported();
+#else
+ return wcstox(s, p, 2);
+#endif
+}
diff --git a/libc-top-half/musl/src/stdlib/wcstol.c b/libc-top-half/musl/src/stdlib/wcstol.c
new file mode 100644
index 0000000..3aefd06
--- /dev/null
+++ b/libc-top-half/musl/src/stdlib/wcstol.c
@@ -0,0 +1,83 @@
+#include "stdio_impl.h"
+#include "intscan.h"
+#include "shgetc.h"
+#include <inttypes.h>
+#include <limits.h>
+#include <wctype.h>
+#include <wchar.h>
+
+/* This read function heavily cheats. It knows:
+ * (1) len will always be 1
+ * (2) non-ascii characters don't matter */
+
+static size_t do_read(FILE *f, unsigned char *buf, size_t len)
+{
+ size_t i;
+ const wchar_t *wcs = f->cookie;
+
+ if (!wcs[0]) wcs=L"@";
+ for (i=0; i<f->buf_size && wcs[i]; i++)
+ f->buf[i] = wcs[i] < 128 ? wcs[i] : '@';
+ f->rpos = f->buf;
+ f->rend = f->buf + i;
+ f->cookie = (void *)(wcs+i);
+
+ if (i && len) {
+ *buf = *f->rpos++;
+ return 1;
+ }
+ return 0;
+}
+
+static unsigned long long wcstox(const wchar_t *s, wchar_t **p, int base, unsigned long long lim)
+{
+ wchar_t *t = (wchar_t *)s;
+ unsigned char buf[64];
+ FILE f = {0};
+ f.flags = 0;
+ f.rpos = f.rend = f.buf = buf + 4;
+ f.buf_size = sizeof buf - 4;
+#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
+ f.lock = -1;
+#endif
+ f.read = do_read;
+ while (iswspace(*t)) t++;
+ f.cookie = (void *)t;
+ shlim(&f, 0);
+ unsigned long long y = __intscan(&f, base, 1, lim);
+ if (p) {
+ size_t cnt = shcnt(&f);
+ *p = cnt ? t + cnt : (wchar_t *)s;
+ }
+ return y;
+}
+
+unsigned long long wcstoull(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstox(s, p, base, ULLONG_MAX);
+}
+
+long long wcstoll(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstox(s, p, base, LLONG_MIN);
+}
+
+unsigned long wcstoul(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstox(s, p, base, ULONG_MAX);
+}
+
+long wcstol(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstox(s, p, base, 0UL+LONG_MIN);
+}
+
+intmax_t wcstoimax(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstoll(s, p, base);
+}
+
+uintmax_t wcstoumax(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstoull(s, p, base);
+}