diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-09-25 19:13:43 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-09-25 19:13:43 -0700 |
commit | e89fc456ed231d7933cd1e9e4d08d8326c51f668 (patch) | |
tree | 8c36509fcd3a95eb708c5730bc64d320904fcd03 | |
parent | 328abc1d77ba78ba2eba6b3df97bd00d9588b881 (diff) | |
parent | 0725ff3edc2ddddbd126193ca8ccaf392044b5ab (diff) |
Merge pull request #1670 from waywardmonkeys/add-locale-stuff
Add locale stuff
36 files changed, 944 insertions, 6 deletions
@@ -1304,6 +1304,10 @@ try: os.path.join('libc', 'gen', 'vwarnx.c'), os.path.join('libc', 'stdlib', 'strtod.c'), ] + musl_files = [ + ] + for directory, sources in musl_files: + libc_files += [os.path.join('libc', 'musl', 'src', directory, source) for source in sources] return build_libc('libc.bc', libc_files) def apply_libc(need): @@ -1341,6 +1345,32 @@ try: 'wctrans.c', 'wcwidth.c', ]], + ['locale', [ + 'iswalnum_l.c', + 'iswalpha_l.c', + 'iswblank_l.c', + 'iswcntrl_l.c', + 'iswctype_l.c', + 'iswdigit_l.c', + 'iswgraph_l.c', + 'iswlower_l.c', + 'iswprint_l.c', + 'iswpunct_l.c', + 'iswspace_l.c', + 'iswupper_l.c', + 'iswxdigit_l.c', + 'strfmon.c', + 'strxfrm.c', + 'towctrans_l.c', + 'towlower_l.c', + 'towupper_l.c', + 'wcscoll.c', + 'wcscoll_l.c', + 'wcsxfrm.c', + 'wcsxfrm_l.c', + 'wctrans_l.c', + 'wctype_l.c', + ]], ['multibyte', [ 'btowc.c', 'mblen.c', @@ -1358,6 +1388,14 @@ try: 'wctob.c', 'wctomb.c', ]], + ['stdio', [ + 'fwprintf.c', + 'swprintf.c', + 'vfwprintf.c', + 'vswprintf.c', + 'vwprintf.c', + 'wprintf.c', + ]], ['stdlib', [ 'ecvt.c', 'fcvt.c', @@ -1367,7 +1405,7 @@ try: 'wcpcpy.c', 'wcpncpy.c', 'wcscasecmp.c', - # 'wcscasecmp_l.c', # XXX: alltypes.h issue + 'wcscasecmp_l.c', 'wcscat.c', 'wcschr.c', 'wcscmp.c', @@ -1376,7 +1414,7 @@ try: 'wcsdup.c', 'wcslen.c', 'wcsncasecmp.c', - # 'wcsncasecmp_l.c', # XXX: alltypes.h issue + 'wcsncasecmp_l.c', 'wcsncat.c', 'wcsncmp.c', 'wcsncpy.c', diff --git a/src/library.js b/src/library.js index 49f8e453..a0115373 100644 --- a/src/library.js +++ b/src/library.js @@ -3818,6 +3818,7 @@ LibraryManager.library = { }, // We always assume ASCII locale. strcoll: 'strcmp', + strcoll_l: 'strcmp', strcasecmp__asm: true, strcasecmp__sig: 'iii', @@ -4084,6 +4085,7 @@ LibraryManager.library = { } }, _toupper: 'toupper', + toupper_l: 'toupper', tolower__asm: true, tolower__sig: 'ii', @@ -4094,54 +4096,65 @@ LibraryManager.library = { return (chr - {{{ charCode('A') }}} + {{{ charCode('a') }}})|0; }, _tolower: 'tolower', + tolower_l: 'tolower', // The following functions are defined as macros in glibc. islower: function(chr) { return chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}; }, + islower_l: 'islower', isupper: function(chr) { return chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}}; }, + isupper_l: 'isupper', isalpha: function(chr) { return (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) || (chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}}); }, + isalpha_l: 'isalpha', isdigit: function(chr) { return chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}}; }, - isdigit_l: 'isdigit', // no locale support yet + isdigit_l: 'isdigit', isxdigit: function(chr) { return (chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}}) || (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('f') }}}) || (chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('F') }}}); }, - isxdigit_l: 'isxdigit', // no locale support yet + isxdigit_l: 'isxdigit', isalnum: function(chr) { return (chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}}) || (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) || (chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}}); }, + isalnum_l: 'isalnum', ispunct: function(chr) { return (chr >= {{{ charCode('!') }}} && chr <= {{{ charCode('/') }}}) || (chr >= {{{ charCode(':') }}} && chr <= {{{ charCode('@') }}}) || (chr >= {{{ charCode('[') }}} && chr <= {{{ charCode('`') }}}) || (chr >= {{{ charCode('{') }}} && chr <= {{{ charCode('~') }}}); }, + ispunct_l: 'ispunct', isspace: function(chr) { return (chr == 32) || (chr >= 9 && chr <= 13); }, + isspace_l: 'isspace', isblank: function(chr) { return chr == {{{ charCode(' ') }}} || chr == {{{ charCode('\t') }}}; }, + isblank_l: 'isblank', iscntrl: function(chr) { return (0 <= chr && chr <= 0x1F) || chr === 0x7F; }, + iscntrl_l: 'iscntrl', isprint: function(chr) { return 0x1F < chr && chr < 0x7F; }, + isprint_l: 'isprint', isgraph: function(chr) { return 0x20 < chr && chr < 0x7F; }, + isgraph_l: 'isgraph', // Lookup tables for glibc ctype implementation. __ctype_b_loc: function() { // http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/baselib---ctype-b-loc.html @@ -8884,7 +8897,7 @@ function autoAddDeps(object, name) { } // Add aborting stubs for various libc stuff needed by libc++ -['pthread_cond_signal', 'pthread_equal', 'wcstol', 'wcstoll', 'wcstoul', 'wcstoull', 'wcstof', 'wcstod', 'wcstold', 'swprintf', 'pthread_join', 'pthread_detach', 'strcoll_l', 'strxfrm_l', 'wcscoll_l', 'toupper_l', 'tolower_l', 'iswspace_l', 'iswprint_l', 'iswcntrl_l', 'iswupper_l', 'iswlower_l', 'iswalpha_l', 'iswdigit_l', 'iswpunct_l', 'iswxdigit_l', 'iswblank_l', 'wcsxfrm_l', 'towupper_l', 'towlower_l', 'catgets', 'catopen', 'catclose'].forEach(function(aborter) { +['pthread_cond_signal', 'pthread_equal', 'wcstol', 'wcstoll', 'wcstoul', 'wcstoull', 'wcstof', 'wcstod', 'wcstold', 'pthread_join', 'pthread_detach', 'catgets', 'catopen', 'catclose'].forEach(function(aborter) { LibraryManager.library[aborter] = function() { throw 'TODO: ' + aborter }; }); diff --git a/system/lib/libc/musl/src/internal/locale_impl.h b/system/lib/libc/musl/src/internal/locale_impl.h new file mode 100644 index 00000000..c268124f --- /dev/null +++ b/system/lib/libc/musl/src/internal/locale_impl.h @@ -0,0 +1,5 @@ +#include <locale.h> + +struct __locale { + int dummy; +}; diff --git a/system/lib/libc/musl/src/internal/stdio_impl.h b/system/lib/libc/musl/src/internal/stdio_impl.h new file mode 100644 index 00000000..2083b2fe --- /dev/null +++ b/system/lib/libc/musl/src/internal/stdio_impl.h @@ -0,0 +1,92 @@ +#ifndef _STDIO_IMPL_H +#define _STDIO_IMPL_H + +#include <stdio.h> +#include "syscall.h" +#include "libc.h" + +#define UNGET 8 + +#define FFINALLOCK(f) ((f)->lock>=0 ? __lockfile((f)) : 0) +#define FLOCK(f) int __need_unlock = ((f)->lock>=0 ? __lockfile((f)) : 0) +#define FUNLOCK(f) if (__need_unlock) __unlockfile((f)); else + +#define F_PERM 1 +#define F_NORD 4 +#define F_NOWR 8 +#define F_EOF 16 +#define F_ERR 32 +#define F_SVB 64 + +struct _IO_FILE { + unsigned flags; + unsigned char *rpos, *rend; + int (*close)(FILE *); + unsigned char *wend, *wpos; + unsigned char *mustbezero_1; + unsigned char *wbase; + size_t (*read)(FILE *, unsigned char *, size_t); + size_t (*write)(FILE *, const unsigned char *, size_t); + off_t (*seek)(FILE *, off_t, int); + unsigned char *buf; + size_t buf_size; + FILE *prev, *next; + int fd; + int pipe_pid; + long lockcount; + short dummy3; + signed char mode; + signed char lbf; + int lock; + int waiters; + void *cookie; + off_t off; + char *getln_buf; + void *mustbezero_2; + unsigned char *shend; + off_t shlim, shcnt; +}; + +size_t __stdio_read(FILE *, unsigned char *, size_t); +size_t __stdio_write(FILE *, const unsigned char *, size_t); +size_t __stdout_write(FILE *, const unsigned char *, size_t); +off_t __stdio_seek(FILE *, off_t, int); +int __stdio_close(FILE *); + +size_t __string_read(FILE *, unsigned char *, size_t); + +int __toread(FILE *); +int __towrite(FILE *); + +#if defined(__PIC__) && (100*__GNUC__+__GNUC_MINOR__ >= 303) +__attribute__((visibility("protected"))) +#endif +int __overflow(FILE *, int), __uflow(FILE *); + +int __fseeko(FILE *, off_t, int); +int __fseeko_unlocked(FILE *, off_t, int); +off_t __ftello(FILE *); +off_t __ftello_unlocked(FILE *); +size_t __fwritex(const unsigned char *, size_t, FILE *); +int __putc_unlocked(int, FILE *); + +FILE *__fdopen(int, const char *); +int __fmodeflags(const char *); + +#define OFLLOCK() LOCK(libc.ofl_lock) +#define OFLUNLOCK() UNLOCK(libc.ofl_lock) + +#define feof(f) ((f)->flags & F_EOF) +#define ferror(f) ((f)->flags & F_ERR) + +#define getc_unlocked(f) \ + ( ((f)->rpos < (f)->rend) ? *(f)->rpos++ : __uflow((f)) ) + +#define putc_unlocked(c, f) ( ((c)!=(f)->lbf && (f)->wpos<(f)->wend) \ + ? *(f)->wpos++ = (c) : __overflow((f),(c)) ) + +/* Caller-allocated FILE * operations */ +FILE *__fopen_rb_ca(const char *, FILE *, unsigned char *, size_t); +int __fclose_ca(FILE *); + +#endif diff --git a/system/lib/libc/musl/src/locale/iswalnum_l.c b/system/lib/libc/musl/src/locale/iswalnum_l.c new file mode 100644 index 00000000..c888060c --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswalnum_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswalnum_l(wint_t c, locale_t l) +{ + return iswalnum(c); +} diff --git a/system/lib/libc/musl/src/locale/iswalpha_l.c b/system/lib/libc/musl/src/locale/iswalpha_l.c new file mode 100644 index 00000000..cd2be91e --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswalpha_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswalpha_l(wint_t c, locale_t l) +{ + return iswalpha(c); +} diff --git a/system/lib/libc/musl/src/locale/iswblank_l.c b/system/lib/libc/musl/src/locale/iswblank_l.c new file mode 100644 index 00000000..f3a2691f --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswblank_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswblank_l(wint_t c, locale_t l) +{ + return iswblank(c); +} diff --git a/system/lib/libc/musl/src/locale/iswcntrl_l.c b/system/lib/libc/musl/src/locale/iswcntrl_l.c new file mode 100644 index 00000000..7681fe09 --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswcntrl_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswcntrl_l(wint_t c, locale_t l) +{ + return iswcntrl(c); +} diff --git a/system/lib/libc/musl/src/locale/iswctype_l.c b/system/lib/libc/musl/src/locale/iswctype_l.c new file mode 100644 index 00000000..13dfb1ed --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswctype_l.c @@ -0,0 +1,9 @@ +#include <wctype.h> +#include "libc.h" + +int iswctype_l(wint_t c, wctype_t t, locale_t l) +{ + return iswctype(c, t); +} + +weak_alias(iswctype_l, __iswctype_l); diff --git a/system/lib/libc/musl/src/locale/iswdigit_l.c b/system/lib/libc/musl/src/locale/iswdigit_l.c new file mode 100644 index 00000000..3de678c2 --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswdigit_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswdigit_l(wint_t c, locale_t l) +{ + return iswdigit(c); +} diff --git a/system/lib/libc/musl/src/locale/iswgraph_l.c b/system/lib/libc/musl/src/locale/iswgraph_l.c new file mode 100644 index 00000000..34df64fc --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswgraph_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswgraph_l(wint_t c, locale_t l) +{ + return iswgraph(c); +} diff --git a/system/lib/libc/musl/src/locale/iswlower_l.c b/system/lib/libc/musl/src/locale/iswlower_l.c new file mode 100644 index 00000000..c52421a0 --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswlower_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswlower_l(wint_t c, locale_t l) +{ + return iswlower(c); +} diff --git a/system/lib/libc/musl/src/locale/iswprint_l.c b/system/lib/libc/musl/src/locale/iswprint_l.c new file mode 100644 index 00000000..73d83ab3 --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswprint_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswprint_l(wint_t c, locale_t l) +{ + return iswprint(c); +} diff --git a/system/lib/libc/musl/src/locale/iswpunct_l.c b/system/lib/libc/musl/src/locale/iswpunct_l.c new file mode 100644 index 00000000..831e0e54 --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswpunct_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswpunct_l(wint_t c, locale_t l) +{ + return iswpunct(c); +} diff --git a/system/lib/libc/musl/src/locale/iswspace_l.c b/system/lib/libc/musl/src/locale/iswspace_l.c new file mode 100644 index 00000000..b507e9e3 --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswspace_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswspace_l(wint_t c, locale_t l) +{ + return iswspace(c); +} diff --git a/system/lib/libc/musl/src/locale/iswupper_l.c b/system/lib/libc/musl/src/locale/iswupper_l.c new file mode 100644 index 00000000..fc988ef1 --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswupper_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswupper_l(wint_t c, locale_t l) +{ + return iswupper(c); +} diff --git a/system/lib/libc/musl/src/locale/iswxdigit_l.c b/system/lib/libc/musl/src/locale/iswxdigit_l.c new file mode 100644 index 00000000..9527cf3e --- /dev/null +++ b/system/lib/libc/musl/src/locale/iswxdigit_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswxdigit_l(wint_t c, locale_t l) +{ + return iswxdigit(c); +} diff --git a/system/lib/libc/musl/src/locale/strfmon.c b/system/lib/libc/musl/src/locale/strfmon.c new file mode 100644 index 00000000..f510d9a4 --- /dev/null +++ b/system/lib/libc/musl/src/locale/strfmon.c @@ -0,0 +1,101 @@ +#include <stdio.h> +#include <ctype.h> +#include <stdarg.h> +#include <monetary.h> +#include <errno.h> +#include <stdarg.h> + +static ssize_t vstrfmon_l(char *s, size_t n, locale_t loc, const char *fmt, va_list ap) +{ + size_t l; + double x; + int fill, nogrp, negpar, nosym, left, intl; + int lp, rp, w, fw; + char *s0=s; + for (; n && *fmt; ) { + if (*fmt != '%') { + literal: + *s++ = *fmt++; + n--; + continue; + } + fmt++; + if (*fmt == '%') goto literal; + + fill = ' '; + nogrp = 0; + negpar = 0; + nosym = 0; + left = 0; + for (; ; fmt++) { + switch (*fmt) { + case '=': + fill = *++fmt; + continue; + case '^': + nogrp = 1; + continue; + case '(': + negpar = 1; + case '+': + continue; + case '!': + nosym = 1; + continue; + case '-': + left = 1; + continue; + } + break; + } + + for (fw=0; isdigit(*fmt); fmt++) + fw = 10*fw + (*fmt-'0'); + lp = 0; + rp = 2; + if (*fmt=='#') for (lp=0, fmt++; isdigit(*fmt); fmt++) + lp = 10*lp + (*fmt-'0'); + if (*fmt=='.') for (rp=0, fmt++; isdigit(*fmt); fmt++) + rp = 10*rp + (*fmt-'0'); + + intl = *fmt++ == 'i'; + + w = lp + 1 + rp; + if (!left && fw>w) w = fw; + + x = va_arg(ap, double); + l = snprintf(s, n, "%*.*f", w, rp, x); + if (l >= n) { + errno = E2BIG; + return -1; + } + s += l; + n -= l; + } + return s-s0; +} + +ssize_t strfmon_l(char *restrict s, size_t n, locale_t loc, const char *restrict fmt, ...) +{ + va_list ap; + ssize_t ret; + + va_start(ap, fmt); + ret = vstrfmon_l(s, n, loc, fmt, ap); + va_end(ap); + + return ret; +} + + +ssize_t strfmon(char *restrict s, size_t n, const char *restrict fmt, ...) +{ + va_list ap; + ssize_t ret; + + va_start(ap, fmt); + ret = vstrfmon_l(s, n, 0, fmt, ap); + va_end(ap); + + return ret; +} diff --git a/system/lib/libc/musl/src/locale/strxfrm.c b/system/lib/libc/musl/src/locale/strxfrm.c new file mode 100644 index 00000000..32c46193 --- /dev/null +++ b/system/lib/libc/musl/src/locale/strxfrm.c @@ -0,0 +1,18 @@ +#include <string.h> +#include <locale.h> +#include "libc.h" + +/* collate only by code points */ +size_t __strxfrm_l(char *restrict dest, const char *restrict src, size_t n, locale_t loc) +{ + size_t l = strlen(src); + if (n > l) strcpy(dest, src); + return l; +} + +size_t strxfrm(char *restrict dest, const char *restrict src, size_t n) +{ + return __strxfrm_l(dest, src, n, 0); +} + +weak_alias(__strxfrm_l, strxfrm_l); diff --git a/system/lib/libc/musl/src/locale/towctrans_l.c b/system/lib/libc/musl/src/locale/towctrans_l.c new file mode 100644 index 00000000..6222058c --- /dev/null +++ b/system/lib/libc/musl/src/locale/towctrans_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +wint_t towctrans_l(wint_t c, wctrans_t t, locale_t l) +{ + return towctrans(c, t); +} diff --git a/system/lib/libc/musl/src/locale/towlower_l.c b/system/lib/libc/musl/src/locale/towlower_l.c new file mode 100644 index 00000000..aaaea370 --- /dev/null +++ b/system/lib/libc/musl/src/locale/towlower_l.c @@ -0,0 +1,9 @@ +#include <wctype.h> +#include "libc.h" + +wint_t towlower_l(wint_t c, locale_t l) +{ + return towlower(c); +} + +weak_alias(towlower_l, __towlower_l); diff --git a/system/lib/libc/musl/src/locale/towupper_l.c b/system/lib/libc/musl/src/locale/towupper_l.c new file mode 100644 index 00000000..ad02a4be --- /dev/null +++ b/system/lib/libc/musl/src/locale/towupper_l.c @@ -0,0 +1,9 @@ +#include <wctype.h> +#include "libc.h" + +wint_t towupper_l(wint_t c, locale_t l) +{ + return towupper(c); +} + +weak_alias(towupper_l, __towupper_l); diff --git a/system/lib/libc/musl/src/locale/wcscoll.c b/system/lib/libc/musl/src/locale/wcscoll.c new file mode 100644 index 00000000..20a60900 --- /dev/null +++ b/system/lib/libc/musl/src/locale/wcscoll.c @@ -0,0 +1,16 @@ +#include <wchar.h> +#include <locale.h> +#include "libc.h" + +/* FIXME: stub */ +int __wcscoll_l(const wchar_t *l, const wchar_t *r, locale_t locale) +{ + return wcscmp(l, r); +} + +int wcscoll(const wchar_t *l, const wchar_t *r) +{ + return __wcscoll_l(l, r, 0); +} + +weak_alias(__wcscoll_l, wcscoll_l); diff --git a/system/lib/libc/musl/src/locale/wcscoll_l.c b/system/lib/libc/musl/src/locale/wcscoll_l.c new file mode 100644 index 00000000..f257ec8d --- /dev/null +++ b/system/lib/libc/musl/src/locale/wcscoll_l.c @@ -0,0 +1,6 @@ +#include <wchar.h> + +int wcscoll_l(const wchar_t *l, const wchar_t *r, locale_t locale) +{ + return wcscoll(l, r); +} diff --git a/system/lib/libc/musl/src/locale/wcsxfrm.c b/system/lib/libc/musl/src/locale/wcsxfrm.c new file mode 100644 index 00000000..cb79c97e --- /dev/null +++ b/system/lib/libc/musl/src/locale/wcsxfrm.c @@ -0,0 +1,21 @@ +#include <wchar.h> +#include <locale.h> +#include "libc.h" + +/* collate only by code points */ +size_t __wcsxfrm_l(wchar_t *restrict dest, const wchar_t *restrict src, size_t n, locale_t loc) +{ + size_t l = wcslen(src); + if (l >= n) { + wmemcpy(dest, src, n-1); + dest[n-1] = 0; + } else wcscpy(dest, src); + return l; +} + +size_t wcsxfrm(wchar_t *restrict dest, const wchar_t *restrict src, size_t n) +{ + return __wcsxfrm_l(dest, src, n, 0); +} + +weak_alias(__wcsxfrm_l, wcsxfrm_l); diff --git a/system/lib/libc/musl/src/locale/wcsxfrm_l.c b/system/lib/libc/musl/src/locale/wcsxfrm_l.c new file mode 100644 index 00000000..66a00193 --- /dev/null +++ b/system/lib/libc/musl/src/locale/wcsxfrm_l.c @@ -0,0 +1,6 @@ +#include <wchar.h> + +size_t wcsxfrm_l(wchar_t *restrict dest, const wchar_t *restrict src, size_t n, locale_t locale) +{ + return wcsxfrm(dest, src, n); +} diff --git a/system/lib/libc/musl/src/locale/wctrans_l.c b/system/lib/libc/musl/src/locale/wctrans_l.c new file mode 100644 index 00000000..dae3381e --- /dev/null +++ b/system/lib/libc/musl/src/locale/wctrans_l.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +wctrans_t wctrans_l(const char *s, locale_t l) +{ + return wctrans(s); +} diff --git a/system/lib/libc/musl/src/locale/wctype_l.c b/system/lib/libc/musl/src/locale/wctype_l.c new file mode 100644 index 00000000..601bab37 --- /dev/null +++ b/system/lib/libc/musl/src/locale/wctype_l.c @@ -0,0 +1,9 @@ +#include <wctype.h> +#include "libc.h" + +wctype_t wctype_l(const char *s, locale_t l) +{ + return wctype(s); +} + +weak_alias(wctype_l, __wctype_l); diff --git a/system/lib/libc/musl/src/stdio/fwprintf.c b/system/lib/libc/musl/src/stdio/fwprintf.c new file mode 100644 index 00000000..9ce4f010 --- /dev/null +++ b/system/lib/libc/musl/src/stdio/fwprintf.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <stdarg.h> +#include <wchar.h> + +int fwprintf(FILE *restrict f, const wchar_t *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vfwprintf(f, fmt, ap); + va_end(ap); + return ret; +} diff --git a/system/lib/libc/musl/src/stdio/swprintf.c b/system/lib/libc/musl/src/stdio/swprintf.c new file mode 100644 index 00000000..cbf83d23 --- /dev/null +++ b/system/lib/libc/musl/src/stdio/swprintf.c @@ -0,0 +1,14 @@ +#include <stdio.h> +#include <stdarg.h> +#include <wchar.h> + +int swprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vswprintf(s, n, fmt, ap); + va_end(ap); + return ret; +} + diff --git a/system/lib/libc/musl/src/stdio/vfwprintf.c b/system/lib/libc/musl/src/stdio/vfwprintf.c new file mode 100644 index 00000000..eb079312 --- /dev/null +++ b/system/lib/libc/musl/src/stdio/vfwprintf.c @@ -0,0 +1,361 @@ +#include "stdio_impl.h" +#include <errno.h> +#include <ctype.h> +#include <limits.h> +#include <string.h> +#include <stdarg.h> +#include <wchar.h> +#include <inttypes.h> + +/* Convenient bit representation for modifier flags, which all fall + * within 31 codepoints of the space character. */ + +#define ALT_FORM (1U<<'#'-' ') +#define ZERO_PAD (1U<<'0'-' ') +#define LEFT_ADJ (1U<<'-'-' ') +#define PAD_POS (1U<<' '-' ') +#define MARK_POS (1U<<'+'-' ') +#define GROUPED (1U<<'\''-' ') + +#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED) + +#if UINT_MAX == ULONG_MAX +#define LONG_IS_INT +#endif + +#if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX +#define ODD_TYPES +#endif + +/* State machine to accept length modifiers + conversion specifiers. + * Result is 0 on failure, or an argument type to pop on success. */ + +enum { + BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE, + ZTPRE, JPRE, + STOP, + PTR, INT, UINT, ULLONG, +#ifndef LONG_IS_INT + LONG, ULONG, +#else +#define LONG INT +#define ULONG UINT +#endif + SHORT, USHORT, CHAR, UCHAR, +#ifdef ODD_TYPES + LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR, +#else +#define LLONG ULLONG +#define SIZET ULONG +#define IMAX LLONG +#define UMAX ULLONG +#define PDIFF LONG +#define UIPTR ULONG +#endif + DBL, LDBL, + NOARG, + MAXSTATE +}; + +#define S(x) [(x)-'A'] + +static const unsigned char states[]['z'-'A'+1] = { + { /* 0: bare types */ + S('d') = INT, S('i') = INT, + S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT, + S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, + S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, + S('c') = CHAR, S('C') = INT, + S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, + S('m') = NOARG, + S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, + S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE, + }, { /* 1: l-prefixed */ + S('d') = LONG, S('i') = LONG, + S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG, + S('c') = INT, S('s') = PTR, S('n') = PTR, + S('l') = LLPRE, + }, { /* 2: ll-prefixed */ + S('d') = LLONG, S('i') = LLONG, + S('o') = ULLONG, S('u') = ULLONG, + S('x') = ULLONG, S('X') = ULLONG, + S('n') = PTR, + }, { /* 3: h-prefixed */ + S('d') = SHORT, S('i') = SHORT, + S('o') = USHORT, S('u') = USHORT, + S('x') = USHORT, S('X') = USHORT, + S('n') = PTR, + S('h') = HHPRE, + }, { /* 4: hh-prefixed */ + S('d') = CHAR, S('i') = CHAR, + S('o') = UCHAR, S('u') = UCHAR, + S('x') = UCHAR, S('X') = UCHAR, + S('n') = PTR, + }, { /* 5: L-prefixed */ + S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL, + S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL, + S('n') = PTR, + }, { /* 6: z- or t-prefixed (assumed to be same size) */ + S('d') = PDIFF, S('i') = PDIFF, + S('o') = SIZET, S('u') = SIZET, + S('x') = SIZET, S('X') = SIZET, + S('n') = PTR, + }, { /* 7: j-prefixed */ + S('d') = IMAX, S('i') = IMAX, + S('o') = UMAX, S('u') = UMAX, + S('x') = UMAX, S('X') = UMAX, + S('n') = PTR, + } +}; + +#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A') + +union arg +{ + uintmax_t i; + long double f; + void *p; +}; + +static void pop_arg(union arg *arg, int type, va_list *ap) +{ + /* Give the compiler a hint for optimizing the switch. */ + if ((unsigned)type > MAXSTATE) return; + switch (type) { + case PTR: arg->p = va_arg(*ap, void *); + break; case INT: arg->i = va_arg(*ap, int); + break; case UINT: arg->i = va_arg(*ap, unsigned int); +#ifndef LONG_IS_INT + break; case LONG: arg->i = va_arg(*ap, long); + break; case ULONG: arg->i = va_arg(*ap, unsigned long); +#endif + break; case ULLONG: arg->i = va_arg(*ap, unsigned long long); + break; case SHORT: arg->i = (short)va_arg(*ap, int); + break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int); + break; case CHAR: arg->i = (signed char)va_arg(*ap, int); + break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int); +#ifdef ODD_TYPES + break; case LLONG: arg->i = va_arg(*ap, long long); + break; case SIZET: arg->i = va_arg(*ap, size_t); + break; case IMAX: arg->i = va_arg(*ap, intmax_t); + break; case UMAX: arg->i = va_arg(*ap, uintmax_t); + break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t); + break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *); +#endif + break; case DBL: arg->f = va_arg(*ap, double); + break; case LDBL: arg->f = va_arg(*ap, long double); + } +} + +static void out(FILE *f, const wchar_t *s, size_t l) +{ + while (l--) fputwc(*s++, f); +} + +static int getint(wchar_t **s) { + int i; + for (i=0; iswdigit(**s); (*s)++) + i = 10*i + (**s-'0'); + return i; +} + +static const char sizeprefix['y'-'a'] = { +['a'-'a']='L', ['e'-'a']='L', ['f'-'a']='L', ['g'-'a']='L', +['d'-'a']='j', ['i'-'a']='j', ['o'-'a']='j', ['u'-'a']='j', ['x'-'a']='j', +['p'-'a']='j' +}; + +static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_arg, int *nl_type) +{ + wchar_t *a, *z, *s=(wchar_t *)fmt, *s0; + unsigned l10n=0, litpct, fl; + int w, p; + union arg arg; + int argpos; + unsigned st, ps; + int cnt=0, l=0; + int i; + int t; + char *bs; + char charfmt[16]; + wchar_t wc; + + for (;;) { + /* Update output count, end loop when fmt is exhausted */ + if (cnt >= 0) { + if (l > INT_MAX - cnt) { + if (!ferror(f)) errno = EOVERFLOW; + cnt = -1; + } else cnt += l; + } + if (!*s) break; + + /* Handle literal text and %% format specifiers */ + for (a=s; *s && *s!='%'; s++); + litpct = wcsspn(s, L"%")/2; /* Optimize %%%% runs */ + z = s+litpct; + s += 2*litpct; + l = z-a; + if (f) out(f, a, l); + if (l) continue; + + if (iswdigit(s[1]) && s[2]=='$') { + l10n=1; + argpos = s[1]-'0'; + s+=3; + } else { + argpos = -1; + s++; + } + + /* Read modifier flags */ + for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++) + fl |= 1U<<*s-' '; + + /* Read field width */ + if (*s=='*') { + if (iswdigit(s[1]) && s[2]=='$') { + l10n=1; + nl_type[s[1]-'0'] = INT; + w = nl_arg[s[1]-'0'].i; + s+=3; + } else if (!l10n) { + w = f ? va_arg(*ap, int) : 0; + s++; + } else return -1; + if (w<0) fl|=LEFT_ADJ, w=-w; + } else if ((w=getint(&s))<0) return -1; + + /* Read precision */ + if (*s=='.' && s[1]=='*') { + if (isdigit(s[2]) && s[3]=='$') { + nl_type[s[2]-'0'] = INT; + p = nl_arg[s[2]-'0'].i; + s+=4; + } else if (!l10n) { + p = f ? va_arg(*ap, int) : 0; + s+=2; + } else return -1; + } else if (*s=='.') { + s++; + p = getint(&s); + } else p = -1; + + /* Format specifier state machine */ + s0=s; + st=0; + do { + if (OOB(*s)) return -1; + ps=st; + st=states[st]S(*s++); + } while (st-1<STOP); + if (!st) return -1; + + /* Check validity of argument type (nl/normal) */ + if (st==NOARG) { + if (argpos>=0) return -1; + else if (!f) continue; + } else { + if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos]; + else if (f) pop_arg(&arg, st, ap); + else return 0; + } + + if (!f) continue; + t = s[-1]; + if (ps && (t&15)==3) t&=~32; + + switch (t) { + case 'n': + switch(ps) { + case BARE: *(int *)arg.p = cnt; break; + case LPRE: *(long *)arg.p = cnt; break; + case LLPRE: *(long long *)arg.p = cnt; break; + case HPRE: *(unsigned short *)arg.p = cnt; break; + case HHPRE: *(unsigned char *)arg.p = cnt; break; + case ZTPRE: *(size_t *)arg.p = cnt; break; + case JPRE: *(uintmax_t *)arg.p = cnt; break; + } + continue; + case 'c': + fputwc(btowc(arg.i), f); + l = 1; + continue; + case 'C': + fputwc(arg.i, f); + l = 1; + continue; + case 'S': + a = arg.p; + z = wmemchr(a, 0, p); + if (!z) z=a+p; + else p=z-a; + if (w<p) w=p; + if (!(fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, ""); + out(f, a, p); + if ((fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, ""); + l=w; + continue; + case 's': + bs = arg.p; + if (p<0) p = INT_MAX; + for (i=l=0; l<p && (i=mbtowc(&wc, bs, MB_LEN_MAX))>0; bs+=i, l++); + if (i<0) return -1; + p=l; + if (w<p) w=p; + if (!(fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, ""); + bs = arg.p; + while (l--) { + i=mbtowc(&wc, bs, MB_LEN_MAX); + bs+=i; + fputwc(wc, f); + } + if ((fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, ""); + l=w; + continue; + } + + snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c%c", + "#"+!(fl & ALT_FORM), + "+"+!(fl & MARK_POS), + "-"+!(fl & LEFT_ADJ), + " "+!(fl & PAD_POS), + "0"+!(fl & ZERO_PAD), + sizeprefix[(t|32)-'a'], t); + + switch (t|32) { + case 'a': case 'e': case 'f': case 'g': + l = fprintf(f, charfmt, w, p, arg.f); + break; + case 'd': case 'i': case 'o': case 'u': case 'x': case 'p': + l = fprintf(f, charfmt, w, p, arg.i); + break; + } + } + + if (f) return cnt; + if (!l10n) return 0; + + for (i=1; i<=NL_ARGMAX && nl_type[i]; i++) + pop_arg(nl_arg+i, nl_type[i], ap); + for (; i<=NL_ARGMAX && !nl_type[i]; i++); + if (i<=NL_ARGMAX) return -1; + return 1; +} + +int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap) +{ + va_list ap2; + int nl_type[NL_ARGMAX] = {0}; + union arg nl_arg[NL_ARGMAX]; + int ret; + + va_copy(ap2, ap); + if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) return -1; + + FLOCK(f); + ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type); + FUNLOCK(f); + va_end(ap2); + return ret; +} diff --git a/system/lib/libc/musl/src/stdio/vswprintf.c b/system/lib/libc/musl/src/stdio/vswprintf.c new file mode 100644 index 00000000..7d237bae --- /dev/null +++ b/system/lib/libc/musl/src/stdio/vswprintf.c @@ -0,0 +1,53 @@ +#include "stdio_impl.h" +#include <limits.h> +#include <string.h> +#include <errno.h> +#include <stdint.h> +#include <wchar.h> + +struct cookie { + wchar_t *ws; + size_t l; +}; + +static size_t sw_write(FILE *f, const unsigned char *s, size_t l) +{ + size_t l0 = l; + int i = 0; + struct cookie *c = f->cookie; + if (s!=f->wbase && sw_write(f, f->wbase, f->wpos-f->wbase)==-1) + return -1; + while (c->l && l && (i=mbtowc(c->ws, (void *)s, l))>=0) { + s+=i; + l-=i; + c->l--; + c->ws++; + } + *c->ws = 0; + return i<0 ? i : l0; +} + +int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_list ap) +{ + int r; + FILE f; + unsigned char buf[256]; + struct cookie c = { s, n-1 }; + + memset(&f, 0, sizeof(FILE)); + f.lbf = EOF; + f.write = sw_write; + f.buf_size = sizeof buf; + f.buf = buf; + f.lock = -1; + f.cookie = &c; + if (!n) { + return -1; + } else if (n > INT_MAX) { + errno = EOVERFLOW; + return -1; + } + r = vfwprintf(&f, fmt, ap); + sw_write(&f, 0, 0); + return r>=n ? -1 : r; +} diff --git a/system/lib/libc/musl/src/stdio/vwprintf.c b/system/lib/libc/musl/src/stdio/vwprintf.c new file mode 100644 index 00000000..eeeecdc7 --- /dev/null +++ b/system/lib/libc/musl/src/stdio/vwprintf.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include <wchar.h> + +int vwprintf(const wchar_t *restrict fmt, va_list ap) +{ + return vfwprintf(stdout, fmt, ap); +} diff --git a/system/lib/libc/musl/src/stdio/wprintf.c b/system/lib/libc/musl/src/stdio/wprintf.c new file mode 100644 index 00000000..342cd979 --- /dev/null +++ b/system/lib/libc/musl/src/stdio/wprintf.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <stdarg.h> +#include <wchar.h> + +int wprintf(const wchar_t *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vwprintf(fmt, ap); + va_end(ap); + return ret; +} diff --git a/system/lib/libcextra.symbols b/system/lib/libcextra.symbols index a365271d..806b49db 100644 --- a/system/lib/libcextra.symbols +++ b/system/lib/libcextra.symbols @@ -1,20 +1,41 @@ + W __iswctype_l + T __strxfrm_l + W __towlower_l + W __towupper_l + T __wcscoll_l + T __wcsxfrm_l + W __wctype_l T btowc T ecvt T fcvt + T fwprintf T gcvt T iswalnum + T iswalnum_l T iswalpha + T iswalpha_l T iswblank + T iswblank_l T iswcntrl + T iswcntrl_l T iswctype + T iswctype_l T iswdigit + T iswdigit_l T iswgraph + T iswgraph_l T iswlower + T iswlower_l T iswprint + T iswprint_l T iswpunct + T iswpunct_l T iswspace + T iswspace_l T iswupper + T iswupper_l T iswxdigit + T iswxdigit_l T mblen T mbrlen T mbrtowc @@ -23,21 +44,36 @@ T mbsrtowcs T mbstowcs T mbtowc + T strfmon + T strfmon_l + T strxfrm + W strxfrm_l + T swprintf T towctrans + T towctrans_l T towlower + T towlower_l T towupper + T towupper_l + T vfwprintf + T vswprintf + T vwprintf T wcpcpy T wcpncpy T wcrtomb T wcscasecmp + T wcscasecmp_l T wcscat T wcschr T wcscmp + T wcscoll + T wcscoll_l T wcscpy T wcscspn T wcsdup T wcslen T wcsncasecmp + T wcsncasecmp_l T wcsncat T wcsncmp T wcsncpy @@ -52,13 +88,18 @@ T wcstombs T wcswcs T wcswidth + T wcsxfrm + T wcsxfrm_l T wctob T wctomb T wctrans + T wctrans_l T wctype + T wctype_l T wcwidth T wmemchr T wmemcmp T wmemcpy T wmemmove T wmemset + T wprintf diff --git a/tools/shared.py b/tools/shared.py index 2d9ae9f6..4d0f92b5 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -304,7 +304,7 @@ def find_temp_directory(): # we re-check sanity when the settings are changed) # We also re-check sanity and clear the cache when the version changes -EMSCRIPTEN_VERSION = '1.6.1' +EMSCRIPTEN_VERSION = '1.6.2' def generate_sanity(): return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT |