diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e38d132959a5c8bde9b8894da74abdcf2891b9e2..628873551f959d0205198db1da08ce4fbd5f53cb 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,27 +1,51 @@
-image: "rust:latest"
+image: "rustlang/rust:nightly"
+
+stages:
+    - build
+    - test
 
 before_script:
     - git submodule update --init --recursive
-    - rustup toolchain add nightly
-    - rustup target add x86_64-unknown-redox --toolchain nightly
+    - rustup toolchain add "$(cat rust-toolchain)"
+    - rustup target add x86_64-unknown-redox --toolchain "$(cat rust-toolchain)"
     - rustup show      # Print version info for debugging
 
+cache:
+    untracked: true
+
 build:linux:
+    stage: build
     script:
         - make all
 
-#build:redox:
-#    script:
-#        - make all
+build:redox:
+    stage: build
+    variables:
+        TARGET: x86_64-unknown-redox
+    script:
+        # Install x86_64-unknown-redox-gcc
+        # This can't be in before_script because that overrides
+        # the global before_script.
+        - apt-get update -qq
+        - apt-get install -qq apt-transport-https build-essential curl git gnupg software-properties-common
+        - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys AA12E97F0881517F
+        - add-apt-repository 'deb https://static.redox-os.org/toolchain/apt /'
+        - apt-get update -qq && apt-get install -qq x86-64-unknown-redox-gcc
+
+        # Main script
+        - make all
 
 test:linux:
+    stage: test
+    dependencies:
+        - build:linux
     script:
         - make test
+        - cd tests && make verify
 
 fmt:
+    stage: test
     script:
         - rustup component add rustfmt-preview
         - ./fmt.sh -- --check
-
-# TODO: Set up a docker image with a redox vm that would allow to
-#   run things like tests under redox
+    allow_failure: true
diff --git a/Cargo.lock b/Cargo.lock
index fa1be69c666916affd388ad2123c0518f2ceee60..23d4c6e1aa570dae5904c6e4457dea1cd16bf1dc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -304,6 +304,7 @@ dependencies = [
  "sys_wait 0.1.0",
  "time 0.1.0",
  "unistd 0.1.0",
+ "wchar 0.1.0",
  "wctype 0.1.0",
 ]
 
@@ -403,7 +404,7 @@ dependencies = [
  "errno 0.1.0",
  "fcntl 0.1.0",
  "platform 0.1.0",
- "stdlib 0.1.0",
+ "ralloc 1.0.0",
  "string 0.1.0",
  "va_list 0.1.0",
 ]
@@ -418,7 +419,9 @@ dependencies = [
  "platform 0.1.0",
  "ralloc 1.0.0",
  "rand 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "string 0.1.0",
  "time 0.1.0",
+ "wchar 0.1.0",
 ]
 
 [[package]]
@@ -428,7 +431,7 @@ dependencies = [
  "cbindgen 0.5.2",
  "errno 0.1.0",
  "platform 0.1.0",
- "stdlib 0.1.0",
+ "ralloc 1.0.0",
 ]
 
 [[package]]
@@ -606,6 +609,18 @@ name = "vec_map"
 version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "wchar"
+version = "0.1.0"
+dependencies = [
+ "cbindgen 0.5.2",
+ "errno 0.1.0",
+ "platform 0.1.0",
+ "stdio 0.1.0",
+ "time 0.1.0",
+ "va_list 0.1.0",
+]
+
 [[package]]
 name = "wctype"
 version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
index b64015bdad3e2207d9a35d5daa17fbf9e156b04b..9514720270cdd499596efb0a759e22f6a1d1bed7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -39,6 +39,7 @@ sys_utsname = { path = "src/sys_utsname" }
 sys_wait = { path = "src/sys_wait" }
 time = { path = "src/time" }
 unistd = { path = "src/unistd" }
+wchar = { path = "src/wchar" }
 wctype = { path = "src/wctype" }
 
 [dependencies.compiler_builtins]
diff --git a/Makefile b/Makefile
index 8ffd601d91c99da1d08080c2eb616fadf2a6ba80..39d1183a56e2142bab1012a0e7c492bf1fff0cf4 100644
--- a/Makefile
+++ b/Makefile
@@ -7,11 +7,11 @@ ifneq ($(TARGET),)
 endif
 
 ifeq ($(TARGET),aarch64-unknown-linux-gnu)
-	CC="aarch64-linux-gnu-gcc"
+	CC=aarch64-linux-gnu-gcc
 endif
 
 ifeq ($(TARGET),x86_64-unknown-redox)
-	CC="x86_64-unknown-redox-gcc"
+	CC=x86_64-unknown-redox-gcc
 endif
 
 SRC=\
diff --git a/fmt.sh b/fmt.sh
index 4e2cf0508534331239b0478c7240b15f8f6eef0d..cb5a928a33df8657a51debf0a0eb73b84cc3d5c7 100755
--- a/fmt.sh
+++ b/fmt.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 ARGS=()
 
 for crate in relibc $(find src -name Cargo.toml | cut -d '/' -f2 | grep -v template)
diff --git a/include/bits/unistd.h b/include/bits/unistd.h
new file mode 100644
index 0000000000000000000000000000000000000000..a7167d047a4988f8fce0372e674c4a4514663fb1
--- /dev/null
+++ b/include/bits/unistd.h
@@ -0,0 +1,7 @@
+#ifndef _BITS_UNISTD_H
+#define _BITS_UNISTD_H
+
+int execl(const char *path, const char* argv0, ...);
+int execle(const char *path, const char* argv0, ...);
+
+#endif
diff --git a/include/bits/wchar.h b/include/bits/wchar.h
index 98216dfb0fa5e22d686cd577f52e3fcd123faedf..eed486f1bcf3c6b39fc8b7bb55efbba72b98bbcb 100644
--- a/include/bits/wchar.h
+++ b/include/bits/wchar.h
@@ -1,7 +1,10 @@
 #ifndef _BITS_WCHAR_H
 #define _BITS_WCHAR_H
+#include <stdint.h>
 
-typedef signed short wchar_t;
-typedef signed int wint_t;
+#define WEOF (0xFFFFFFFFu)
+
+typedef int32_t wchar_t;
+typedef uint32_t wint_t;
 
 #endif /* _BITS_WCHAR_H */
diff --git a/include/stddef.h b/include/stddef.h
index fa0bc7daf528f082aab9958c1054fa0f716e9a03..1dc7f60fc1f57381b7323237c472de81c6cc86ed 100644
--- a/include/stddef.h
+++ b/include/stddef.h
@@ -1,11 +1,12 @@
 #ifndef _STDDEF_H
 #define _STDDEF_H
+#include <stdint.h>
 
 #define NULL 0
 
 typedef signed long long ptrdiff_t;
 
-typedef unsigned char wchar_t;
+typedef int32_t wchar_t;
 
 typedef unsigned long long size_t;
 
diff --git a/include/stdint.h b/include/stdint.h
index cbe5e37fe71a6271f17dc5e55f78e85a93930f2b..3a578783fa770e858d7bf2b25463f6ac62715438 100644
--- a/include/stdint.h
+++ b/include/stdint.h
@@ -1,130 +1,367 @@
+/* Copyright (C) 2008-2018 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/*
+ * ISO C Standard:  7.18  Integer types  <stdint.h>
+ */
+
 #ifndef _STDINT_H
 #define _STDINT_H
 
-#define INT8_C(value) ((int8_t) value)
-#define INT8_MIN -0x80
-#define INT8_MAX 0x7F
-typedef signed char int8_t;
-
-#define INT_LEAST8_MIN -0x80
-#define INT_LEAST8_MAX 0x7F
-typedef signed char int_least8_t;
-
-#define INT_FAST8_MIN -0x80
-#define INT_FAST8_MAX 0x7F
-typedef signed char int_fast8_t;
-
-#define UINT8_C(value) ((uint8_t) value ## U)
-#define UINT8_MIN 0x00
-#define UINT8_MAX 0xFF
-typedef unsigned char uint8_t;
-
-#define UINT_LEAST8_MIN 0x00
-#define UINT_LEAST8_MAX 0xFF
-typedef unsigned char uint_least8_t;
-
-#define UINT_FAST8_MIN 0x00
-#define UINT_FAST8_MAX 0xFF
-typedef unsigned char uint_fast8_t;
-
-#define INT16_C(value) value
-#define INT16_MIN -0x8000
-#define INT16_MAX 0x7FFF
-typedef signed short int16_t;
-
-#define INT_LEAST16_MIN -0x8000
-#define INT_LEAST16_MAX 0x7FFF
-typedef signed short int_least16_t;
-
-#define INT_FAST16_MIN -0x8000
-#define INT_FAST16_MAX 0x7FFF
-typedef signed short int_fast16_t;
-
-#define UINT16_C(value) value ## U
-#define UINT16_MIN 0x0000
-#define UINT16_MAX 0xFFFF
-typedef unsigned short uint16_t;
-
-#define UINT_LEAST16_MIN 0x0000
-#define UINT_LEAST16_MAX 0xFFFF
-typedef unsigned short uint_least16_t;
-
-#define UINT_FAST16_MIN 0x0000
-#define UINT_FAST16_MAX 0xFFFF
-typedef unsigned short uint_fast16_t;
-
-#define INT32_C(value) value ## L
-#define INT32_MIN -0x80000000
-#define INT32_MAX 0x7FFFFFFF
-typedef signed long int32_t;
-
-#define INT_LEAST32_MIN -0x80000000
-#define INT_LEAST32_MAX 0x7FFFFFFF
-typedef signed long int_least32_t;
-
-#define INT_FAST32_MIN -0x80000000
-#define INT_FAST32_MAX 0x7FFFFFFF
-typedef signed long int_fast32_t;
-
-#define UINT32_C(value) value ## UL
-#define UINT32_MIN 0x00000000
-#define UINT32_MAX 0xFFFFFFFF
-typedef unsigned long uint32_t;
-
-#define UINT_LEAST32_MIN 0x00000000
-#define UINT_LEAST32_MAX 0xFFFFFFFF
-typedef unsigned long uint_least32_t;
-
-#define UINT_FAST32_MIN 0x00000000
-#define UINT_FAST32_MAX 0xFFFFFFFF
-typedef unsigned long uint_fast32_t;
-
-#define INT64_C(value) value ## LL
-#define INT64_MIN -0x8000000000000000
-#define INT64_MAX 0x7FFFFFFFFFFFFFFF
-typedef signed long long int64_t;
-
-#define INT_LEAST64_MIN -0x8000000000000000
-#define INT_LEAST64_MAX 0x7FFFFFFFFFFFFFFF
-typedef signed long long int_least64_t;
-
-#define INT_FAST64_MIN -0x8000000000000000
-#define INT_FAST64_MAX 0x7FFFFFFFFFFFFFFF
-typedef signed long long int_fast64_t;
-
-#define UINT64_C(value) value ## ULL
-#define UINT64_MIN 0x0000000000000000
-#define UINT64_MAX 0xFFFFFFFFFFFFFFFF
-typedef unsigned long long uint64_t;
-
-#define UINT_LEAST64_MIN 0x0000000000000000
-#define UINT_LEAST64_MAX 0xFFFFFFFFFFFFFFFF
-typedef unsigned long long uint_least64_t;
-
-#define UINT_FAST64_MIN 0x0000000000000000
-#define UINT_FAST64_MAX 0xFFFFFFFFFFFFFFFF
-typedef unsigned long long uint_fast64_t;
-
-#define INTMAX_C(value) value ## LL
-#define INTMAX_MIN INT64_MIN
-#define INTMAX_MAX INT64_MAX
-typedef int64_t intmax_t;
-
-#define UINTMAX_C(value) value ## ULL
-#define UINTMAX_MIN UINT64_MIN
-#define UINTMAX_MAX UINT64_MAX
-typedef uint64_t uintmax_t;
-
-#define INTPTR_MIN INT64_MIN
-#define INTPTR_MAX INT64_MAX
-typedef int64_t intptr_t;
-
-#define UINTPTR_MIN UINT64_MIN
-#define UINTPTR_MAX UINT64_MAX
-typedef uint64_t uintptr_t;
+/* 7.8.1.1 Exact-width integer types */
+
+#ifdef __INT8_TYPE__
+typedef __INT8_TYPE__ int8_t;
+#endif
+#ifdef __INT16_TYPE__
+typedef __INT16_TYPE__ int16_t;
+#endif
+#ifdef __INT32_TYPE__
+typedef __INT32_TYPE__ int32_t;
+#endif
+#ifdef __INT64_TYPE__
+typedef __INT64_TYPE__ int64_t;
+#endif
+#ifdef __UINT8_TYPE__
+typedef __UINT8_TYPE__ uint8_t;
+#endif
+#ifdef __UINT16_TYPE__
+typedef __UINT16_TYPE__ uint16_t;
+#endif
+#ifdef __UINT32_TYPE__
+typedef __UINT32_TYPE__ uint32_t;
+#endif
+#ifdef __UINT64_TYPE__
+typedef __UINT64_TYPE__ uint64_t;
+#endif
+
+/* 7.8.1.2 Minimum-width integer types */
+
+typedef __INT_LEAST8_TYPE__ int_least8_t;
+typedef __INT_LEAST16_TYPE__ int_least16_t;
+typedef __INT_LEAST32_TYPE__ int_least32_t;
+typedef __INT_LEAST64_TYPE__ int_least64_t;
+typedef __UINT_LEAST8_TYPE__ uint_least8_t;
+typedef __UINT_LEAST16_TYPE__ uint_least16_t;
+typedef __UINT_LEAST32_TYPE__ uint_least32_t;
+typedef __UINT_LEAST64_TYPE__ uint_least64_t;
+
+/* 7.8.1.3 Fastest minimum-width integer types */
+
+typedef __INT_FAST8_TYPE__ int_fast8_t;
+typedef __INT_FAST16_TYPE__ int_fast16_t;
+typedef __INT_FAST32_TYPE__ int_fast32_t;
+typedef __INT_FAST64_TYPE__ int_fast64_t;
+typedef __UINT_FAST8_TYPE__ uint_fast8_t;
+typedef __UINT_FAST16_TYPE__ uint_fast16_t;
+typedef __UINT_FAST32_TYPE__ uint_fast32_t;
+typedef __UINT_FAST64_TYPE__ uint_fast64_t;
+
+/* 7.8.1.4 Integer types capable of holding object pointers */
+
+#ifdef __INTPTR_TYPE__
+typedef __INTPTR_TYPE__ intptr_t;
+#endif
+#ifdef __UINTPTR_TYPE__
+typedef __UINTPTR_TYPE__ uintptr_t;
+#endif
+
+/* 7.8.1.5 Greatest-width integer types */
+
+typedef __INTMAX_TYPE__ intmax_t;
+typedef __UINTMAX_TYPE__ uintmax_t;
+
+#if (!defined __cplusplus || __cplusplus >= 201103L \
+     || defined __STDC_LIMIT_MACROS)
+
+/* 7.18.2 Limits of specified-width integer types */
+
+#ifdef __INT8_MAX__
+# undef INT8_MAX
+# define INT8_MAX __INT8_MAX__
+# undef INT8_MIN
+# define INT8_MIN (-INT8_MAX - 1)
+#endif
+#ifdef __UINT8_MAX__
+# undef UINT8_MAX
+# define UINT8_MAX __UINT8_MAX__
+#endif
+#ifdef __INT16_MAX__
+# undef INT16_MAX
+# define INT16_MAX __INT16_MAX__
+# undef INT16_MIN
+# define INT16_MIN (-INT16_MAX - 1)
+#endif
+#ifdef __UINT16_MAX__
+# undef UINT16_MAX
+# define UINT16_MAX __UINT16_MAX__
+#endif
+#ifdef __INT32_MAX__
+# undef INT32_MAX
+# define INT32_MAX __INT32_MAX__
+# undef INT32_MIN
+# define INT32_MIN (-INT32_MAX - 1)
+#endif
+#ifdef __UINT32_MAX__
+# undef UINT32_MAX
+# define UINT32_MAX __UINT32_MAX__
+#endif
+#ifdef __INT64_MAX__
+# undef INT64_MAX
+# define INT64_MAX __INT64_MAX__
+# undef INT64_MIN
+# define INT64_MIN (-INT64_MAX - 1)
+#endif
+#ifdef __UINT64_MAX__
+# undef UINT64_MAX
+# define UINT64_MAX __UINT64_MAX__
+#endif
+
+#undef INT_LEAST8_MAX
+#define INT_LEAST8_MAX __INT_LEAST8_MAX__
+#undef INT_LEAST8_MIN
+#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1)
+#undef UINT_LEAST8_MAX
+#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__
+#undef INT_LEAST16_MAX
+#define INT_LEAST16_MAX __INT_LEAST16_MAX__
+#undef INT_LEAST16_MIN
+#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1)
+#undef UINT_LEAST16_MAX
+#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__
+#undef INT_LEAST32_MAX
+#define INT_LEAST32_MAX __INT_LEAST32_MAX__
+#undef INT_LEAST32_MIN
+#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1)
+#undef UINT_LEAST32_MAX
+#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__
+#undef INT_LEAST64_MAX
+#define INT_LEAST64_MAX __INT_LEAST64_MAX__
+#undef INT_LEAST64_MIN
+#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1)
+#undef UINT_LEAST64_MAX
+#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__
+
+#undef INT_FAST8_MAX
+#define INT_FAST8_MAX __INT_FAST8_MAX__
+#undef INT_FAST8_MIN
+#define INT_FAST8_MIN (-INT_FAST8_MAX - 1)
+#undef UINT_FAST8_MAX
+#define UINT_FAST8_MAX __UINT_FAST8_MAX__
+#undef INT_FAST16_MAX
+#define INT_FAST16_MAX __INT_FAST16_MAX__
+#undef INT_FAST16_MIN
+#define INT_FAST16_MIN (-INT_FAST16_MAX - 1)
+#undef UINT_FAST16_MAX
+#define UINT_FAST16_MAX __UINT_FAST16_MAX__
+#undef INT_FAST32_MAX
+#define INT_FAST32_MAX __INT_FAST32_MAX__
+#undef INT_FAST32_MIN
+#define INT_FAST32_MIN (-INT_FAST32_MAX - 1)
+#undef UINT_FAST32_MAX
+#define UINT_FAST32_MAX __UINT_FAST32_MAX__
+#undef INT_FAST64_MAX
+#define INT_FAST64_MAX __INT_FAST64_MAX__
+#undef INT_FAST64_MIN
+#define INT_FAST64_MIN (-INT_FAST64_MAX - 1)
+#undef UINT_FAST64_MAX
+#define UINT_FAST64_MAX __UINT_FAST64_MAX__
+
+#ifdef __INTPTR_MAX__
+# undef INTPTR_MAX
+# define INTPTR_MAX __INTPTR_MAX__
+# undef INTPTR_MIN
+# define INTPTR_MIN (-INTPTR_MAX - 1)
+#endif
+#ifdef __UINTPTR_MAX__
+# undef UINTPTR_MAX
+# define UINTPTR_MAX __UINTPTR_MAX__
+#endif
+
+#undef INTMAX_MAX
+#define INTMAX_MAX __INTMAX_MAX__
+#undef INTMAX_MIN
+#define INTMAX_MIN (-INTMAX_MAX - 1)
+#undef UINTMAX_MAX
+#define UINTMAX_MAX __UINTMAX_MAX__
+
+/* 7.18.3 Limits of other integer types */
+
+#undef PTRDIFF_MAX
+#define PTRDIFF_MAX __PTRDIFF_MAX__
+#undef PTRDIFF_MIN
+#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
+
+#undef SIG_ATOMIC_MAX
+#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
+#undef SIG_ATOMIC_MIN
+#define SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__
+
+#undef SIZE_MAX
+#define SIZE_MAX __SIZE_MAX__
+
+#undef WCHAR_MAX
+#define WCHAR_MAX __WCHAR_MAX__
+#undef WCHAR_MIN
+#define WCHAR_MIN __WCHAR_MIN__
+
+#undef WINT_MAX
+#define WINT_MAX __WINT_MAX__
+#undef WINT_MIN
+#define WINT_MIN __WINT_MIN__
+
+#endif /* (!defined __cplusplus || __cplusplus >= 201103L
+	   || defined __STDC_LIMIT_MACROS)  */
+
+#if (!defined __cplusplus || __cplusplus >= 201103L \
+     || defined __STDC_CONSTANT_MACROS)
+
+#undef INT8_C
+#define INT8_C(c) __INT8_C(c)
+#undef INT16_C
+#define INT16_C(c) __INT16_C(c)
+#undef INT32_C
+#define INT32_C(c) __INT32_C(c)
+#undef INT64_C
+#define INT64_C(c) __INT64_C(c)
+#undef UINT8_C
+#define UINT8_C(c) __UINT8_C(c)
+#undef UINT16_C
+#define UINT16_C(c) __UINT16_C(c)
+#undef UINT32_C
+#define UINT32_C(c) __UINT32_C(c)
+#undef UINT64_C
+#define UINT64_C(c) __UINT64_C(c)
+#undef INTMAX_C
+#define INTMAX_C(c) __INTMAX_C(c)
+#undef UINTMAX_C
+#define UINTMAX_C(c) __UINTMAX_C(c)
+
+#endif /* (!defined __cplusplus || __cplusplus >= 201103L
+	   || defined __STDC_CONSTANT_MACROS) */
+
+#ifdef __STDC_WANT_IEC_60559_BFP_EXT__
+/* TS 18661-1 widths of integer types.  */
+
+#ifdef __INT8_TYPE__
+# undef INT8_WIDTH
+# define INT8_WIDTH 8
+#endif
+#ifdef __UINT8_TYPE__
+# undef UINT8_WIDTH
+# define UINT8_WIDTH 8
+#endif
+#ifdef __INT16_TYPE__
+# undef INT16_WIDTH
+# define INT16_WIDTH 16
+#endif
+#ifdef __UINT16_TYPE__
+# undef UINT16_WIDTH
+# define UINT16_WIDTH 16
+#endif
+#ifdef __INT32_TYPE__
+# undef INT32_WIDTH
+# define INT32_WIDTH 32
+#endif
+#ifdef __UINT32_TYPE__
+# undef UINT32_WIDTH
+# define UINT32_WIDTH 32
+#endif
+#ifdef __INT64_TYPE__
+# undef INT64_WIDTH
+# define INT64_WIDTH 64
+#endif
+#ifdef __UINT64_TYPE__
+# undef UINT64_WIDTH
+# define UINT64_WIDTH 64
+#endif
+
+#undef INT_LEAST8_WIDTH
+#define INT_LEAST8_WIDTH __INT_LEAST8_WIDTH__
+#undef UINT_LEAST8_WIDTH
+#define UINT_LEAST8_WIDTH __INT_LEAST8_WIDTH__
+#undef INT_LEAST16_WIDTH
+#define INT_LEAST16_WIDTH __INT_LEAST16_WIDTH__
+#undef UINT_LEAST16_WIDTH
+#define UINT_LEAST16_WIDTH __INT_LEAST16_WIDTH__
+#undef INT_LEAST32_WIDTH
+#define INT_LEAST32_WIDTH __INT_LEAST32_WIDTH__
+#undef UINT_LEAST32_WIDTH
+#define UINT_LEAST32_WIDTH __INT_LEAST32_WIDTH__
+#undef INT_LEAST64_WIDTH
+#define INT_LEAST64_WIDTH __INT_LEAST64_WIDTH__
+#undef UINT_LEAST64_WIDTH
+#define UINT_LEAST64_WIDTH __INT_LEAST64_WIDTH__
+
+#undef INT_FAST8_WIDTH
+#define INT_FAST8_WIDTH __INT_FAST8_WIDTH__
+#undef UINT_FAST8_WIDTH
+#define UINT_FAST8_WIDTH __INT_FAST8_WIDTH__
+#undef INT_FAST16_WIDTH
+#define INT_FAST16_WIDTH __INT_FAST16_WIDTH__
+#undef UINT_FAST16_WIDTH
+#define UINT_FAST16_WIDTH __INT_FAST16_WIDTH__
+#undef INT_FAST32_WIDTH
+#define INT_FAST32_WIDTH __INT_FAST32_WIDTH__
+#undef UINT_FAST32_WIDTH
+#define UINT_FAST32_WIDTH __INT_FAST32_WIDTH__
+#undef INT_FAST64_WIDTH
+#define INT_FAST64_WIDTH __INT_FAST64_WIDTH__
+#undef UINT_FAST64_WIDTH
+#define UINT_FAST64_WIDTH __INT_FAST64_WIDTH__
+
+#ifdef __INTPTR_TYPE__
+# undef INTPTR_WIDTH
+# define INTPTR_WIDTH __INTPTR_WIDTH__
+#endif
+#ifdef __UINTPTR_TYPE__
+# undef UINTPTR_WIDTH
+# define UINTPTR_WIDTH __INTPTR_WIDTH__
+#endif
+
+#undef INTMAX_WIDTH
+#define INTMAX_WIDTH __INTMAX_WIDTH__
+#undef UINTMAX_WIDTH
+#define UINTMAX_WIDTH __INTMAX_WIDTH__
+
+#undef PTRDIFF_WIDTH
+#define PTRDIFF_WIDTH __PTRDIFF_WIDTH__
+
+#undef SIG_ATOMIC_WIDTH
+#define SIG_ATOMIC_WIDTH __SIG_ATOMIC_WIDTH__
+
+#undef SIZE_WIDTH
+#define SIZE_WIDTH __SIZE_WIDTH__
+
+#undef WCHAR_WIDTH
+#define WCHAR_WIDTH __WCHAR_WIDTH__
+
+#undef WINT_WIDTH
+#define WINT_WIDTH __WINT_WIDTH__
 
 #define SIZE_MAX UINT64_MAX
+#endif
 
 typedef long sig_atomic_t;
 
-#endif /* _STDINT_H */
+#endif /* _GCC_STDINT_H */
diff --git a/rustfmt.toml b/rustfmt.toml
index d52a68e960ed52d6efadc8fdbc63907b8f2c1069..5780cc6e08c5d0a433f49497d1c1b6b214a50ddc 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -9,19 +9,13 @@ fn_single_line = false
 where_single_line = false
 imports_indent = "Visual"
 imports_layout = "Mixed"
-reorder_extern_crates = true
-reorder_extern_crates_in_group = true
 reorder_imports = false
-reorder_imported_names = true
-spaces_within_parens_and_brackets = false
-remove_blank_lines_at_start_or_end_of_block = true
 fn_args_density = "Tall"
 brace_style = "SameLineWhere"
 trailing_comma = "Vertical"
 blank_lines_upper_bound = 1
 blank_lines_lower_bound = 0
 force_explicit_abi = true
-write_mode = "Overwrite"
 disable_all_formatting = false
 skip_children = false
 hide_parse_errors = false
diff --git a/include/bits/exec.h b/src/c/unistd.c
similarity index 83%
rename from include/bits/exec.h
rename to src/c/unistd.c
index 94024518ba8fd7999a7b8902e357810504a1191f..a2a78ce727dc9d161c8d6c55213bcd0c72a24bcf 100644
--- a/include/bits/exec.h
+++ b/src/c/unistd.c
@@ -1,5 +1,7 @@
-#ifndef _BITS_EXEC_H
-#define _BITS_EXEC_H
+#include <stdarg.h>
+#include <stddef.h>
+
+int execv(const char *path, char *const *argv);
 
 int execl(const char *path, const char* argv0, ...)
 {
@@ -22,6 +24,8 @@ int execl(const char *path, const char* argv0, ...)
 	}
 }
 
+int execve(const char *path, char *const *argv, char *const *envp);
+
 int execle(const char *path, const char* argv0, ...)
 {
 	int argc;
diff --git a/src/inttypes/src/lib.rs b/src/inttypes/src/lib.rs
index 0ceb7bc55bab48d76beee4e7ed006ac2feceb045..ff2007a2138743c26a33e97bfc720d0164a1126b 100644
--- a/src/inttypes/src/lib.rs
+++ b/src/inttypes/src/lib.rs
@@ -1,3 +1,5 @@
+#![no_std]
+
 #[macro_use] extern crate stdlib;
 extern crate ctype;
 extern crate errno;
diff --git a/src/lib.rs b/src/lib.rs
index 7c9f060b592f915d747a2a50246bfa5168d86175..558f7764d8ae759a39038fd085579f18d3096b10 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -29,6 +29,7 @@ pub extern crate sys_utsname;
 pub extern crate sys_wait;
 pub extern crate time;
 pub extern crate unistd;
+pub extern crate wchar;
 pub extern crate wctype;
 
 #[cfg(not(test))]
diff --git a/src/platform/Cargo.toml b/src/platform/Cargo.toml
index dd5ba725ac56ffd3eb4431e3df80d7b94791eff0..e25b8251c0c6bb44761c2f5a8af2e7eda0c70881 100644
--- a/src/platform/Cargo.toml
+++ b/src/platform/Cargo.toml
@@ -8,6 +8,3 @@ sc = "0.2"
 
 [target.'cfg(target_os = "redox")'.dependencies]
 redox_syscall = "0.1"
-
-[dependencies]
-ralloc = { path = "../../ralloc" }
diff --git a/src/platform/src/lib.rs b/src/platform/src/lib.rs
index 185354ff856fdeb481e9b678eac235bed344ffa9..1838b29edd05177f16eaa3d985a158f888e6fc0a 100644
--- a/src/platform/src/lib.rs
+++ b/src/platform/src/lib.rs
@@ -2,8 +2,6 @@
 
 #![no_std]
 #![allow(non_camel_case_types)]
-#![feature(alloc)]
-#![feature(global_allocator)]
 //TODO #![feature(thread_local)]
 
 #[cfg(all(not(feature = "no_std"), target_os = "linux"))]
@@ -24,17 +22,12 @@ mod sys;
 #[path = "redox/mod.rs"]
 mod sys;
 
-extern crate alloc;
-extern crate ralloc;
-
 pub mod types;
 
 use core::fmt;
 
 use types::*;
 
-#[global_allocator]
-static ALLOCATOR: ralloc::Allocator = ralloc::Allocator;
 //TODO #[thread_local]
 #[allow(non_upper_case_globals)]
 #[no_mangle]
diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs
index 71019375f7c9f4400a34fe805bb1e8ac77a4a02e..b72e5d72b6c054cfa436297bce67183a75d2837d 100644
--- a/src/platform/src/redox/mod.rs
+++ b/src/platform/src/redox/mod.rs
@@ -1,7 +1,6 @@
 use core::ptr;
 use core::slice;
 use core::mem;
-use alloc::Vec;
 use syscall;
 use syscall::flag::*;
 use syscall::data::TimeSpec as redox_timespec;
@@ -68,58 +67,6 @@ pub fn dup2(fd1: c_int, fd2: c_int) -> c_int {
     e(syscall::dup2(fd1 as usize, fd2 as usize, &[])) as c_int
 }
 
-pub fn execve(path: *const c_char, argv: *const *mut c_char, envp: *const *mut c_char) -> c_int {
-    unsafe {
-        let mut env = envp;
-        while !(*env).is_null() {
-            let slice = c_str(*env);
-            // Should always contain a =, but worth checking
-            if let Some(sep) = slice.iter().position(|&c| c == b'=') {
-                // If the environment variable has no name, do not attempt
-                // to add it to the env.
-                if sep > 0 {
-                    let mut path = b"env:".to_vec();
-                    path.extend_from_slice(&slice[..sep]);
-                    match syscall::open(&path, O_WRONLY | O_CREAT) {
-                        Ok(fd) => {
-                            // If the environment variable has no value, there
-                            // is no need to write anything to the env scheme.
-                            if sep + 1 < slice.len() {
-                                let n = match syscall::write(fd, &slice[sep + 1..]) {
-                                    Ok(n) => n,
-                                    err => {
-                                        return e(err) as c_int;
-                                    }
-                                };
-                            }
-                            // Cleanup after adding the variable.
-                            match syscall::close(fd) {
-                                Ok(_) => (),
-                                err => {
-                                    return e(err) as c_int;
-                                }
-                            }
-                        }
-                        err => {
-                            return e(err) as c_int;
-                        }
-                    }
-                }
-            }
-            env = env.offset(1);
-        }
-
-        let mut args: Vec<[usize; 2]> = Vec::new();
-        let mut arg = argv;
-        while !(*arg).is_null() {
-            args.push([*arg as usize, c_str(*arg).len()]);
-            arg = arg.offset(1);
-        }
-
-        e(syscall::execve(c_str(path), &args)) as c_int
-    }
-}
-
 pub fn exit(status: c_int) -> ! {
     let _ = syscall::exit(status as usize);
     loop {}
diff --git a/src/platform/src/types.rs b/src/platform/src/types.rs
index 29ed354d1b543470513c0f47cc2844176358fa06..61b1fea30dee89c0496232c9275a1f3205a288c1 100644
--- a/src/platform/src/types.rs
+++ b/src/platform/src/types.rs
@@ -44,8 +44,8 @@ pub type c_char = i8;
 pub type c_long = i64;
 pub type c_ulong = u64;
 
-pub type wchar_t = i16;
-pub type wint_t = i32;
+pub type wchar_t = i32;
+pub type wint_t = u32;
 pub type wctype_t = i64;
 
 pub type off_t = i64;
diff --git a/src/setjmp/src/impl/bin/.gitignore b/src/setjmp/src/impl/bin/.gitignore
deleted file mode 100644
index d6b7ef32c8478a48c3994dcadc86837f4371184d..0000000000000000000000000000000000000000
--- a/src/setjmp/src/impl/bin/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/src/stdio/Cargo.toml b/src/stdio/Cargo.toml
index 1f2f2794e94243c98145156a658c5ccd28095b98..27fbe42bc7eaccfac21d736d8b85de209f2a8a36 100644
--- a/src/stdio/Cargo.toml
+++ b/src/stdio/Cargo.toml
@@ -12,7 +12,7 @@ errno = { path = "../errno"}
 fcntl = { path = "../fcntl" }
 lazy_static = { version = "*", features = ["nightly", "spin_no_std"] }
 platform = { path = "../platform" }
-ralloc = { path = "../../ralloc" }
+ralloc = { path = "../../ralloc", default-features = false }
 string = { path = "../string" }
 stdlib = { path = "../stdlib" }
 va_list = { path = "../../va_list", features = ["no_std"] }
diff --git a/src/stdio/src/helpers.rs b/src/stdio/src/helpers.rs
index 242e83f1ec4e164b004748bff093bca85169eae2..3e898a24b5cd8fabed410ce0e5e32bdd90a4446a 100644
--- a/src/stdio/src/helpers.rs
+++ b/src/stdio/src/helpers.rs
@@ -1,4 +1,6 @@
-use super::{BUFSIZ, FILE, UNGET};
+use super::{internal, BUFSIZ, FILE, UNGET};
+use ralloc;
+use core::{mem, ptr};
 use core::sync::atomic::AtomicBool;
 use platform::types::*;
 use super::constants::*;
@@ -62,8 +64,8 @@ pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> Option<*mut FILE> {
         flags |= F_APP;
     }
 
+    let f = ralloc::alloc(mem::size_of::<FILE>(), 1) as *mut FILE;
     // Allocate the file
-    let f = malloc(size_of::<FILE>()) as *mut FILE;
     if f.is_null() {
         None
     } else {
diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs
index e3e23d8c21625c3e7417b678871bbec9f5d8813c..317d5c9a980370c12494ae9f51c09bfd796d6dc9 100644
--- a/src/stdio/src/lib.rs
+++ b/src/stdio/src/lib.rs
@@ -12,12 +12,11 @@ extern crate fcntl;
 #[macro_use]
 extern crate lazy_static;
 extern crate platform;
-extern crate stdlib;
+extern crate ralloc;
 extern crate string;
 extern crate va_list as vl;
 
-use core::str;
-use core::ptr;
+use core::{str,ptr,mem};
 use core::fmt::{self, Error, Result};
 use core::fmt::Write as WriteFmt;
 use core::sync::atomic::{AtomicBool, Ordering};
@@ -28,8 +27,8 @@ use platform::{c_str, errno, Read, Write};
 use alloc::vec::Vec;
 use vl::VaList as va_list;
 
-mod scanf;
 mod printf;
+mod scanf;
 
 mod default;
 pub use default::*;
@@ -214,13 +213,16 @@ pub extern "C" fn cuserid(_s: *mut c_char) -> *mut c_char {
 /// prior to using this function.
 #[no_mangle]
 pub extern "C" fn fclose(stream: &mut FILE) -> c_int {
-    use stdlib::free;
+    use ralloc::free;
     flockfile(stream);
     let r = helpers::fflush_unlocked(stream) | platform::close(stream.fd);
     if stream.flags & constants::F_PERM == 0 {
         // Not one of stdin, stdout or stderr
         unsafe {
-            free(stream as *mut _ as *mut _);
+            free(
+                stream as *mut _ as *mut _,
+                mem::size_of::<FILE>() + BUFSIZ + UNGET,
+            );
         }
     } else {
         funlockfile(stream);
@@ -897,5 +899,9 @@ pub unsafe extern "C" fn vscanf(format: *const c_char, ap: va_list) -> c_int {
 
 #[no_mangle]
 pub unsafe extern "C" fn vsscanf(s: *const c_char, format: *const c_char, ap: va_list) -> c_int {
-    scanf::scanf(&mut platform::UnsafeStringReader(s as *const u8), format, ap)
+    scanf::scanf(
+        &mut platform::UnsafeStringReader(s as *const u8),
+        format,
+        ap,
+    )
 }
diff --git a/src/stdlib/Cargo.toml b/src/stdlib/Cargo.toml
index 97ed4e9dfe4237934303f1326c68d5fe088b66ac..1122990e1d1261c12f2659f63406591b1878548c 100644
--- a/src/stdlib/Cargo.toml
+++ b/src/stdlib/Cargo.toml
@@ -14,3 +14,5 @@ ctype = { path = "../ctype" }
 errno = { path = "../errno" }
 rand = { version = "0.5.2", default-features = false }
 time = { path = "../time" }
+wchar = { path = "../wchar" }
+string = { path = "../string" }
\ No newline at end of file
diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs
index ff5404d56dc1307331fbc3db06798a47645e8eb6..50eadb2eec0490bdb5619d6717dcf4ed2d3e9253 100644
--- a/src/stdlib/src/lib.rs
+++ b/src/stdlib/src/lib.rs
@@ -9,12 +9,16 @@ extern crate platform;
 extern crate ralloc;
 extern crate rand;
 extern crate time;
+extern crate wchar;
+extern crate string;
 
 use core::{ptr, str};
-use rand::{Rng, SeedableRng}; 
+use rand::{Rng, SeedableRng};
 use rand::rngs::JitterRng;
 use rand::prng::XorShiftRng;
 use rand::distributions::Alphanumeric;
+use wchar::*;
+use string::*;
 
 use errno::*;
 use platform::types::*;
@@ -28,6 +32,11 @@ pub const EXIT_FAILURE: c_int = 1;
 pub const EXIT_SUCCESS: c_int = 0;
 pub const RAND_MAX: c_int = 2147483647;
 
+//Maximum number of bytes in a multibyte character for the current locale
+pub const MB_CUR_MAX: c_int = 4;
+//Maximum number of bytes in a multibyte characters for any locale
+pub const MB_LEN_MAX: c_int = 4;
+
 static mut ATEXIT_FUNCS: [Option<extern "C" fn()>; 32] = [None; 32];
 static mut RNG: Option<XorShiftRng> = None;
 
@@ -101,7 +110,7 @@ pub unsafe extern "C" fn atof(s: *const c_char) -> c_double {
 }
 
 macro_rules! dec_num_from_ascii {
-    ($s: expr, $t: ty) => {
+    ($s:expr, $t:ty) => {
         unsafe {
             let mut s = $s;
             // Iterate past whitespace
@@ -351,8 +360,19 @@ pub unsafe extern "C" fn memalign(alignment: size_t, size: size_t) -> *mut c_voi
 }
 
 #[no_mangle]
-pub extern "C" fn mblen(s: *const c_char, n: size_t) -> c_int {
-    unimplemented!();
+pub unsafe extern "C" fn mblen(s: *const c_char, n: size_t) -> c_int {
+    let mut wc : wchar_t = 0;
+    let mut state : mbstate_t = mbstate_t { };
+	let result : usize = mbrtowc(&mut wc, s, n, &mut state);
+
+	if result == -1isize as usize {
+        return -1;
+    }
+	if result == -2isize as usize {
+        return -1;
+    }
+		
+	result as i32
 }
 
 #[no_mangle]
@@ -370,16 +390,13 @@ pub extern "C" fn mktemp(name: *mut c_char) -> *mut c_char {
     use core::slice;
     use core::iter;
     use core::mem;
-    extern "C" {
-        fn strlen(s: *const c_char) -> size_t;
-    }
     let len = unsafe { strlen(name) };
     if len < 6 {
         unsafe { platform::errno = errno::EINVAL };
         unsafe { *name = 0 };
         return name;
     }
-    for i in len-6..len {
+    for i in len - 6..len {
         if unsafe { *name.offset(i as isize) } != b'X' as c_char {
             unsafe { platform::errno = errno::EINVAL };
             unsafe { *name = 0 };
@@ -392,11 +409,9 @@ pub extern "C" fn mktemp(name: *mut c_char) -> *mut c_char {
 
     let mut retries = 100;
     loop {
-        let mut char_iter = iter::repeat(())
-        .map(|()| rng.sample(Alphanumeric))
-        .take(6);
+        let mut char_iter = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(6);
         unsafe {
-            for (i,c) in char_iter.enumerate() {
+            for (i, c) in char_iter.enumerate() {
                 *name.offset(len as isize - i as isize - 1) = c as c_char
             }
         }
@@ -404,13 +419,17 @@ pub extern "C" fn mktemp(name: *mut c_char) -> *mut c_char {
         unsafe {
             let mut st: stat = mem::uninitialized();
             if platform::stat(name, &mut st) != 0 {
-                if platform::errno != ENOENT { *name = 0; }
+                if platform::errno != ENOENT {
+                    *name = 0;
+                }
                 return name;
             }
             mem::forget(st);
         }
-        retries = retries -1;
-        if retries == 0 { break; }
+        retries = retries - 1;
+        if retries == 0 {
+            break;
+        }
     }
     unsafe { platform::errno = EEXIST };
     unsafe { *name = 0 };
@@ -421,11 +440,10 @@ fn get_nstime() -> u64 {
     use core::mem;
     use time::constants::CLOCK_MONOTONIC;
     let mut ts: timespec = unsafe { mem::uninitialized() };
-    platform::clock_gettime(CLOCK_MONOTONIC, &mut ts); 
+    platform::clock_gettime(CLOCK_MONOTONIC, &mut ts);
     unsafe { ts.tv_nsec as u64 }
 }
 
-
 #[no_mangle]
 pub extern "C" fn mkstemp(name: *mut c_char) -> c_int {
     unimplemented!();
@@ -639,7 +657,8 @@ pub fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong, isize,
         if val == -1 || val as c_int >= base {
             break;
         } else {
-            if let Some(res) = num.checked_mul(base as c_ulong)
+            if let Some(res) = num
+                .checked_mul(base as c_ulong)
                 .and_then(|num| num.checked_add(val as c_ulong))
             {
                 num = res;
@@ -665,13 +684,7 @@ pub fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong, isize,
 #[macro_export]
 macro_rules! strto_impl {
     (
-        $rettype:ty,
-        $signed:expr,
-        $maxval:expr,
-        $minval:expr,
-        $s:ident,
-        $endptr:ident,
-        $base:ident
+        $rettype:ty, $signed:expr, $maxval:expr, $minval:expr, $s:ident, $endptr:ident, $base:ident
     ) => {{
         // ensure these are constants
         const CHECK_SIGN: bool = $signed;
@@ -721,9 +734,8 @@ macro_rules! strto_impl {
         // convert the string to a number
         let num_str = $s.offset(idx);
         let res = match $base {
-            0 => detect_base(num_str).and_then(|($base, i)| {
-                convert_integer(num_str.offset(i), $base)
-            }),
+            0 => detect_base(num_str)
+                .and_then(|($base, i)| convert_integer(num_str.offset(i), $base)),
             8 => convert_octal(num_str),
             16 => convert_hex(num_str),
             _ => convert_integer(num_str, $base),
@@ -770,15 +782,15 @@ macro_rules! strto_impl {
         set_endptr(idx);
 
         num
-    }}
+    }};
 }
 
-
 #[no_mangle]
-pub unsafe extern "C" fn strtoul(s: *const c_char,
-                                 endptr: *mut *mut c_char,
-                                 base: c_int)
-                                 -> c_ulong {
+pub unsafe extern "C" fn strtoul(
+    s: *const c_char,
+    endptr: *mut *mut c_char,
+    base: c_int,
+) -> c_ulong {
     strto_impl!(
         c_ulong,
         false,
@@ -791,10 +803,7 @@ pub unsafe extern "C" fn strtoul(s: *const c_char,
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn strtol(s: *const c_char,
-                                endptr: *mut *mut c_char,
-                                base: c_int)
-                                -> c_long {
+pub unsafe extern "C" fn strtol(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long {
     strto_impl!(
         c_long,
         true,
@@ -835,11 +844,22 @@ pub unsafe extern "C" fn valloc(size: size_t) -> *mut c_void {
 }
 
 #[no_mangle]
-pub extern "C" fn wcstombs(s: *mut c_char, pwcs: *const wchar_t, n: size_t) -> size_t {
-    unimplemented!();
+pub extern "C" fn wcstombs(s: *mut c_char, pwcs: *mut *const wchar_t, n: size_t) -> size_t {
+    let mut state: mbstate_t = mbstate_t {};
+    wcsrtombs(s, pwcs, n, &mut state)
 }
 
 #[no_mangle]
-pub extern "C" fn wctomb(s: *mut c_char, wchar: wchar_t) -> c_int {
-    unimplemented!();
+pub unsafe extern "C" fn wctomb(s: *mut c_char, wc: wchar_t) -> c_int {
+    let mut state : mbstate_t = mbstate_t {};
+    let result: usize = wcrtomb(s, wc, &mut state);
+
+    if result == -1isize as usize {
+        return -1;
+    }
+    if result == -2isize as usize {
+        return -1;
+    }
+
+    result as c_int
 }
diff --git a/src/string/Cargo.toml b/src/string/Cargo.toml
index 9bf1d9dc99edd2d756c893a1efa89690858ce757..f134d7ff7a43a9a6ba5c93beeb21c917895af4be 100644
--- a/src/string/Cargo.toml
+++ b/src/string/Cargo.toml
@@ -9,5 +9,5 @@ cbindgen = { path = "../../cbindgen" }
 
 [dependencies]
 platform = { path = "../platform" }
-stdlib = { path = "../stdlib" }
+ralloc = { path = "../../ralloc", default-features = false }
 errno = { path = "../errno" }
diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs
index 681bbe2b8f9d6c1585213e5910fb30b434089447..601b3385d80c913194c02600bb3018868a272544 100644
--- a/src/string/src/lib.rs
+++ b/src/string/src/lib.rs
@@ -1,10 +1,9 @@
 //! string implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/string.h.html
-
 #![no_std]
 
 extern crate errno;
 extern crate platform;
-extern crate stdlib;
+extern crate ralloc;
 
 use platform::types::*;
 use errno::*;
@@ -193,7 +192,7 @@ pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char
     let len = strnlen(s1, size);
 
     // the "+ 1" is to account for the NUL byte
-    let buffer = stdlib::malloc(len + 1) as *mut c_char;
+    let buffer = ralloc::alloc(len + 1, 1) as *mut c_char;
     if buffer.is_null() {
         platform::errno = ENOMEM as c_int;
     } else {
diff --git a/src/sys_utsname/src/lib.rs b/src/sys_utsname/src/lib.rs
index a0792dd564fef80c4c2b5c3882dfb11aca623f83..0bb0da2ed372eaca9fa0a57c8d39df6dcbcc8f1e 100644
--- a/src/sys_utsname/src/lib.rs
+++ b/src/sys_utsname/src/lib.rs
@@ -1,28 +1,32 @@
 //! sys/utsname implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysutsname.h.html
 
 #![no_std]
-#![cfg(target_os = "linux")]
 
-extern crate platform;
+#[cfg(target_os = "linux")]
+mod inner {
+    extern crate platform;
 
-use core::ptr;
-use platform::types::*;
+    use core::ptr;
+    use self::platform::types::*;
 
-const LENGTH: usize = 65;
+    const LENGTH: usize = 65;
 
-#[allow(non_camel_case)]
-#[no_mangle]
-#[repr(C)]
-pub struct utsname {
-    pub sysname:    [c_char; LENGTH],
-    pub nodename:   [c_char; LENGTH],
-    pub release:    [c_char; LENGTH],
-    pub version:    [c_char; LENGTH],
-    pub machine:    [c_char; LENGTH],
-    pub domainname: [c_char; LENGTH]
-}
+    #[allow(non_camel_case)]
+    #[no_mangle]
+    #[repr(C)]
+    pub struct utsname {
+        pub sysname:    [c_char; LENGTH],
+        pub nodename:   [c_char; LENGTH],
+        pub release:    [c_char; LENGTH],
+        pub version:    [c_char; LENGTH],
+        pub machine:    [c_char; LENGTH],
+        pub domainname: [c_char; LENGTH]
+    }
 
-#[no_mangle]
-pub unsafe extern "C" fn uname(uts: *mut utsname) -> c_int {
-    platform::uname(uts as usize)
+    #[no_mangle]
+    pub unsafe extern "C" fn uname(uts: *mut utsname) -> c_int {
+        platform::uname(uts as usize)
+    }
 }
+#[cfg(target_os = "linux")]
+pub use inner::*;
diff --git a/src/todo/wchar/lib.rs b/src/todo/wchar/lib.rs
deleted file mode 100644
index b760fba7aafb1f9ed785fcd6c99086d359816c3e..0000000000000000000000000000000000000000
--- a/src/todo/wchar/lib.rs
+++ /dev/null
@@ -1,377 +0,0 @@
-pub type wchar_t = libc::c_int;
-pub type wint_t = libc::c_uint;
-
-#[no_mangle]
-pub extern "C" fn btowc(c: libc::c_int) -> wint_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn fwprintf(stream: *mut FILE, format: *const wchar_t, ...)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn fwscanf(stream: *mut FILE, format: *const wchar_t, ...)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn iswalnum(wc: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn iswalpha(wc: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn iswcntrl(wc: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn iswdigit(wc: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn iswgraph(wc: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn iswlower(wc: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn iswprint(wc: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn iswpunct(wc: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn iswspace(wc: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn iswupper(wc: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn iswxdigit(wc: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn fgetwc(stream: *mut FILE) -> wint_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn fgetws(ws: *mut wchar_t, n: libc::c_int,
-                  stream: *mut FILE) -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn fputwc(wc: wchar_t, stream: *mut FILE) -> wint_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn fputws(ws: *const wchar_t, stream: *mut FILE)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn fwide(stream: *mut FILE, mode: libc::c_int)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn getwc(stream: *mut FILE) -> wint_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn getwchar() -> wint_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn mbsinit(ps: *const mbstate_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn mbrlen(s: *const libc::c_char, n: usize,
-                  ps: *mut mbstate_t) -> usize {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn mbrtowc(pwc: *mut wchar_t, s: *const libc::c_char,
-                   n: usize, ps: *mut mbstate_t) -> usize {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn mbsrtowcs(dst: *mut wchar_t,
-                     src: *mut *const libc::c_char, len: usize,
-                     ps: *mut mbstate_t) -> usize {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn putwc(wc: wchar_t, stream: *mut FILE) -> wint_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn putwchar(wc: wchar_t) -> wint_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn swprintf(s: *mut wchar_t, n: usize,
-                    format: *const wchar_t, ...) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn swscanf(s: *const wchar_t, format: *const wchar_t, ...)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn towlower(wc: wint_t) -> wint_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn towupper(wc: wint_t) -> wint_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn ungetwc(wc: wint_t, stream: *mut FILE) -> wint_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn vfwprintf(stream: *mut FILE, format: *const wchar_t,
-                   arg: va_list) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn vwprintf(format: *const wchar_t, arg: va_list)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn vswprintf(s: *mut wchar_t, n: usize, format: *const wchar_t,
-                     arg: va_list) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcrtomb(s: *mut libc::c_char, wc: wchar_t,
-                   ps: *mut mbstate_t) -> usize {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcscat(ws1: *mut wchar_t, ws2: *const wchar_t) -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcschr(ws1: *const wchar_t, ws2: wchar_t)
-     -> *mut libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcscmp(ws1: *const wchar_t, ws2: *const wchar_t)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcscoll(ws1: *const wchar_t, ws2: *const wchar_t)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcscpy(ws1: *mut wchar_t, ws2: *const wchar_t) -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcscspn(ws1: *const wchar_t, ws2: *const wchar_t) -> usize {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcsftime(wcs: *mut wchar_t, maxsize: usize, format: *const wchar_t,
-                    timptr: *mut tm) -> usize {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcslen(ws: *const wchar_t) -> libc::c_ulong {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcsncat(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize)
-     -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcsncmp(ws1: *const wchar_t, ws2: *const wchar_t, n: usize)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcsncpy(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize)
-     -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcspbrk(ws1: *const wchar_t, ws2: *const wchar_t)
-     -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcsrchr(ws1: *const wchar_t, ws2: wchar_t) -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcsrtombs(dst: *mut libc::c_char,
-                     src: *mut *const wchar_t, len: usize,
-                     ps: *mut mbstate_t) -> usize {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcsspn(ws1: *const wchar_t, ws2: *const wchar_t) -> usize {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcsstr(ws1: *const wchar_t, ws2: *const wchar_t) -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcstod(nptr: *const wchar_t, endptr: *mut *mut wchar_t) -> f64 {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcstok(ws1: *mut wchar_t, ws2: *const wchar_t,
-                  ptr: *mut *mut wchar_t) -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcstol(nptr: *const wchar_t, endptr: *mut *mut wchar_t,
-                  base: libc::c_int) -> libc::c_long {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcstoul(nptr: *const wchar_t, endptr: *mut *mut wchar_t,
-                   base: libc::c_int) -> libc::c_ulong {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcswcs(ws1: *const wchar_t, ws2: *const wchar_t) -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcswidth(pwcs: *const wchar_t, n: usize)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcsxfrm(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize)
-     -> usize {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wctob(c: wint_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wcwidth(wc: wchar_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wmemchr(ws: *const wchar_t, wc: wchar_t, n: usize)
-     -> *mut libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wmemcmp(ws1: *const wchar_t, ws2: *const wchar_t, n: usize)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wmemcpy(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize)
-     -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wmemmove(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize)
-     -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wmemset(ws1: *mut wchar_t, ws2: wchar_t, n: usize)
-     -> *mut wchar_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wprintf(format: *const wchar_t, ...) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn wscanf(format: *const wchar_t, ...) -> libc::c_int {
-    unimplemented!();
-}
diff --git a/src/unistd/cbindgen.toml b/src/unistd/cbindgen.toml
index ef4ad8123a3ed5aed99c7d22f7187965d2a72dca..a10250c6ddd2b485719f28ee675929235850f5c4 100644
--- a/src/unistd/cbindgen.toml
+++ b/src/unistd/cbindgen.toml
@@ -1,6 +1,6 @@
-sys_includes = ["stddef.h", "stdint.h", "sys/types.h", "stdarg.h", "bits/exec.h"]
+sys_includes = ["stddef.h", "stdint.h", "sys/types.h"]
 include_guard = "_UNISTD_H"
-trailer = "#include <bits/fcntl.h>"
+trailer = "#include <bits/fcntl.h>\n#include <bits/unistd.h>"
 language = "C"
 
 [enum]
diff --git a/src/unistd/src/lib.rs b/src/unistd/src/lib.rs
index db90a9feafd2f975a00f343166e92f7196d9a9b8..b673671f8df73c515dab194d79417e10da86e26e 100644
--- a/src/unistd/src/lib.rs
+++ b/src/unistd/src/lib.rs
@@ -1,7 +1,9 @@
 //! unistd implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/unistd.h.html
 
 #![no_std]
+#![cfg_attr(target_os = "redox", feature(alloc))]
 
+#[cfg(target_os = "redox")] extern crate alloc;
 extern crate platform;
 extern crate stdio;
 extern crate string;
@@ -33,7 +35,7 @@ pub const STDOUT_FILENO: c_int = 1;
 pub const STDERR_FILENO: c_int = 2;
 
 #[no_mangle]
-pub static mut environ: *const *mut c_char = 0 as *const *mut c_char;
+pub static mut environ: *const *mut c_char = ptr::null();
 
 #[no_mangle]
 pub extern "C" fn _exit(status: c_int) {
@@ -120,17 +122,80 @@ pub extern "C" fn encrypt(block: [c_char; 64], edflag: c_int) {
 // }
 
 #[no_mangle]
-pub extern "C" fn execv(path: *const c_char, argv: *const *mut c_char) -> c_int {
-    unsafe { execve(path, argv, environ) }
+pub unsafe extern "C" fn execv(path: *const c_char, argv: *const *mut c_char) -> c_int {
+    execve(path, argv, environ)
 }
 
 #[no_mangle]
-pub extern "C" fn execve(
+pub unsafe extern "C" fn execve(
     path: *const c_char,
     argv: *const *mut c_char,
     envp: *const *mut c_char,
 ) -> c_int {
-    platform::execve(path, argv, envp)
+    #[cfg(target_os = "linux")] {
+        platform::execve(path, argv, envp)
+    }
+    #[cfg(target_os = "redox")] {
+        use alloc::Vec;
+        use platform::{c_str, e};
+        use platform::syscall::flag::*;
+
+        let mut env = envp;
+        while !(*env).is_null() {
+            let slice = c_str(*env);
+            // Should always contain a =, but worth checking
+            if let Some(sep) = slice.iter().position(|&c| c == b'=') {
+                // If the environment variable has no name, do not attempt
+                // to add it to the env.
+                if sep > 0 {
+                    let mut path = b"env:".to_vec();
+                    path.extend_from_slice(&slice[..sep]);
+                    match platform::syscall::open(&path, O_WRONLY | O_CREAT) {
+                        Ok(fd) => {
+                            // If the environment variable has no value, there
+                            // is no need to write anything to the env scheme.
+                            if sep + 1 < slice.len() {
+                                let n = match platform::syscall::write(fd, &slice[sep + 1..]) {
+                                    Ok(n) => n,
+                                    err => {
+                                        return e(err) as c_int;
+                                    }
+                                };
+                            }
+                            // Cleanup after adding the variable.
+                            match platform::syscall::close(fd) {
+                                Ok(_) => (),
+                                err => {
+                                    return e(err) as c_int;
+                                }
+                            }
+                        }
+                        err => {
+                            return e(err) as c_int;
+                        }
+                    }
+                }
+            }
+            env = env.offset(1);
+        }
+
+        let mut len = 0;
+        for i in 0.. {
+            if (*argv.offset(i)).is_null() {
+                len = i;
+                break;
+            }
+        }
+
+        let mut args: Vec<[usize; 2]> = Vec::with_capacity(len as usize);
+        let mut arg = argv;
+        while !(*arg).is_null() {
+            args.push([*arg as usize, c_str(*arg).len()]);
+            arg = arg.offset(1);
+        }
+
+        e(platform::syscall::execve(c_str(path), &args)) as c_int
+    }
 }
 
 #[no_mangle]
@@ -235,25 +300,25 @@ pub unsafe extern "C" fn gethostname(mut name: *mut c_char, len: size_t) -> c_in
 
             name = name.offset(1);
         }
-        0
     }
     #[cfg(target_os = "redox")] {
-        use platform::{FileReader, Read};
+        use platform::{e, FileReader, Read};
         use platform::syscall::flag::*;
 
-        let fd = platform::open("/etc/hostname\0",as_ptr(), 0, O_RDONLY);
+        let fd = e(platform::syscall::open("/etc/hostname", O_RDONLY)) as i32;
         if fd < 0 {
             return fd;
         }
-        let reader = FileReader(fd);
+        let mut reader = FileReader(fd);
         for _ in 0..len {
-            if !reader.read_u8(&mut *name) {
+            if !reader.read_u8(&mut *(name as *mut u8)) {
                 *name = 0;
                 break;
             }
             name = name.offset(1);
         }
     }
+    0
 }
 
 #[no_mangle]
diff --git a/src/wchar/Cargo.toml b/src/wchar/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..97e412f20d966296a739e19c3859e811782901b9
--- /dev/null
+++ b/src/wchar/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "wchar"
+version = "0.1.0"
+authors = ["Stephan Vedder <stephan.vedder@gmail.com>"]
+build = "build.rs"
+
+[build-dependencies]
+cbindgen = { path = "../../cbindgen" }
+
+[features]
+str_internals = []
+
+[dependencies]
+platform = { path = "../platform" }
+stdio = { path = "../stdio" }
+errno = { path = "../errno" }
+time = { path = "../time" }
+va_list = { path = "../../va_list", features = ["no_std"] }
\ No newline at end of file
diff --git a/src/wchar/build.rs b/src/wchar/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5b64a17833ecbbf57ae8892cffdbceb1f2cc1fe8
--- /dev/null
+++ b/src/wchar/build.rs
@@ -0,0 +1,11 @@
+extern crate cbindgen;
+
+use std::{env, fs};
+
+fn main() {
+    let crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
+    fs::create_dir_all("../../target/include").expect("failed to create include directory");
+    cbindgen::generate(crate_dir)
+        .expect("failed to generate bindings")
+        .write_to_file("../../target/include/wchar.h");
+}
diff --git a/src/wchar/cbindgen.toml b/src/wchar/cbindgen.toml
new file mode 100644
index 0000000000000000000000000000000000000000..0e0aa10c843a41423844ef34faa5749a87c5041a
--- /dev/null
+++ b/src/wchar/cbindgen.toml
@@ -0,0 +1,7 @@
+sys_includes = ["stddef.h", "stdint.h", "time.h", "stdio.h" ]
+include_guard = "_WCHAR_H"
+header = "#include <bits/wchar.h>"
+language = "C"
+
+[enum]
+prefix_with_name = true
diff --git a/src/wchar/src/lib.rs b/src/wchar/src/lib.rs
index 96bb95d1feafac03a8534a38f674584eb8b9ec4a..31ae9667f56506b0d260c50b127439ac15e33093 100644
--- a/src/wchar/src/lib.rs
+++ b/src/wchar/src/lib.rs
@@ -1,55 +1,84 @@
-//! wchar implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/string.h.html
+//! wchar implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/wchar.h.html
 
 #![no_std]
+#![feature(str_internals)]
 
 extern crate errno;
 extern crate platform;
-extern crate stdlib;
-extern crate string;
+extern crate stdio;
 extern crate time;
+extern crate va_list as vl;
 
 use platform::types::*;
-use errno::*;
 use time::*;
-use core::cmp;
 use core::usize;
 use core::ptr;
-use core::mem;
-use string::*;
+use stdio::*;
+use vl::VaList as va_list;
 
-pub type wint_t = i32;
+mod utf8;
+
+const WEOF: wint_t = 0xFFFFFFFFu32;
+
+//Maximum number of bytes in a multibyte character for the current locale
+const MB_CUR_MAX: c_int = 4;
+//Maximum number of bytes in a multibyte characters for any locale
+const MB_LEN_MAX: c_int = 4;
 
 #[repr(C)]
-pub struct mbstate_t {
-    pub mbs_count: c_int,
-    pub mbs_length: c_int,
-    pub mbs_wch: wint_t,
-}
+#[derive(Clone, Copy)]
+pub struct mbstate_t;
 
 #[no_mangle]
 pub unsafe extern "C" fn btowc(c: c_int) -> wint_t {
     //Check for EOF
-    if c == -1 {
-        return -1;
+    if c as wint_t == WEOF {
+        return WEOF;
     }
 
     let uc = c as u8;
     let c = uc as c_char;
-    let mut ps: mbstate_t = mbstate_t {
-        mbs_count: 0,
-        mbs_length: 0,
-        mbs_wch: 0,
-    };
+    let mut ps: mbstate_t = mbstate_t;
     let mut wc: wchar_t = 0;
     let saved_errno = platform::errno;
     let status = mbrtowc(&mut wc, &c as (*const c_char), 1, &mut ps);
     if status == usize::max_value() || status == usize::max_value() - 1 {
         platform::errno = saved_errno;
-        return platform::errno;
+        return WEOF;
     }
     return wc as wint_t;
 }
 
+#[no_mangle]
+pub unsafe extern "C" fn fputwc(wc: wchar_t, stream: *mut FILE) -> wint_t {
+    //Convert wchar_t to multibytes first
+    static mut INTERNAL: mbstate_t = mbstate_t;
+    let mut bytes: [c_char; MB_CUR_MAX as usize] = [0; MB_CUR_MAX as usize];
+
+    let amount = wcrtomb(bytes.as_mut_ptr(), wc, &mut INTERNAL);
+
+    for i in 0..amount {
+        fputc(bytes[i] as c_int, &mut *stream);
+    }
+
+    wc as wint_t
+}
+
+#[no_mangle]
+pub extern "C" fn fputws(ws: *const wchar_t, stream: *mut FILE) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn fwide(stream: *mut FILE, mode: c_int) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn getwc(stream: *mut FILE) -> wint_t {
+    unimplemented!();
+}
+
 #[no_mangle]
 pub extern "C" fn getwchar() -> wint_t {
     unimplemented!();
@@ -57,24 +86,21 @@ pub extern "C" fn getwchar() -> wint_t {
 
 #[no_mangle]
 pub unsafe extern "C" fn mbsinit(ps: *const mbstate_t) -> c_int {
-    if ps.is_null() || (*ps).mbs_count == 0 {
-        return 1;
+    //Add a check for the state maybe
+    if ps.is_null() {
+        1
     } else {
-        return 0;
+        0
     }
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn mbrlen(s: *const c_char, n: usize, ps: *mut mbstate_t) -> usize {
-    static mut internal: mbstate_t = mbstate_t {
-        mbs_count: 0,
-        mbs_length: 0,
-        mbs_wch: 0,
-    };
-    return mbrtowc(ptr::null_mut(), s, n, &mut internal);
+    static mut INTERNAL: mbstate_t = mbstate_t;
+    mbrtowc(ptr::null_mut(), s, n, &mut INTERNAL)
 }
 
-//Only works for utf8!
+//Only works for UTF8 at the moment
 #[no_mangle]
 pub unsafe extern "C" fn mbrtowc(
     pwc: *mut wchar_t,
@@ -82,123 +108,85 @@ pub unsafe extern "C" fn mbrtowc(
     n: usize,
     ps: *mut mbstate_t,
 ) -> usize {
-    static mut internal: mbstate_t = mbstate_t {
-        mbs_count: 0,
-        mbs_length: 0,
-        mbs_wch: 0,
-    };
+    static mut INTERNAL: mbstate_t = mbstate_t;
 
     if ps.is_null() {
-        let ps = &mut internal;
+        let ps = &mut INTERNAL;
     }
     if s.is_null() {
         let xs: [c_char; 1] = [0];
-        utf8_mbrtowc(pwc, &xs[0] as *const c_char, 1, ps);
+        return utf8::mbrtowc(pwc, &xs[0] as *const c_char, 1, ps);
+    } else {
+        return utf8::mbrtowc(pwc, s, n, ps);
     }
-
-    return utf8_mbrtowc(pwc, s, n, ps);
 }
 
+//Convert a multibyte string to a wide string with a limited amount of bytes
+//Required for in POSIX.1-2008
 #[no_mangle]
-unsafe extern "C" fn utf8_mbrtowc(
-    pwc: *mut wchar_t,
-    s: *const c_char,
-    n: usize,
+pub unsafe extern "C" fn mbsnrtowcs(
+    dst_ptr: *mut wchar_t,
+    src_ptr: *mut *const c_char,
+    src_len: usize,
+    dst_len: usize,
     ps: *mut mbstate_t,
 ) -> usize {
-    let mut i: usize = 0;
+    static mut INTERNAL: mbstate_t = mbstate_t;
 
-    while !(i > 0 && (*ps).mbs_count == 0) {
-        if (n <= i) {
-            return -2isize as usize;
-        }
-        let c = s.offset(i as isize);
-        let uc = c as u8;
-
-        if (*ps).mbs_count == 0 {
-            //1 byte sequence - 00–7F
-            if (uc & 0b10000000) == 0b00000000 {
-                (*ps).mbs_count = 0;
-                (*ps).mbs_length = 1;
-                (*ps).mbs_wch = (uc as wchar_t & 0b1111111) as wint_t;
-            }
-            //2 byte sequence - C2–DF
-            else if (uc & 0b11100000) == 0b11000000 {
-                (*ps).mbs_count = 1;
-                (*ps).mbs_length = 2;
-                (*ps).mbs_wch = (uc as wchar_t & 0b11111) as wint_t;
-            }
-            //3 byte sequence - E0–EF
-            else if (uc & 0b11110000) == 0b11100000 {
-                (*ps).mbs_count = 2;
-                (*ps).mbs_length = 3;
-                (*ps).mbs_wch = (uc as wchar_t & 0b1111) as wint_t;
-            }
-            //4 byte sequence - F0–F4
-            else if (uc & 0b11111000) == 0b11110000 {
-                (*ps).mbs_count = 3;
-                (*ps).mbs_length = 4;
-                (*ps).mbs_wch = (uc as wchar_t & 0b111) as wint_t;
-            } else {
-                platform::errno = errno::EILSEQ;
-                return -1isize as usize;
-            }
-        } else {
-            if (uc & 0b11000000) != 0b10000000 {
-                platform::errno = errno::EILSEQ;
-                return -1isize as usize;
-            }
-
-            (*ps).mbs_wch = (*ps).mbs_wch << 6 | (uc & 0b00111111) as wint_t;
-            (*ps).mbs_count -= 1;
-        }
-
-        i += 1;
+    if ps.is_null() {
+        let ps = &mut INTERNAL;
     }
 
-    // Reject the character if it was produced with an overly long sequence.
-    if (*ps).mbs_length == 1 && 1 << 7 <= (*ps).mbs_wch {
-        platform::errno = errno::EILSEQ;
-        return -1isize as usize;
-    }
-    if (*ps).mbs_length == 2 && 1 << (5 + 1 * 6) <= (*ps).mbs_wch {
-        platform::errno = errno::EILSEQ;
-        return -1isize as usize;
-    }
-    if (*ps).mbs_length == 3 && 1 << (5 + 2 * 6) <= (*ps).mbs_wch {
-        platform::errno = errno::EILSEQ;
-        return -1isize as usize;
-    }
-    if (*ps).mbs_length == 4 && 1 << (5 + 3 * 6) <= (*ps).mbs_wch {
-        platform::errno = errno::EILSEQ;
-        return -1isize as usize;
-    }
+    let mut src = *src_ptr;
+
+    let mut dst_offset: usize = 0;
+    let mut src_offset: usize = 0;
+
+    while (dst_ptr.is_null() || dst_offset < dst_len) && src_offset < src_len {
+        let ps_copy = *ps;
+        let mut wc: wchar_t = 0;
+        let amount = mbrtowc(
+            &mut wc,
+            src.offset(src_offset as isize),
+            src_len - src_offset,
+            ps,
+        );
+
+        // Stop in the event a decoding error occured.
+        if amount == -1isize as usize {
+            *src_ptr = src.offset(src_offset as isize);
+            return 1isize as usize;
+        }
 
-    // The definition of UTF-8 prohibits encoding character numbers between
-    // U+D800 and U+DFFF, which are reserved for use with the UTF-16 encoding
-    // form (as surrogate pairs) and do not directly represent characters.
-    if 0xD800 <= (*ps).mbs_wch && (*ps).mbs_wch <= 0xDFFF {
-        platform::errno = errno::EILSEQ;
-        return -1isize as usize;
-    }
-    // RFC 3629 limits UTF-8 to 0x0 through 0x10FFFF.
-    if 0x10FFFF <= (*ps).mbs_wch {
-        platform::errno = errno::EILSEQ;
-        return -1isize as usize;
-    }
+        // Stop decoding early in the event we encountered a partial character.
+        if amount == -2isize as usize {
+            *ps = ps_copy;
+            break;
+        }
 
-    let result: wchar_t = (*ps).mbs_wch as wchar_t;
+        // Store the decoded wide character in the destination buffer.
+        if !dst_ptr.is_null() {
+            *dst_ptr.offset(dst_offset as isize) = wc;
+        }
 
-    if !pwc.is_null() {
-        *pwc = result;
-    }
+        // Stop decoding after decoding a null character and return a NULL
+        // source pointer to the caller, not including the null character in the
+        // number of characters stored in the destination buffer.
+        if wc == 0 {
+            src = ptr::null();
+            src_offset = 0;
+            break;
+        }
 
-    (*ps).mbs_length = 0;
-    (*ps).mbs_wch = 0;
+        dst_offset += 1;
+        src_offset += amount;
+    }
 
-    return if result != 0 { i } else { 0 };
+    *src_ptr = src.offset(src_offset as isize);
+    return dst_offset;
 }
 
+//Convert a multibyte string to a wide string
 #[no_mangle]
 pub extern "C" fn mbsrtowcs(
     dst: *mut wchar_t,
@@ -206,11 +194,31 @@ pub extern "C" fn mbsrtowcs(
     len: usize,
     ps: *mut mbstate_t,
 ) -> usize {
+    unsafe { mbsnrtowcs(dst, src, usize::max_value(), len, ps) }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn putwc(wc: wchar_t, stream: *mut FILE) -> wint_t {
+    fputwc(wc, &mut *stream)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn putwchar(wc: wchar_t) -> wint_t {
+    fputwc(wc, &mut *__stdout())
+}
+
+#[no_mangle]
+pub extern "C" fn swprintf(
+    s: *mut wchar_t,
+    n: usize,
+    format: *const wchar_t,
+    mut ap: va_list,
+) -> c_int {
     unimplemented!();
 }
 
 #[no_mangle]
-pub extern "C" fn putwchar(wc: wchar_t) -> wint_t {
+pub extern "C" fn swscanf(s: *const wchar_t, format: *const wchar_t, mut ap: va_list) -> c_int {
     unimplemented!();
 }
 
@@ -225,10 +233,45 @@ pub extern "C" fn towupper(wc: wint_t) -> wint_t {
 }
 
 #[no_mangle]
-pub extern "C" fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t) -> usize {
+pub extern "C" fn ungetwc(wc: wint_t, stream: *mut FILE) -> wint_t {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn vfwprintf(stream: *mut FILE, format: *const wchar_t, arg: va_list) -> c_int {
     unimplemented!();
 }
 
+#[no_mangle]
+pub extern "C" fn vwprintf(format: *const wchar_t, arg: va_list) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn vswprintf(
+    s: *mut wchar_t,
+    n: usize,
+    format: *const wchar_t,
+    arg: va_list,
+) -> c_int {
+    unimplemented!();
+}
+
+//widechar to multibyte
+#[no_mangle]
+pub extern "C" fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t) -> usize {
+    let mut buffer: [c_char; MB_CUR_MAX as usize] = [0; MB_CUR_MAX as usize];
+    let mut wc_cpy = wc;
+    let mut s_cpy = s;
+
+    if s.is_null() {
+        wc_cpy = 0;
+        s_cpy = buffer.as_mut_ptr();
+    }
+
+    unsafe { utf8::wcrtomb(s_cpy, wc_cpy, ps) }
+}
+
 #[no_mangle]
 pub extern "C" fn wcscat(ws1: *mut wchar_t, ws2: *const wchar_t) -> *mut wchar_t {
     unimplemented!();
@@ -392,3 +435,13 @@ pub extern "C" fn wmemmove(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) ->
 pub extern "C" fn wmemset(ws1: *mut wchar_t, ws2: wchar_t, n: usize) -> *mut wchar_t {
     unimplemented!();
 }
+
+#[no_mangle]
+pub extern "C" fn wprintf(format: *const wchar_t, mut ap: va_list) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn wscanf(format: *const wchar_t, mut ap: va_list) -> c_int {
+    unimplemented!();
+}
diff --git a/src/wchar/src/utf8.rs b/src/wchar/src/utf8.rs
new file mode 100644
index 0000000000000000000000000000000000000000..52166210f67741a07af25bbb4b484e4adbb80896
--- /dev/null
+++ b/src/wchar/src/utf8.rs
@@ -0,0 +1,57 @@
+//UTF implementation parts for wchar.h.
+//Partially ported from the Sortix libc
+
+extern crate errno;
+extern crate platform;
+
+use platform::types::*;
+use mbstate_t;
+use core::{slice,str,usize,char};
+
+//It's guaranteed that we don't have any nullpointers here
+pub unsafe fn mbrtowc(pwc: *mut wchar_t, s: *const c_char, n: usize, ps: *mut mbstate_t) -> usize {
+    let mut size = str::utf8_char_width(*s as u8);
+    if size > n {
+        platform::errno = errno::EILSEQ;
+        return -2isize as usize;
+    }
+    if size == 0 {
+        platform::errno = errno::EILSEQ;
+        return -1isize as usize;
+    }
+
+    let slice = slice::from_raw_parts(s as *const u8, size);
+    let decoded = str::from_utf8(slice);
+    if decoded.is_err() {
+        platform::errno = errno::EILSEQ;
+        return -1isize as usize;
+    }
+
+    let wc = decoded.unwrap();
+
+    let result: wchar_t = wc.chars().next().unwrap() as wchar_t;
+
+    if !pwc.is_null() {
+        *pwc = result;
+    }
+
+    return if result != 0 { size } else { 0 };
+}
+
+//It's guaranteed that we don't have any nullpointers here
+pub unsafe fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t) -> usize {
+    let dc = char::from_u32(wc as u32);
+
+    if dc.is_none() {
+        platform::errno = errno::EILSEQ;
+        return -1isize as usize;
+    }
+
+    let c = dc.unwrap();
+    let size = c.len_utf8();
+    let mut slice = slice::from_raw_parts_mut(s as *mut u8, size);
+
+    c.encode_utf8(slice);
+
+    size
+}
diff --git a/tests/.gitignore b/tests/.gitignore
index c60d7feecf6720f05e8ee899c0f6ba2fe3a4f2ab..e2242ca6a691e06861fcc4b710cd1e059094cf01 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -54,6 +54,10 @@
 /unistd/getopt
 /unlink
 /waitpid
+/wchar/mbrtowc
+/wchar/mbsrtowcs
+/wchar/putwchar
+/wchar/wcrtomb
 /write
 /time
 /gmtime
diff --git a/tests/Makefile b/tests/Makefile
index dbe6063de243a036f087e7555b016eb0b2bb2970..3588a66a5b164d4eaa9e81e6388aba3f01e1d5a2 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -44,6 +44,10 @@ EXPECT_BINS=\
 	string/strtok_r \
 	unistd/getopt \
 	waitpid \
+	wchar/mbrtowc \
+	wchar/mbsrtowcs \
+	wchar/putwchar \
+	wchar/wcrtomb \
 	write \
 	time \
 	gmtime \
@@ -112,4 +116,4 @@ TAILLIBS=\
 	../target/openlibm/libopenlibm.a
 
 %: %.c $(HEADLIBS) $(TAILLIBS)
-	gcc -fno-stack-protector -Wall $(CFLAGS) $(HEADLIBS) "$<" $(TAILLIBS) -o "$@"
+	gcc -fno-stack-protector -Wall -g $(CFLAGS) $(HEADLIBS) "$<" $(TAILLIBS) -o "$@"
diff --git a/tests/exec.c b/tests/exec.c
index 4a09e743b59e80de89fbf221a3115cbac6f78af4..213df7f8d325de98c78367e592cfae730e3a48c9 100644
--- a/tests/exec.c
+++ b/tests/exec.c
@@ -1,4 +1,5 @@
 #include <unistd.h>
+#include <stdio.h>
 
 int main(int argc, char** argv) {
     char *const args[1] = {"arg"};
diff --git a/tests/expected/exec.stderr b/tests/expected/exec.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/exec.stdout b/tests/expected/exec.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..980a0d5f19a64b4b30a87d4206aade58726b60e3
--- /dev/null
+++ b/tests/expected/exec.stdout
@@ -0,0 +1 @@
+Hello World!
diff --git a/tests/expected/wchar/mbrtowc.stderr b/tests/expected/wchar/mbrtowc.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/wchar/mbrtowc.stdout b/tests/expected/wchar/mbrtowc.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..ae1d1cd6f9abcd8ba435cfd8efe9960655aeb1ae
--- /dev/null
+++ b/tests/expected/wchar/mbrtowc.stdout
@@ -0,0 +1,2 @@
+Processing 11 UTF-8 code units: [ 7a c3 9f e6 b0 b4 f0 9f 8d 8c 0 ]
+into 5 wchar_t units: [ 7a df 6c34 1f34c 0 ]
diff --git a/tests/expected/wchar/mbsrtowcs.stderr b/tests/expected/wchar/mbsrtowcs.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/wchar/mbsrtowcs.stdout b/tests/expected/wchar/mbsrtowcs.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..e8f8258f2edcc440863f3ac05f1f49d0f7723258
--- /dev/null
+++ b/tests/expected/wchar/mbsrtowcs.stdout
@@ -0,0 +1 @@
+The length, including '\0': 5 
diff --git a/tests/expected/wchar/putwchar.stderr b/tests/expected/wchar/putwchar.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/wchar/putwchar.stdout b/tests/expected/wchar/putwchar.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/wchar/wcrtomb.stderr b/tests/expected/wchar/wcrtomb.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/wchar/wcrtomb.stdout b/tests/expected/wchar/wcrtomb.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..d41045ed2b49e1f52c6aef455fc8fca00b689451
--- /dev/null
+++ b/tests/expected/wchar/wcrtomb.stdout
@@ -0,0 +1,2 @@
+Processing 5 wchar_t units: [ 7a df 6c34 1f34c 0 ]
+into 11 UTF-8 code units: [ 7a c3 9f e6 b0 b4 f0 9f 8d 8c 0 ]
diff --git a/tests/wchar/mbrtowc.c b/tests/wchar/mbrtowc.c
new file mode 100644
index 0000000000000000000000000000000000000000..4487d2273192ce2b38c98e2eac6ef054b34d1c82
--- /dev/null
+++ b/tests/wchar/mbrtowc.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+ 
+int main(void)
+{
+    mbstate_t state;
+    memset(&state, 0, sizeof state);
+    char in[] = u8"z\u00df\u6c34\U0001F34C"; // or u8"zß水🍌"
+    size_t in_sz = sizeof in / sizeof *in;
+ 
+    printf("Processing %zu UTF-8 code units: [ ", in_sz); //Should be 11 regular chars
+    for(size_t n = 0; n < in_sz; ++n) printf("%#x ", (unsigned char)in[n]);
+    puts("]");
+ 
+    wchar_t out[in_sz];
+    char *p_in = in, *end = in + in_sz;
+    wchar_t *p_out = out;
+    int rc;
+    while((rc = mbrtowc(p_out, p_in, end - p_in, &state)) > 0)
+    {
+        p_in += rc;
+        p_out += 1;
+    }
+ 
+    size_t out_sz = p_out - out + 1;
+    printf("into %zu wchar_t units: [ ", out_sz); //Should be 5 wchars
+    for(size_t x = 0; x < out_sz; ++x) printf("%#x ", out[x]);
+    puts("]");
+}
\ No newline at end of file
diff --git a/tests/wchar/mbsrtowcs.c b/tests/wchar/mbsrtowcs.c
new file mode 100644
index 0000000000000000000000000000000000000000..1ee1560a9f7c27dc13369a6694fbb2ce61543cf5
--- /dev/null
+++ b/tests/wchar/mbsrtowcs.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <wchar.h>
+ 
+void print_as_wide(const char* mbstr)
+{
+    mbstate_t state;
+    memset(&state, 0, sizeof state);
+    size_t len = 1 + mbsrtowcs(NULL, &mbstr, 0, &state);
+    wchar_t wstr[len];
+    mbsrtowcs(&wstr[0], &mbstr, len, &state);
+
+    //Should be 5
+    printf("The length, including '\\0': %i \n",len);
+
+    //missing wprintf to print this wide string
+    //wprintf(L"The wide string: %ls \n", &wstr[0]);
+}
+ 
+int main()
+{
+    const char* mbstr = u8"z\u00df\u6c34\U0001f34c"; // or u8"zß水🍌"
+    print_as_wide(mbstr);
+}
\ No newline at end of file
diff --git a/tests/wchar/putwchar.c b/tests/wchar/putwchar.c
new file mode 100644
index 0000000000000000000000000000000000000000..f9f7ea41236ce5bbbf85d1cbd1ed318b67a0ea71
--- /dev/null
+++ b/tests/wchar/putwchar.c
@@ -0,0 +1,21 @@
+#include <string.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdlib.h>
+
+int main(void)
+{
+    wchar_t *wcs = L"zß水🍌";
+
+    int i;
+    for (i = 0; wcs[i] != L'\0'; i++)
+    {
+        if (0xFFFFFFFFu == putwchar(wcs[i]))
+        {
+            printf("Unable to putwchar() the wide character.\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    return 0;
+}
\ No newline at end of file
diff --git a/tests/wchar/wcrtomb.c b/tests/wchar/wcrtomb.c
new file mode 100644
index 0000000000000000000000000000000000000000..27b05cef6b3bbfb9b383867c11ec5f185cc65f02
--- /dev/null
+++ b/tests/wchar/wcrtomb.c
@@ -0,0 +1,29 @@
+#include <string.h>  
+#include <stdio.h>  
+#include <wchar.h> 
+#include <stdlib.h>
+  
+int main( void )  
+{  
+    mbstate_t state;
+    memset(&state, 0, sizeof state);
+    wchar_t in[] = L"zß水🍌"; // or "z\u00df\u6c34\U0001F34C"
+    size_t in_sz = sizeof in / sizeof *in;
+ 
+    printf("Processing %zu wchar_t units: [ ", in_sz);
+    for(size_t n = 0; n < in_sz; ++n) printf("%#x ", (unsigned int)in[n]);
+    puts("]");
+ 
+    char out[MB_CUR_MAX * in_sz];
+    char *p = out;
+    for(size_t n = 0; n < in_sz; ++n) {
+        int rc = wcrtomb(p, in[n], &state); 
+        if(rc == -1) break;
+        p += rc;
+    }
+ 
+    size_t out_sz = p - out;
+    printf("into %zu UTF-8 code units: [ ", out_sz);
+    for(size_t x = 0; x < out_sz; ++x) printf("%#x ", +(unsigned char)out[x]);
+    puts("]");
+} 
\ No newline at end of file