aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Mitchener <bruce.mitchener@gmail.com>2013-04-15 23:03:13 +0700
committerBruce Mitchener <bruce.mitchener@gmail.com>2013-04-22 16:45:07 +0700
commit7cacf252e7f99fc2c98b969f8076011cfb6854d1 (patch)
tree36baa3a1af6723d24dae5b4e1dc1351abf06fa71
parentb9090fa1f2ba90a5745981d1a4d4108915ddd6e9 (diff)
Add musl multibyte function implementations.
-rwxr-xr-xemcc17
-rw-r--r--src/library.js37
-rw-r--r--system/lib/libc/musl/src/multibyte/btowc.c7
-rw-r--r--system/lib/libc/musl/src/multibyte/internal.c38
-rw-r--r--system/lib/libc/musl/src/multibyte/internal.h22
-rw-r--r--system/lib/libc/musl/src/multibyte/mblen.c17
-rw-r--r--system/lib/libc/musl/src/multibyte/mbrlen.c18
-rw-r--r--system/lib/libc/musl/src/multibyte/mbrtowc.c57
-rw-r--r--system/lib/libc/musl/src/multibyte/mbsinit.c17
-rw-r--r--system/lib/libc/musl/src/multibyte/mbsnrtowcs.c65
-rw-r--r--system/lib/libc/musl/src/multibyte/mbsrtowcs.c100
-rw-r--r--system/lib/libc/musl/src/multibyte/mbstowcs.c7
-rw-r--r--system/lib/libc/musl/src/multibyte/mbtowc.c53
-rw-r--r--system/lib/libc/musl/src/multibyte/wcrtomb.c38
-rw-r--r--system/lib/libc/musl/src/multibyte/wcsnrtombs.c52
-rw-r--r--system/lib/libc/musl/src/multibyte/wcsrtombs.c58
-rw-r--r--system/lib/libc/musl/src/multibyte/wcstombs.c7
-rw-r--r--system/lib/libc/musl/src/multibyte/wctob.c8
-rw-r--r--system/lib/libc/musl/src/multibyte/wctomb.c18
19 files changed, 599 insertions, 37 deletions
diff --git a/emcc b/emcc
index 8c21562b..ce5b499e 100755
--- a/emcc
+++ b/emcc
@@ -1128,6 +1128,23 @@ try:
];
musl_files = [
+ ['multibyte', [
+ 'btowc.c',
+ 'mblen.c',
+ 'mbrlen.c',
+ 'mbrtowc.c',
+ 'mbsinit.c',
+ 'mbsnrtowcs.c',
+ 'mbsrtowcs.c',
+ 'mbstowcs.c',
+ 'mbtowc.c',
+ 'wcrtomb.c',
+ 'wcsnrtombs.c',
+ 'wcsrtombs.c',
+ 'wcstombs.c',
+ 'wctob.c',
+ 'wctomb.c',
+ ]],
['string', [
'wcpcpy.c',
'wcpncpy.c',
diff --git a/src/library.js b/src/library.js
index bb4d710b..dfaff1fb 100644
--- a/src/library.js
+++ b/src/library.js
@@ -4168,32 +4168,6 @@ LibraryManager.library = {
}
},
- mbtowc: function(pwc, pmb, maxx) {
- // XXX doesn't really handle multibyte at all
- if (!pmb) return 0;
- maxx = Math.min({{{ cDefine('_NL_CTYPE_MB_CUR_MAX') }}}, maxx);
- var i;
- for (i = 0; i < maxx; i++) {
- var curr = {{{ makeGetValue('pmb', 0, 'i8') }}};
- if (pwc) {
- {{{ makeSetValue('pwc', '0', 'curr', 'i8') }}};
- {{{ makeSetValue('pwc', '1', '0', 'i8') }}};
- pwc += 2;
- }
- pmb++;
- if (!curr) break;
- }
- return i;
- },
-
- wcrtomb: function(s, wc, ps) {
- // XXX doesn't really handle multibyte at all
- if (s) {
- {{{ makeSetValue('s', '0', 'wc', 'i8') }}};
- }
- return 1;
- },
-
arc4random: 'rand',
// ==========================================================================
@@ -4324,17 +4298,6 @@ LibraryManager.library = {
return (curr - ptr)|0;
},
- // TODO: Implement when we have real unicode support.
- mblen: function() {
- return 1;
- },
-
- mbrlen: function() { throw 'mbrlen not implemented' },
- mbsrtowcs: function() { throw 'mbsrtowcs not implemented' },
- wcsnrtombs: function() { throw 'wcsnrtombs not implemented' },
- mbsnrtowcs: function() { throw 'mbsnrtowcs not implemented' },
- mbrtowc: function() { throw 'mbrtowc not implemented' },
-
strspn: function(pstr, pset) {
var str = pstr, set, strcurr, setcurr;
while (1) {
diff --git a/system/lib/libc/musl/src/multibyte/btowc.c b/system/lib/libc/musl/src/multibyte/btowc.c
new file mode 100644
index 00000000..9d2c3b16
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/btowc.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <wchar.h>
+
+wint_t btowc(int c)
+{
+ return c<128U ? c : EOF;
+}
diff --git a/system/lib/libc/musl/src/multibyte/internal.c b/system/lib/libc/musl/src/multibyte/internal.c
new file mode 100644
index 00000000..ab22806e
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/internal.c
@@ -0,0 +1,38 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <inttypes.h>
+
+#include "internal.h"
+
+#define C(x) ( x<2 ? -1 : ( R(0x80,0xc0) | x ) )
+#define D(x) C((x+16))
+#define E(x) ( ( x==0 ? R(0xa0,0xc0) : \
+ x==0xd ? R(0x80,0xa0) : \
+ R(0x80,0xc0) ) \
+ | ( R(0x80,0xc0) >> 6 ) \
+ | x )
+#define F(x) ( ( x>=5 ? 0 : \
+ x==0 ? R(0x90,0xc0) : \
+ x==4 ? R(0x80,0xa0) : \
+ R(0x80,0xc0) ) \
+ | ( R(0x80,0xc0) >> 6 ) \
+ | ( R(0x80,0xc0) >> 12 ) \
+ | x )
+
+const uint32_t bittab[] = {
+ C(0x2),C(0x3),C(0x4),C(0x5),C(0x6),C(0x7),
+ C(0x8),C(0x9),C(0xa),C(0xb),C(0xc),C(0xd),C(0xe),C(0xf),
+ D(0x0),D(0x1),D(0x2),D(0x3),D(0x4),D(0x5),D(0x6),D(0x7),
+ D(0x8),D(0x9),D(0xa),D(0xb),D(0xc),D(0xd),D(0xe),D(0xf),
+ E(0x0),E(0x1),E(0x2),E(0x3),E(0x4),E(0x5),E(0x6),E(0x7),
+ E(0x8),E(0x9),E(0xa),E(0xb),E(0xc),E(0xd),E(0xe),E(0xf),
+ F(0x0),F(0x1),F(0x2),F(0x3),F(0x4)
+};
+
+#ifdef BROKEN_VISIBILITY
+__asm__(".hidden __fsmu8");
+#endif
diff --git a/system/lib/libc/musl/src/multibyte/internal.h b/system/lib/libc/musl/src/multibyte/internal.h
new file mode 100644
index 00000000..25ba240e
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/internal.h
@@ -0,0 +1,22 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#define bittab __fsmu8
+
+#include "libc.h"
+
+extern const uint32_t bittab[] ATTR_LIBC_VISIBILITY;
+
+/* Upper 6 state bits are a negative integer offset to bound-check next byte */
+/* equivalent to: ( (b-0x80) | (b+offset) ) & ~0x3f */
+#define OOB(c,b) (((((b)>>3)-0x10)|(((b)>>3)+((int32_t)(c)>>26))) & ~7)
+
+/* Interval [a,b). Either a must be 80 or b must be c0, lower 3 bits clear. */
+#define R(a,b) ((uint32_t)((a==0x80 ? 0x40-b : -a) << 23))
+#define FAILSTATE R(0x80,0x80)
+
+#define SA 0xc2u
+#define SB 0xf4u
diff --git a/system/lib/libc/musl/src/multibyte/mblen.c b/system/lib/libc/musl/src/multibyte/mblen.c
new file mode 100644
index 00000000..26d35649
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mblen.c
@@ -0,0 +1,17 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+int mblen(const char *s, size_t n)
+{
+ return mbtowc(0, s, n);
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbrlen.c b/system/lib/libc/musl/src/multibyte/mbrlen.c
new file mode 100644
index 00000000..c9714ef8
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbrlen.c
@@ -0,0 +1,18 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t mbrlen(const char *restrict s, size_t n, mbstate_t *restrict st)
+{
+ static unsigned internal;
+ return mbrtowc(0, s, n, st ? st : (mbstate_t *)&internal);
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbrtowc.c b/system/lib/libc/musl/src/multibyte/mbrtowc.c
new file mode 100644
index 00000000..db803661
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbrtowc.c
@@ -0,0 +1,57 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate_t *restrict st)
+{
+ static unsigned internal_state;
+ unsigned c;
+ const unsigned char *s = (const void *)src;
+ const unsigned N = n;
+
+ if (!st) st = (void *)&internal_state;
+ c = *(unsigned *)st;
+
+ if (!s) {
+ if (c) goto ilseq;
+ return 0;
+ } else if (!wc) wc = (void *)&wc;
+
+ if (!n) return -2;
+ if (!c) {
+ if (*s < 0x80) return !!(*wc = *s);
+ if (*s-SA > SB-SA) goto ilseq;
+ c = bittab[*s++-SA]; n--;
+ }
+
+ if (n) {
+ if (OOB(c,*s)) goto ilseq;
+loop:
+ c = c<<6 | *s++-0x80; n--;
+ if (!(c&(1U<<31))) {
+ *(unsigned *)st = 0;
+ *wc = c;
+ return N-n;
+ }
+ if (n) {
+ if (*s-0x80u >= 0x40) goto ilseq;
+ goto loop;
+ }
+ }
+
+ *(unsigned *)st = c;
+ return -2;
+ilseq:
+ *(unsigned *)st = 0;
+ errno = EILSEQ;
+ return -1;
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbsinit.c b/system/lib/libc/musl/src/multibyte/mbsinit.c
new file mode 100644
index 00000000..c0e7e494
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbsinit.c
@@ -0,0 +1,17 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+int mbsinit(const mbstate_t *st)
+{
+ return !st || !*(unsigned *)st;
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c b/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c
new file mode 100644
index 00000000..33457f95
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c
@@ -0,0 +1,65 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "internal.h"
+
+size_t mbsnrtowcs(wchar_t *restrict wcs, const char **restrict src, size_t n, size_t wn, mbstate_t *restrict st)
+{
+ size_t l, cnt=0, n2;
+ wchar_t *ws, wbuf[256];
+ const char *s = *src;
+
+ if (!wcs) ws = wbuf, wn = sizeof wbuf / sizeof *wbuf;
+ else ws = wcs;
+
+ /* making sure output buffer size is at most n/4 will ensure
+ * that mbsrtowcs never reads more than n input bytes. thus
+ * we can use mbsrtowcs as long as it's practical.. */
+
+ while ( s && wn && ( (n2=n/4)>=wn || n2>32 ) ) {
+ if (n2>=wn) n2=wn;
+ n -= n2;
+ l = mbsrtowcs(ws, &s, n2, st);
+ if (!(l+1)) {
+ cnt = l;
+ wn = 0;
+ break;
+ }
+ if (ws != wbuf) {
+ ws += l;
+ wn -= l;
+ }
+ cnt += l;
+ }
+ if (s) while (wn && n) {
+ l = mbrtowc(ws, s, n, st);
+ if (l+2<=2) {
+ if (!(l+1)) {
+ cnt = l;
+ break;
+ }
+ if (!l) {
+ s = 0;
+ break;
+ }
+ /* have to roll back partial character */
+ *(unsigned *)st = 0;
+ break;
+ }
+ s += l; n -= l;
+ /* safe - this loop runs fewer than sizeof(wbuf)/8 times */
+ ws++; wn--;
+ cnt++;
+ }
+ if (wcs) *src = s;
+ return cnt;
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbsrtowcs.c b/system/lib/libc/musl/src/multibyte/mbsrtowcs.c
new file mode 100644
index 00000000..75a493c4
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbsrtowcs.c
@@ -0,0 +1,100 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbstate_t *restrict st)
+{
+ const unsigned char *s = (const void *)*src;
+ size_t wn0 = wn;
+ unsigned c = 0;
+
+ if (st && (c = *(unsigned *)st)) {
+ if (ws) {
+ *(unsigned *)st = 0;
+ goto resume;
+ } else {
+ goto resume0;
+ }
+ }
+
+ if (!ws) for (;;) {
+ if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
+ while (!(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
+ s += 4;
+ wn -= 4;
+ }
+ }
+ if (*s-1u < 0x7f) {
+ s++;
+ wn--;
+ continue;
+ }
+ if (*s-SA > SB-SA) break;
+ c = bittab[*s++-SA];
+resume0:
+ if (OOB(c,*s)) { s--; break; }
+ s++;
+ if (c&(1U<<25)) {
+ if (*s-0x80u >= 0x40) { s-=2; break; }
+ s++;
+ if (c&(1U<<19)) {
+ if (*s-0x80u >= 0x40) { s-=3; break; }
+ s++;
+ }
+ }
+ wn--;
+ c = 0;
+ } else for (;;) {
+ if (!wn) return wn0;
+ if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
+ while (wn>=4 && !(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
+ *ws++ = *s++;
+ *ws++ = *s++;
+ *ws++ = *s++;
+ *ws++ = *s++;
+ wn -= 4;
+ }
+ }
+ if (*s-1u < 0x7f) {
+ *ws++ = *s++;
+ wn--;
+ continue;
+ }
+ if (*s-SA > SB-SA) break;
+ c = bittab[*s++-SA];
+resume:
+ if (OOB(c,*s)) { s--; break; }
+ c = (c<<6) | *s++-0x80;
+ if (c&(1U<<31)) {
+ if (*s-0x80u >= 0x40) { s-=2; break; }
+ c = (c<<6) | *s++-0x80;
+ if (c&(1U<<31)) {
+ if (*s-0x80u >= 0x40) { s-=3; break; }
+ c = (c<<6) | *s++-0x80;
+ }
+ }
+ *ws++ = c;
+ wn--;
+ c = 0;
+ }
+
+ if (!c && !*s) {
+ if (ws) {
+ *ws = 0;
+ *src = 0;
+ }
+ return wn0-wn;
+ }
+ errno = EILSEQ;
+ if (ws) *src = (const void *)s;
+ return -1;
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbstowcs.c b/system/lib/libc/musl/src/multibyte/mbstowcs.c
new file mode 100644
index 00000000..dc0d4594
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbstowcs.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+#include <wchar.h>
+
+size_t mbstowcs(wchar_t *restrict ws, const char *restrict s, size_t wn)
+{
+ return mbsrtowcs(ws, (void*)&s, wn, 0);
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbtowc.c b/system/lib/libc/musl/src/multibyte/mbtowc.c
new file mode 100644
index 00000000..ec9e54ad
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbtowc.c
@@ -0,0 +1,53 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+#include <stdio.h>
+int mbtowc(wchar_t *restrict wc, const char *restrict src, size_t n)
+{
+ unsigned c;
+ const unsigned char *s = (const void *)src;
+
+ if (!s) return 0;
+ if (!n) goto ilseq;
+ if (!wc) wc = (void *)&wc;
+
+ if (*s < 0x80) return !!(*wc = *s);
+ if (*s-SA > SB-SA) goto ilseq;
+ c = bittab[*s++-SA];
+
+ /* Avoid excessive checks against n: If shifting the state n-1
+ * times does not clear the high bit, then the value of n is
+ * insufficient to read a character */
+ if (n<4 && ((c<<(6*n-6)) & (1U<<31))) goto ilseq;
+
+ if (OOB(c,*s)) goto ilseq;
+ c = c<<6 | *s++-0x80;
+ if (!(c&(1U<<31))) {
+ *wc = c;
+ return 2;
+ }
+
+ if (*s-0x80u >= 0x40) goto ilseq;
+ c = c<<6 | *s++-0x80;
+ if (!(c&(1U<<31))) {
+ *wc = c;
+ return 3;
+ }
+
+ if (*s-0x80u >= 0x40) goto ilseq;
+ *wc = c<<6 | *s++-0x80;
+ return 4;
+
+ilseq:
+ errno = EILSEQ;
+ return -1;
+}
diff --git a/system/lib/libc/musl/src/multibyte/wcrtomb.c b/system/lib/libc/musl/src/multibyte/wcrtomb.c
new file mode 100644
index 00000000..250649f5
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wcrtomb.c
@@ -0,0 +1,38 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st)
+{
+ if (!s) return 1;
+ if ((unsigned)wc < 0x80) {
+ *s = wc;
+ return 1;
+ } else if ((unsigned)wc < 0x800) {
+ *s++ = 0xc0 | (wc>>6);
+ *s = 0x80 | (wc&0x3f);
+ return 2;
+ } else if ((unsigned)wc < 0xd800 || (unsigned)wc-0xe000 < 0x2000) {
+ *s++ = 0xe0 | (wc>>12);
+ *s++ = 0x80 | ((wc>>6)&0x3f);
+ *s = 0x80 | (wc&0x3f);
+ return 3;
+ } else if ((unsigned)wc-0x10000 < 0x100000) {
+ *s++ = 0xf0 | (wc>>18);
+ *s++ = 0x80 | ((wc>>12)&0x3f);
+ *s++ = 0x80 | ((wc>>6)&0x3f);
+ *s = 0x80 | (wc&0x3f);
+ return 4;
+ }
+ errno = EILSEQ;
+ return -1;
+}
diff --git a/system/lib/libc/musl/src/multibyte/wcsnrtombs.c b/system/lib/libc/musl/src/multibyte/wcsnrtombs.c
new file mode 100644
index 00000000..a2e308b3
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wcsnrtombs.c
@@ -0,0 +1,52 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t wcsnrtombs(char *restrict dst, const wchar_t **restrict wcs, size_t wn, size_t n, mbstate_t *restrict st)
+{
+ size_t l, cnt=0, n2;
+ char *s, buf[256];
+ const wchar_t *ws = *wcs;
+
+ if (!dst) s = buf, n = sizeof buf;
+ else s = dst;
+
+ while ( ws && n && ( (n2=wn)>=n || n2>32 ) ) {
+ if (n2>=n) n2=n;
+ wn -= n2;
+ l = wcsrtombs(s, &ws, n2, 0);
+ if (!(l+1)) {
+ cnt = l;
+ n = 0;
+ break;
+ }
+ if (s != buf) {
+ s += l;
+ n -= l;
+ }
+ cnt += l;
+ }
+ if (ws) while (n && wn) {
+ l = wcrtomb(s, *ws, 0);
+ if ((l+1)<=1) {
+ if (!l) ws = 0;
+ else cnt = l;
+ break;
+ }
+ ws++; wn--;
+ /* safe - this loop runs fewer than sizeof(buf) times */
+ s+=l; n-=l;
+ cnt++;
+ }
+ if (dst) *wcs = ws;
+ return cnt;
+}
diff --git a/system/lib/libc/musl/src/multibyte/wcsrtombs.c b/system/lib/libc/musl/src/multibyte/wcsrtombs.c
new file mode 100644
index 00000000..d48a65e7
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wcsrtombs.c
@@ -0,0 +1,58 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t wcsrtombs(char *restrict s, const wchar_t **restrict ws, size_t n, mbstate_t *restrict st)
+{
+ const wchar_t *ws2;
+ char buf[4];
+ size_t N = n, l;
+ if (!s) {
+ for (n=0, ws2=*ws; *ws2; ws2++) {
+ if (*ws2 >= 0x80u) {
+ l = wcrtomb(buf, *ws2, 0);
+ if (!(l+1)) return -1;
+ n += l;
+ } else n++;
+ }
+ return n;
+ }
+ while (n>=4 && **ws) {
+ if (**ws >= 0x80u) {
+ l = wcrtomb(s, **ws, 0);
+ if (!(l+1)) return -1;
+ s += l;
+ n -= l;
+ } else {
+ *s++ = **ws;
+ n--;
+ }
+ (*ws)++;
+ }
+ while (n && **ws) {
+ if (**ws >= 0x80u) {
+ l = wcrtomb(buf, **ws, 0);
+ if (!(l+1)) return -1;
+ if (l>n) return N-n;
+ wcrtomb(s, **ws, 0);
+ s += l;
+ n -= l;
+ } else {
+ *s++ = **ws;
+ n--;
+ }
+ (*ws)++;
+ }
+ if (n) *s = 0;
+ *ws = 0;
+ return N-n;
+}
diff --git a/system/lib/libc/musl/src/multibyte/wcstombs.c b/system/lib/libc/musl/src/multibyte/wcstombs.c
new file mode 100644
index 00000000..ab152874
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wcstombs.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+#include <wchar.h>
+
+size_t wcstombs(char *restrict s, const wchar_t *restrict ws, size_t n)
+{
+ return wcsrtombs(s, &(const wchar_t *){ws}, n, 0);
+}
diff --git a/system/lib/libc/musl/src/multibyte/wctob.c b/system/lib/libc/musl/src/multibyte/wctob.c
new file mode 100644
index 00000000..d6353ee1
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wctob.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include <wchar.h>
+
+int wctob(wint_t c)
+{
+ if (c < 128U) return c;
+ return EOF;
+}
diff --git a/system/lib/libc/musl/src/multibyte/wctomb.c b/system/lib/libc/musl/src/multibyte/wctomb.c
new file mode 100644
index 00000000..6910ef37
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wctomb.c
@@ -0,0 +1,18 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+int wctomb(char *s, wchar_t wc)
+{
+ if (!s) return 0;
+ return wcrtomb(s, wc, 0);
+}