From a7c8a57aa744497746c0b8743116cd3e1978bf23 Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <hch@cloudius-systems.com>
Date: Mon, 21 Jan 2013 15:48:22 +0100
Subject: [PATCH] import stdlib from musl

except for the floating point functionality for now.
---
 libc/build.mak        |  20 +++-
 libc/libc.cc          |  77 ---------------
 libc/qsort.c          | 197 --------------------------------------
 libc/stdlib/abs.c     |   4 +
 libc/stdlib/atoi.c    |  16 ++++
 libc/stdlib/atol.c    |  17 ++++
 libc/stdlib/atoll.c   |  17 ++++
 libc/stdlib/bsearch.c |  20 ++++
 libc/stdlib/div.c     |   6 ++
 libc/stdlib/ecvt.c    |  19 ++++
 libc/stdlib/fcvt.c    |  25 +++++
 libc/stdlib/gcvt.c    |   8 ++
 libc/stdlib/imaxabs.c |   6 ++
 libc/stdlib/imaxdiv.c |   6 ++
 libc/stdlib/labs.c    |   4 +
 libc/stdlib/ldiv.c    |   6 ++
 libc/stdlib/llabs.c   |   4 +
 libc/stdlib/lldiv.c   |   6 ++
 libc/stdlib/qsort.c   | 215 ++++++++++++++++++++++++++++++++++++++++++
 libc/stdlib/strtol.c  |  56 +++++++++++
 libc/stdlib/wcstol.c  |  82 ++++++++++++++++
 21 files changed, 536 insertions(+), 275 deletions(-)
 delete mode 100644 libc/qsort.c
 create mode 100644 libc/stdlib/abs.c
 create mode 100644 libc/stdlib/atoi.c
 create mode 100644 libc/stdlib/atol.c
 create mode 100644 libc/stdlib/atoll.c
 create mode 100644 libc/stdlib/bsearch.c
 create mode 100644 libc/stdlib/div.c
 create mode 100644 libc/stdlib/ecvt.c
 create mode 100644 libc/stdlib/fcvt.c
 create mode 100644 libc/stdlib/gcvt.c
 create mode 100644 libc/stdlib/imaxabs.c
 create mode 100644 libc/stdlib/imaxdiv.c
 create mode 100644 libc/stdlib/labs.c
 create mode 100644 libc/stdlib/ldiv.c
 create mode 100644 libc/stdlib/llabs.c
 create mode 100644 libc/stdlib/lldiv.c
 create mode 100644 libc/stdlib/qsort.c
 create mode 100644 libc/stdlib/strtol.c
 create mode 100644 libc/stdlib/wcstol.c

diff --git a/libc/build.mak b/libc/build.mak
index 07a1ba656..845928f76 100644
--- a/libc/build.mak
+++ b/libc/build.mak
@@ -247,6 +247,25 @@ libc += stdio/vwscanf.o
 libc += stdio/wprintf.o
 libc += stdio/wscanf.o
 
+libc += stdlib/abs.o
+libc += stdlib/atoi.o
+libc += stdlib/atol.o
+libc += stdlib/atoll.o
+libc += stdlib/bsearch.o
+libc += stdlib/div.o
+libc += stdlib/ecvt.o
+libc += stdlib/fcvt.o
+libc += stdlib/gcvt.o
+libc += stdlib/imaxabs.o
+libc += stdlib/imaxdiv.o
+libc += stdlib/labs.o
+libc += stdlib/ldiv.o
+libc += stdlib/llabs.o
+libc += stdlib/lldiv.o
+libc += stdlib/qsort.o
+libc += stdlib/strtol.o
+libc += stdlib/wcstol.o
+
 libc += string/bcmp.o
 libc += string/bcopy.o
 libc += string/bzero.o
@@ -352,5 +371,4 @@ libc += dlfcn.o
 libc += time.o
 libc += signal.o
 libc += mman.o
-libc += qsort.o
 libc += sem.o
diff --git a/libc/libc.cc b/libc/libc.cc
index d3711e5bd..5076982f8 100644
--- a/libc/libc.cc
+++ b/libc/libc.cc
@@ -65,83 +65,6 @@ int putenv(char* string)
     return 0; // no environent
 }
 
-template <typename N>
-N strtoN(const char* s, char** e, int base)
-{
-    typedef typename std::make_unsigned<N>::type tmp_type;
-    tmp_type tmp = 0;
-    auto max = std::numeric_limits<N>::max();
-    auto min = std::numeric_limits<N>::min();
-
-    while (*s && isspace(*s)) {
-        ++s;
-    }
-    int sign = 1;
-    if (*s == '+' || *s == '-') {
-        sign = *s++ == '-' ? -1 : 1;
-    }
-    auto overflow = sign > 0 ? max : min;
-    if (base == 0 && s[0] == '0' && s[1] == 'x') {
-        base = 16;
-    } else if (base == 0 && s[0] == '0') {
-        base = 8;
-    }
-    if (base == 16 && s[0] == '0' && s[1] == 'x') {
-        s += 2;
-    }
-    if (base == 0) {
-        base = 10;
-    }
-
-    auto convdigit = [=] (char c, int& digit) {
-        if (isdigit(c)) {
-            digit = c - '0';
-        } else if (isalpha(c)) {
-            digit = tolower(c) - 'a' + 10;
-        } else {
-            return false;
-        }
-        return digit < base;
-    };
-
-    int digit;
-    while (*s && convdigit(*s, digit)) {
-        auto old = tmp;
-        tmp = tmp * base + digit;
-        if (tmp < old) {
-            errno = ERANGE;
-            return overflow;
-        }
-        ++s;
-    }
-    if ((sign < 0 && tmp > tmp_type(max)) || (tmp > tmp_type(-min))) {
-        errno = ERANGE;
-        return overflow;
-    }
-    if (sign < 0) {
-        tmp = -tmp;
-    }
-    if (e) {
-        *e = const_cast<char*>(s);
-    }
-    return tmp;
-}
-
-long strtol(const char* s, char** e, int base)
-{
-    return strtoN<long>(s, e, base);
-}
-
-unsigned long strtoul(const char* s, char** e, int base)
-{
-    return strtoN<unsigned long>(s, e, base);
-}
-
-long long strtoll(const char* s, char** e, int base)
-{
-    return strtoN<long long>(s, e, base);
-}
-
 int getrlimit(int resource, struct rlimit *rlim)
 {
     auto set = [=] (rlim_t r) { rlim->rlim_cur = rlim->rlim_max = r; };
diff --git a/libc/qsort.c b/libc/qsort.c
deleted file mode 100644
index 7069106b5..000000000
--- a/libc/qsort.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993
- *      The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)qsort.c     8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-//__FBSDID("$FreeBSD$");
-
-#define __unused __attribute__((unused))
-
-#include <stdlib.h>
-
-#ifdef I_AM_QSORT_R
-typedef int              cmp_t(void *, const void *, const void *);
-#else
-typedef int              cmp_t(const void *, const void *);
-#endif
-static inline char      *med3(char *, char *, char *, cmp_t *, void *);
-static inline void       swapfunc(char *, char *, int, int);
-
-#define min(a, b)       (a) < (b) ? a : b
-
-/*
- * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
- */
-#define swapcode(TYPE, parmi, parmj, n) {               \
-        long i = (n) / sizeof (TYPE);                   \
-        TYPE *pi = (TYPE *) (parmi);            \
-        TYPE *pj = (TYPE *) (parmj);            \
-        do {                                            \
-                TYPE    t = *pi;                \
-                *pi++ = *pj;                            \
-                *pj++ = t;                              \
-        } while (--i > 0);                              \
-}
-
-#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
-        es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
-
-static inline void
-swapfunc(a, b, n, swaptype)
-        char *a, *b;
-        int n, swaptype;
-{
-        if(swaptype <= 1)
-                swapcode(long, a, b, n)
-        else
-                swapcode(char, a, b, n)
-}
-
-#define swap(a, b)                                      \
-        if (swaptype == 0) {                            \
-                long t = *(long *)(a);                  \
-                *(long *)(a) = *(long *)(b);            \
-                *(long *)(b) = t;                       \
-        } else                                          \
-                swapfunc(a, b, es, swaptype)
-
-#define vecswap(a, b, n)        if ((n) > 0) swapfunc(a, b, n, swaptype)
-
-#ifdef I_AM_QSORT_R
-#define CMP(t, x, y) (cmp((t), (x), (y)))
-#else
-#define CMP(t, x, y) (cmp((x), (y)))
-#endif
-
-static inline char *
-med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
-#ifndef I_AM_QSORT_R
-__unused
-#endif
-)
-{
-        return CMP(thunk, a, b) < 0 ?
-               (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
-              :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
-}
-
-#ifdef I_AM_QSORT_R
-void
-qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
-#else
-#define thunk NULL
-void
-qsort(void *a, size_t n, size_t es, cmp_t *cmp)
-#endif
-{
-        char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
-        size_t d, r;
-        int cmp_result;
-        int swaptype, swap_cnt;
-
-loop:   SWAPINIT(a, es);
-        swap_cnt = 0;
-        if (n < 7) {
-                for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
-                        for (pl = pm;
-                             pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
-                             pl -= es)
-                                swap(pl, pl - es);
-                return;
-        }
-        pm = (char *)a + (n / 2) * es;
-        if (n > 7) {
-                pl = a;
-                pn = (char *)a + (n - 1) * es;
-                if (n > 40) {
-                        d = (n / 8) * es;
-                        pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
-                        pm = med3(pm - d, pm, pm + d, cmp, thunk);
-                        pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
-                }
-                pm = med3(pl, pm, pn, cmp, thunk);
-        }
-        swap(a, pm);
-        pa = pb = (char *)a + es;
-
-        pc = pd = (char *)a + (n - 1) * es;
-        for (;;) {
-                while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
-                        if (cmp_result == 0) {
-                                swap_cnt = 1;
-                                swap(pa, pb);
-                                pa += es;
-                        }
-                        pb += es;
-                }
-                while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
-                        if (cmp_result == 0) {
-                                swap_cnt = 1;
-                                swap(pc, pd);
-                                pd -= es;
-                        }
-                        pc -= es;
-                }
-                if (pb > pc)
-                        break;
-                swap(pb, pc);
-                swap_cnt = 1;
-                pb += es;
-                pc -= es;
-        }
-        if (swap_cnt == 0) {  /* Switch to insertion sort */
-                for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
-                        for (pl = pm;
-                             pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
-                             pl -= es)
-                                swap(pl, pl - es);
-                return;
-        }
-
-        pn = (char *)a + n * es;
-        r = min(pa - (char *)a, pb - pa);
-        vecswap(a, pb - r, r);
-        r = min(pd - pc, pn - pd - es);
-        vecswap(pb, pn - r, r);
-        if ((r = pb - pa) > es)
-#ifdef I_AM_QSORT_R
-                qsort_r(a, r / es, es, thunk, cmp);
-#else
-                qsort(a, r / es, es, cmp);
-#endif
-        if ((r = pd - pc) > es) {
-                /* Iterate rather than recurse to save stack space */
-                a = pn - r;
-                n = r / es;
-                goto loop;
-        }
-/*              qsort(pn - r, r / es, es, cmp);*/
-}
diff --git a/libc/stdlib/abs.c b/libc/stdlib/abs.c
new file mode 100644
index 000000000..4806d629d
--- /dev/null
+++ b/libc/stdlib/abs.c
@@ -0,0 +1,4 @@
+int abs(int a)
+{
+	return a>0 ? a : -a;
+}
diff --git a/libc/stdlib/atoi.c b/libc/stdlib/atoi.c
new file mode 100644
index 000000000..9baca7b89
--- /dev/null
+++ b/libc/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/stdlib/atol.c b/libc/stdlib/atol.c
new file mode 100644
index 000000000..140ea3ea3
--- /dev/null
+++ b/libc/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/stdlib/atoll.c b/libc/stdlib/atoll.c
new file mode 100644
index 000000000..b69304895
--- /dev/null
+++ b/libc/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/stdlib/bsearch.c b/libc/stdlib/bsearch.c
new file mode 100644
index 000000000..61d89367e
--- /dev/null
+++ b/libc/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/libc/stdlib/div.c b/libc/stdlib/div.c
new file mode 100644
index 000000000..e42c1f14f
--- /dev/null
+++ b/libc/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/stdlib/ecvt.c b/libc/stdlib/ecvt.c
new file mode 100644
index 000000000..48e70cd86
--- /dev/null
+++ b/libc/stdlib/ecvt.c
@@ -0,0 +1,19 @@
+#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);
+
+	return buf;
+}
diff --git a/libc/stdlib/fcvt.c b/libc/stdlib/fcvt.c
new file mode 100644
index 000000000..003aa5aaa
--- /dev/null
+++ b/libc/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 = 0;
+		if (n>14U) n = 14;
+		return "000000000000000"+14-n;
+	}
+
+	return ecvt(x, n-lz, dp, sign);
+}
diff --git a/libc/stdlib/gcvt.c b/libc/stdlib/gcvt.c
new file mode 100644
index 000000000..6c075e258
--- /dev/null
+++ b/libc/stdlib/gcvt.c
@@ -0,0 +1,8 @@
+#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/stdlib/imaxabs.c b/libc/stdlib/imaxabs.c
new file mode 100644
index 000000000..810018193
--- /dev/null
+++ b/libc/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/stdlib/imaxdiv.c b/libc/stdlib/imaxdiv.c
new file mode 100644
index 000000000..b2ce821f5
--- /dev/null
+++ b/libc/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/stdlib/labs.c b/libc/stdlib/labs.c
new file mode 100644
index 000000000..675b95b8e
--- /dev/null
+++ b/libc/stdlib/labs.c
@@ -0,0 +1,4 @@
+long labs(long a)
+{
+	return a>0 ? a : -a;
+}
diff --git a/libc/stdlib/ldiv.c b/libc/stdlib/ldiv.c
new file mode 100644
index 000000000..36eb960b0
--- /dev/null
+++ b/libc/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/stdlib/llabs.c b/libc/stdlib/llabs.c
new file mode 100644
index 000000000..bec4a03d6
--- /dev/null
+++ b/libc/stdlib/llabs.c
@@ -0,0 +1,4 @@
+long long llabs(long long a)
+{
+	return a>0 ? a : -a;
+}
diff --git a/libc/stdlib/lldiv.c b/libc/stdlib/lldiv.c
new file mode 100644
index 000000000..7aaf7a0e6
--- /dev/null
+++ b/libc/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/stdlib/qsort.c b/libc/stdlib/qsort.c
new file mode 100644
index 000000000..434d93507
--- /dev/null
+++ b/libc/stdlib/qsort.c
@@ -0,0 +1,215 @@
+/* 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. */
+
+#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 *);
+
+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, 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) >= 0 && (*cmp)(ar[0], rt) >= 0) {
+			break;
+		}
+		if((*cmp)(lf, rt) >= 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, 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]) <= 0) {
+			break;
+		}
+		if(!trusty && pshift > 1) {
+			rt = head - width;
+			lf = head - width - lp[pshift - 2];
+			if((*cmp)(rt, stepson) >= 0 || (*cmp)(lf, stepson) >= 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, pshift, lp);
+	}
+}
+
+void qsort(void *base, size_t nel, size_t width, cmpfun cmp)
+{
+	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, pshift, lp);
+			shr(p, 2);
+			pshift += 2;
+		} else {
+			if(lp[pshift - 1] >= high - head) {
+				trinkle(head, width, cmp, p, pshift, 0, lp);
+			} else {
+				sift(head, width, cmp, 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, 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, p, pshift + 1, 1, lp);
+			shl(p, 1);
+			p[0] |= 1;
+			trinkle(head - width, width, cmp, p, pshift, 1, lp);
+		}
+		head -= width;
+	}
+}
diff --git a/libc/stdlib/strtol.c b/libc/stdlib/strtol.c
new file mode 100644
index 000000000..4af0cf826
--- /dev/null
+++ b/libc/stdlib/strtol.c
@@ -0,0 +1,56 @@
+#include "../stdio/stdio_impl.h"
+#include "intscan.h"
+#include "../stdio/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)
+{
+	/* FIXME: use a helper function or macro to setup the FILE */
+	FILE f;
+	f.flags = 0;
+	f.buf = f.rpos = (void *)s;
+	if ((size_t)s > (size_t)-1/2)
+		f.rend = (void *)-1;
+	else
+		f.rend = (unsigned char *)s+(size_t)-1/2;
+	f.lock = -1;
+	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);
+}
diff --git a/libc/stdlib/wcstol.c b/libc/stdlib/wcstol.c
new file mode 100644
index 000000000..000e266a9
--- /dev/null
+++ b/libc/stdlib/wcstol.c
@@ -0,0 +1,82 @@
+#include "../stdio/stdio_impl.h"
+#include "intscan.h"
+#include "../stdio/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 = 0;
+	f.buf = buf + 4;
+	f.buf_size = sizeof buf - 4;
+	f.lock = -1;
+	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);
+}
-- 
GitLab