Merge remote-tracking branch 'origin/master' into wchar - scc - simple c99 compiler
 (HTM) git clone git://git.simple-cc.org/scc
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 3b42911841f616a37e3fa7bd5f4ad7177ce959cf
 (DIR) parent b96ef460770e7d0bf335cbadbed7efd2db08199e
 (HTM) Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
       Date:   Tue, 25 Mar 2025 10:52:47 +0100
       
       Merge remote-tracking branch 'origin/master' into wchar
       
       Diffstat:
         M include/bits/darwin/sys/cdefs.h     |      10 +---------
         M include/bits/dragonfly/sys/cdefs.h  |       9 +--------
         M include/bits/freebsd/sys/cdefs.h    |       9 +--------
         M include/bits/linux/sys/cdefs.h      |       9 +--------
         M include/bits/netbsd/sys/cdefs.h     |       9 +--------
         M include/bits/openbsd/sys/cdefs.h    |       9 +--------
         M include/stdlib.h                    |       2 --
         M include/wchar.h                     |      30 +++++++++++++++++++-----------
         M src/cmd/scc-make/rules.c            |      13 +++++++++----
         M src/libc/arch/bsd/Makefile          |       4 +---
         D src/libc/arch/bsd/_mbsget.c         |       9 ---------
         D src/libc/arch/bsd/_mbsset.c         |       9 ---------
         M src/libc/arch/darwin/Makefile       |       2 --
         D src/libc/arch/darwin/_mbsget.c      |       9 ---------
         D src/libc/arch/darwin/_mbsset.c      |      10 ----------
         M src/libc/arch/linux/Makefile        |       2 --
         D src/libc/arch/linux/_mbsget.c       |       9 ---------
         D src/libc/arch/linux/_mbsset.c       |       9 ---------
         M src/libc/libc.h                     |       7 ++-----
         M src/libc/objs/amd64-linux.mk        |       2 --
         M src/libc/objs/amd64-netbsd.mk       |       2 --
         M src/libc/objs/amd64-openbsd.mk      |       2 --
         M src/libc/objs/common-objs.mk        |       4 ++++
         M src/libc/stdlib/mblen.c             |       9 ++++++++-
         M src/libc/stdlib/mbstowcs.c          |       4 +++-
         M src/libc/stdlib/mbtowc.c            |      10 +++++++++-
         M src/libc/stdlib/wcstombs.c          |       4 +++-
         M src/libc/stdlib/wctomb.c            |       4 +++-
         M src/libc/string/strcmp.c            |       2 +-
         M src/libc/wchar/_validutf8.c         |       2 +-
         M src/libc/wchar/mbrlen.c             |       4 ++++
         M src/libc/wchar/mbrtowc.c            |      92 +++++++++++++++++++++++--------
         M src/libc/wchar/mbsinit.c            |       4 +---
         M src/libc/wchar/mbsrtowcs.c          |      26 +++++++++++++++++++++-----
         A src/libc/wchar/wcscmp.c             |      15 +++++++++++++++
         A src/libc/wchar/wcscoll.c            |       9 +++++++++
         A src/libc/wchar/wcscpy.c             |      16 ++++++++++++++++
         A src/libc/wchar/wcsncmp.c            |      18 ++++++++++++++++++
         M tests/libc/execute/.gitignore       |      10 ++++++++++
         A tests/libc/execute/0038-mbsinit.c   |      29 +++++++++++++++++++++++++++++
         A tests/libc/execute/0039-mbrtowc.c   |      84 +++++++++++++++++++++++++++++++
         A tests/libc/execute/0040-wcrtomb.c   |     102 +++++++++++++++++++++++++++++++
         A tests/libc/execute/0041-mbrlen.c    |      75 +++++++++++++++++++++++++++++++
         A tests/libc/execute/0042-mbsrtowcs.c |     126 +++++++++++++++++++++++++++++++
         A tests/libc/execute/0044-wcslen.c    |      28 ++++++++++++++++++++++++++++
         A tests/libc/execute/0045-wcscmp.c    |      36 +++++++++++++++++++++++++++++++
         A tests/libc/execute/0046-wcsncmp.c   |      30 ++++++++++++++++++++++++++++++
         A tests/libc/execute/0047-wcscoll.c   |      36 +++++++++++++++++++++++++++++++
         A tests/libc/execute/0048-wcscpy.c    |      32 +++++++++++++++++++++++++++++++
         M tests/libc/execute/libc-tests.lst   |      10 ++++++++++
         A tests/libc/execute/mbtest.h         |      44 +++++++++++++++++++++++++++++++
         A tests/make/execute/0107-inference.… |      31 +++++++++++++++++++++++++++++++
       
       52 files changed, 895 insertions(+), 177 deletions(-)
       ---
 (DIR) diff --git a/include/bits/darwin/sys/cdefs.h b/include/bits/darwin/sys/cdefs.h
       @@ -1,9 +1 @@
       -#ifdef _NEED_MBSTATE_T
       -#ifndef _MBSTATE_T
       -typedef struct {
       -    unsigned char state[4];
       -    size_t count;
       -} mbstate_t;
       -#define _MBSTATE_T
       -#endif
       -#endif
       +/* nothing fpr darwin */
 (DIR) diff --git a/include/bits/dragonfly/sys/cdefs.h b/include/bits/dragonfly/sys/cdefs.h
       @@ -1,8 +1 @@
       -#ifdef _NEED_MBSTATE_T
       -#ifndef _MBSTATE_T
       -typedef union {
       -        char __mbstate8[128];
       -} mbstate_t;
       -#define _MBSTATE_T
       -#endif
       -#endif
       +/* nothing for dragonfly */
 (DIR) diff --git a/include/bits/freebsd/sys/cdefs.h b/include/bits/freebsd/sys/cdefs.h
       @@ -1,8 +1 @@
       -#ifdef _NEED_MBSTATE_T
       -#ifndef _MBSTATE_T
       -typedef union {
       -        char __mbstate8[128];
       -} mbstate_t;
       -#define _MBSTATE_T
       -#endif
       -#endif
       +/* nothing for Openbsd */
 (DIR) diff --git a/include/bits/linux/sys/cdefs.h b/include/bits/linux/sys/cdefs.h
       @@ -1,8 +1 @@
       -#ifdef _NEED_MBSTATE_T
       -#ifndef _MBSTATE_T
       -typedef struct __mbstate_t {
       -        unsigned __opaque1, __opaque2;
       -} mbstate_t;
       -#define _MBSTATE_T
       -#endif
       -#endif
       +/* nothing for Linux */
 (DIR) diff --git a/include/bits/netbsd/sys/cdefs.h b/include/bits/netbsd/sys/cdefs.h
       @@ -1,8 +1 @@
       -#ifdef _NEED_MBSTATE_T
       -#ifndef _MBSTATE_T
       -typedef union {
       -        char __mbstate8[128];
       -} mbstate_t;
       -#define _MBSTATE_T
       -#endif
       -#endif
       +/* nothing for netbsd */
 (DIR) diff --git a/include/bits/openbsd/sys/cdefs.h b/include/bits/openbsd/sys/cdefs.h
       @@ -1,8 +1 @@
       -#ifdef _NEED_MBSTATE_T
       -#ifndef _MBSTATE_T
       -typedef union {
       -        char __mbstate8[128];
       -} mbstate_t;
       -#define _MBSTATE_T
       -#endif
       -#endif
       +/* nothing for Openbsd */
 (DIR) diff --git a/include/stdlib.h b/include/stdlib.h
       @@ -66,6 +66,4 @@ extern int wctomb(char *, wchar_t);
        extern size_t mbstowcs(wchar_t *restrict, const char *restrict, size_t);
        extern size_t wcstombs(char *restrict, const wchar_t *restrict, size_t);
        
       -#define mblen(s,n) mbtowc(NULL, s, n)
       -
        #endif
 (DIR) diff --git a/include/wchar.h b/include/wchar.h
       @@ -8,10 +8,15 @@
        #define _NEED_WCHARLIM
        #define _NEED_WINT
        #define _NEED_VA_LIST
       -#define _NEED_MBSTATE_T
        #include <arch/cdefs.h>
        #include <sys/cdefs.h>
        
       +typedef struct {
       +        unsigned char oc;
       +        unsigned char sh;
       +        wchar_t wc;
       +} mbstate_t;
       +
        struct tm;
        struct _FILE;
        
       @@ -30,8 +35,11 @@ extern wint_t fgetwc(struct _FILE *);
        extern wint_t fputwc(wchar_t c, struct _FILE *);
        extern wint_t getwc(struct _FILE *);
        extern wint_t putwc(wchar_t, struct _FILE *);
       -extern int fwide(struct _FILE *, int);
       +extern wint_t getwchar(void);
       +extern wint_t putwchar(wchar_t);
        extern wint_t ungetwc(wint_t, struct _FILE *);
       +
       +extern int fwide(struct _FILE *, int);
        extern wchar_t *fgetws(wchar_t *restrict, int, struct _FILE *restrict);
        extern int fputws(const wchar_t *restrict, struct _FILE *restrict);
        
       @@ -40,9 +48,6 @@ extern int swscanf(const wchar_t *restrict, const wchar_t *restrict, ...);
        extern int wprintf(const wchar_t *restrict, ...);
        extern int wscanf(const wchar_t *restrict, ...);
        
       -extern wint_t getwchar(void);
       -extern wint_t putwchar(wchar_t);
       -
        extern double wcstod(const wchar_t *restrict, wchar_t **restrict);
        extern float wcstof(const wchar_t *restrict, wchar_t **restrict);
        extern long double wcstold(const wchar_t *restrict, wchar_t **restrict);
       @@ -57,13 +62,17 @@ extern wchar_t *wcsncpy(wchar_t *restrict, const wchar_t *restrict, size_t);
        
        extern wchar_t *wmemcpy(wchar_t *restrict, const wchar_t *restrict, size_t);
        extern wchar_t *wmemmove(wchar_t *, const wchar_t *, size_t);
       +extern wchar_t *wmemset(wchar_t *, wchar_t, size_t);
       +extern wchar_t *wmemchr(const wchar_t *, wchar_t, size_t);
       +extern int wmemcmp(const wchar_t *, const wchar_t *, size_t);
       +
       +extern size_t wcslen(const wchar_t *);
       +extern int wcscmp(const wchar_t *, const wchar_t *);
        extern wchar_t *wcscat(wchar_t *restrict, const wchar_t *restrict);
        extern wchar_t *wcsncat(wchar_t *restrict, const wchar_t *restrict, size_t);
       -extern int wcscmp(const wchar_t *, const wchar_t *);
        extern int wcscoll(const wchar_t *, const wchar_t *);
        extern int wcsncmp(const wchar_t *, const wchar_t *, size_t);
        extern size_t wcsxfrm(wchar_t *restrict, const wchar_t *restrict, size_t);
       -extern int wmemcmp(const wchar_t *, const wchar_t *, size_t);
        extern wchar_t *wcschr(const wchar_t *, wchar_t);
        extern size_t wcscspn(const wchar_t *, const wchar_t *);
        extern wchar_t *wcspbrk(const wchar_t *, const wchar_t *);
       @@ -71,12 +80,11 @@ extern wchar_t *wcsrchr(const wchar_t *, wchar_t);
        extern size_t wcsspn(const wchar_t *, const wchar_t *);
        extern wchar_t *wcsstr(const wchar_t *, const wchar_t *);
        extern wchar_t *wcstok(wchar_t *restrict, const wchar_t *restrict, wchar_t **restrict);
       -extern wchar_t *wmemchr(const wchar_t *, wchar_t, size_t);
       -extern size_t wcslen(const wchar_t *);
       -extern wchar_t *wmemset(wchar_t *, wchar_t, size_t);
       +
        extern size_t wcsftime(wchar_t *restrict, size_t, const wchar_t *restrict, const struct tm *restrict);
        extern wint_t btowc(int);
        extern int wctob(wint_t);
       +
        extern int mbsinit(const mbstate_t *);
        extern size_t mbrlen(const char *restrict, size_t, mbstate_t *restrict);
        extern size_t mbrtowc(wchar_t *restrict, const char *restrict, size_t, mbstate_t *restrict);
       @@ -85,7 +93,7 @@ extern size_t mbsrtowcs(wchar_t *restrict, const char **restrict, size_t, mbstat
        extern size_t wcsrtombs(char *restrict, const wchar_t **restrict, size_t, mbstate_t *restrict);
        extern int wcwidth(wchar_t);
        
       -#define mbrlen(s, n, ps) mbrtowc(NULL, s, n, ps)
        #define putwc(wc, fp) fputwc(wc, fp)
       +#define getwc(fp)     fgetwc(fp)
        
        #endif
 (DIR) diff --git a/src/cmd/scc-make/rules.c b/src/cmd/scc-make/rules.c
       @@ -506,7 +506,7 @@ rebuild(Target *tp, int *buildp)
                        q = *p;
                        debug("checking dependency %s", q->name);
        
       -                if (q->actions)
       +                if (strcmp(q->name, tp->name) == 0 && q->actions)
                                def = 1;
        
                        build = 0;
       @@ -526,10 +526,14 @@ rebuild(Target *tp, int *buildp)
                        }
                }
        
       -        if (tp->stamp == -1)
       -                need = 1;
       -        else if (!def && inference(tp, NOFORCE))
       +        if (tp->stamp == -1) {
                        need = 1;
       +        } else if (!def)  {
       +                debug("no action found for %s, looking a inference rule",
       +                      tp->name);
       +                if (inference(tp, NOFORCE))
       +                        need = 1;
       +        }
        
                if (err) {
                        warning("target %s not remade because of errors", tp->name);
       @@ -537,6 +541,7 @@ rebuild(Target *tp, int *buildp)
                } else if (need) {
                        *buildp = 1;
        
       +                debug("target %s needs updating", tp->name);
                        r = update(tp);
                        if (r == 0)
                                return 0;
 (DIR) diff --git a/src/libc/arch/bsd/Makefile b/src/libc/arch/bsd/Makefile
       @@ -4,8 +4,6 @@ include $(PROJECTDIR)/scripts/rules.mk
        include ../../rules.mk
        
        OBJS=\
       -        _mbsget.$O\
       -        _mbsset.$O\
       -        _waitpid.$O\
       +        _waitpid.$O\
        
        all: $(OBJS)
 (DIR) diff --git a/src/libc/arch/bsd/_mbsget.c b/src/libc/arch/bsd/_mbsget.c
       @@ -1,9 +0,0 @@
       -#include <wchar.h>
       -
       -#include "../../libc.h"
       -
       -int
       -_mbsget(mbstate_t *ps)
       -{
       -        return ps->__mbstate8[0];
       -}
 (DIR) diff --git a/src/libc/arch/bsd/_mbsset.c b/src/libc/arch/bsd/_mbsset.c
       @@ -1,9 +0,0 @@
       -#include <wchar.h>
       -
       -#include "../../libc.h"
       -
       -int
       -_mbsset(mbstate_t *ps, int ch)
       -{
       -        return ps->__mbstate8[0] = ch;
       -}
 (DIR) diff --git a/src/libc/arch/darwin/Makefile b/src/libc/arch/darwin/Makefile
       @@ -5,7 +5,5 @@ include ../../rules.mk
        
        OBJS=\
                _getheap.$O\
       -        _mbsget.$O\
       -        _mbsset.$O\
        
        all: $(OBJS)
 (DIR) diff --git a/src/libc/arch/darwin/_mbsget.c b/src/libc/arch/darwin/_mbsget.c
       @@ -1,9 +0,0 @@
       -#include <wchar.h>
       -
       -#include "../../libc.h"
       -
       -int
       -_mbsget(mbstate_t *ps)
       -{
       -        return ps->state[0];
       -}
 (DIR) diff --git a/src/libc/arch/darwin/_mbsset.c b/src/libc/arch/darwin/_mbsset.c
       @@ -1,10 +0,0 @@
       -#include <wchar.h>
       -
       -#include "../../libc.h"
       -
       -int
       -_mbsset(mbstate_t *ps, int ch)
       -{
       -        ps-count = 1;
       -        return ps->state[0] = ch;
       -}
 (DIR) diff --git a/src/libc/arch/linux/Makefile b/src/libc/arch/linux/Makefile
       @@ -6,8 +6,6 @@ include ../../rules.mk
        OBJS=\
                _brk.$O\
                _getheap.$O\
       -        _mbsget.$O\
       -        _mbsset.$O\
                _sigaction.$O\
                _waitpid.$O\
        
 (DIR) diff --git a/src/libc/arch/linux/_mbsget.c b/src/libc/arch/linux/_mbsget.c
       @@ -1,9 +0,0 @@
       -#include <wchar.h>
       -
       -#include "../../libc.h"
       -
       -int
       -_mbsget(mbstate_t *ps)
       -{
       -        return ps->__opaque1;
       -}
 (DIR) diff --git a/src/libc/arch/linux/_mbsset.c b/src/libc/arch/linux/_mbsset.c
       @@ -1,9 +0,0 @@
       -#include <wchar.h>
       -
       -#include "../../libc.h"
       -
       -int
       -_mbsset(mbstate_t *ps, int ch)
       -{
       -        return ps->__opaque1 = ch;
       -}
 (DIR) diff --git a/src/libc/libc.h b/src/libc/libc.h
       @@ -20,6 +20,7 @@ enum {
        #define SECDAY (24 * SECHOUR)   /* 86400 */
        
        struct tm;
       +struct _FILE;
        
        struct tzone {
                char *name;
       @@ -61,9 +62,5 @@ extern void (*_atexithdl)(void);
        
        #ifdef _WCHAR_H
        extern int _validutf8(wchar_t, int *);
       -extern int _mbsset(mbstate_t *, int);
       -extern int _mbsget(mbstate_t *);
       -#ifdef _STDIO_H
       -extern wint_t _fputwc(wchar_t, FILE *, int *);
       -#endif
       +extern wint_t _fputwc(wchar_t, struct _FILE *, int *);
        #endif
 (DIR) diff --git a/src/libc/objs/amd64-linux.mk b/src/libc/objs/amd64-linux.mk
       @@ -36,8 +36,6 @@ OBJS =\
                arch/amd64/strcpy.$O\
                arch/linux/_brk.$O\
                arch/linux/_getheap.$O\
       -        arch/linux/_mbsget.$O\
       -        arch/linux/_mbsset.$O\
                arch/linux/_sigaction.$O\
                arch/linux/_waitpid.$O\
                arch/posix/_open.$O\
 (DIR) diff --git a/src/libc/objs/amd64-netbsd.mk b/src/libc/objs/amd64-netbsd.mk
       @@ -28,8 +28,6 @@ OBJS =\
                arch/amd64/strcmp.$O\
                arch/amd64/strcpy.$O\
                arch/bsd/_waitpid.$O\
       -        arch/bsd/_mbsget.$O\
       -        arch/bsd/_mbsset.$O\
                arch/netbsd/_sigaction.$O\
                arch/posix/_getheap.$O\
                arch/posix/_open.$O\
 (DIR) diff --git a/src/libc/objs/amd64-openbsd.mk b/src/libc/objs/amd64-openbsd.mk
       @@ -33,8 +33,6 @@ OBJS =\
                arch/amd64/strcmp.$O\
                arch/amd64/strcpy.$O\
                arch/bsd/_waitpid.$O\
       -        arch/bsd/_mbsget.$O\
       -        arch/bsd/_mbsset.$O\
                arch/posix/_getheap.$O\
                arch/posix/_open.$O\
                arch/posix/_systime.$O\
 (DIR) diff --git a/src/libc/objs/common-objs.mk b/src/libc/objs/common-objs.mk
       @@ -127,6 +127,10 @@ COMMON_OBJS =\
                wchar/mbsrtowcs.$O\
                wchar/wcrtomb.$O\
                wchar/wcslen.$O\
       +        wchar/wcscmp.$O\
       +        wchar/wcscoll.$O\
       +        wchar/wcsncmp.$O\
       +        wchar/wcscpy.$O\
                wchar/wcsrtombs.$O\
                wchar/wcwidth.$O\
                wchar/putwc.$O\
 (DIR) diff --git a/src/libc/stdlib/mblen.c b/src/libc/stdlib/mblen.c
       @@ -1,9 +1,16 @@
        #include <stdlib.h>
       +#include <wchar.h>
        
        #undef mblen
        
        int
        mblen(const char *s, size_t n)
        {
       -        return mbtowc(NULL, s, n);
       +        int ret;
       +        static mbstate_t st;
       +
       +        ret = mbrtowc(NULL, s, n, &st);
       +        if (ret < 0)
       +                ret = -1;
       +        return ret;
        }
 (DIR) diff --git a/src/libc/stdlib/mbstowcs.c b/src/libc/stdlib/mbstowcs.c
       @@ -7,5 +7,7 @@
        size_t
        mbstowcs(wchar_t *restrict dest, const char *restrict src, size_t n)
        {
       -        return mbsrtowcs(dest, (void *) &src, n, NULL);
       +        static mbstate_t st;
       +
       +        return mbsrtowcs(dest, (void *) &src, n, &st);
        }
 (DIR) diff --git a/src/libc/stdlib/mbtowc.c b/src/libc/stdlib/mbtowc.c
       @@ -1,4 +1,5 @@
        #include <stdlib.h>
       +#include <string.h>
        #include <wchar.h>
        
        #undef mbtowc
       @@ -6,5 +7,12 @@
        int
        mbtowc(wchar_t *restrict pwc, const char *restrict s, size_t n)
        {
       -        return mbrtowc(pwc, s, n, NULL);
       +        static mbstate_t st;
       +        int ret;
       +
       +        ret = mbrtowc(pwc, s, n, &st);
       +        if (ret < 0)
       +                ret = -1;
       +
       +        return ret;
        }
 (DIR) diff --git a/src/libc/stdlib/wcstombs.c b/src/libc/stdlib/wcstombs.c
       @@ -6,5 +6,7 @@
        size_t
        wcstombs(char *restrict dest, const wchar_t *restrict src, size_t n)
        {
       -        return wcsrtombs(dest, (void *) &src, n, NULL);
       +        static mbstate_t st;
       +
       +        return wcsrtombs(dest, (void *) &src, n, &st);
        }
 (DIR) diff --git a/src/libc/stdlib/wctomb.c b/src/libc/stdlib/wctomb.c
       @@ -6,5 +6,7 @@
        int
        wctomb(char *s, wchar_t wc)
        {
       -        return wcrtomb(s, wc, NULL);
       +        static mbstate_t st;
       +
       +        return wcrtomb(s, wc, &st);
        }
 (DIR) diff --git a/src/libc/string/strcmp.c b/src/libc/string/strcmp.c
       @@ -5,7 +5,7 @@
        int
        strcmp(const char *s1, const char *s2)
        {
       -        while (*s1 && *s2 && *s1 == *s2)
       +        while (*s1 && *s1 == *s2)
                        ++s1, ++s2;
                return *(unsigned char *) s1 - *(unsigned char *) s2;
        }
 (DIR) diff --git a/src/libc/wchar/_validutf8.c b/src/libc/wchar/_validutf8.c
       @@ -19,7 +19,7 @@ _validutf8(wchar_t wc, int *nbytes)
                        {0xD800,    0xDD00,     0, 3},
                        {0xDD00,    0x10000,    1, 3},
                        {0x10000,   0x110000,   1, 4},
       -                {0x11000,   -1ul,       0, 0},
       +                {0x110000,  -1ul,       0, 0},
                };
                struct range *bp;
        
 (DIR) diff --git a/src/libc/wchar/mbrlen.c b/src/libc/wchar/mbrlen.c
       @@ -5,5 +5,9 @@
        size_t
        mbrlen(const char *restrict s, size_t n, mbstate_t *restrict ps)
        {
       +        static mbstate_t st;
       +
       +        if (!ps)
       +                ps = &st;
                return mbrtowc(NULL, s, n, ps);
        }
 (DIR) diff --git a/src/libc/wchar/mbrtowc.c b/src/libc/wchar/mbrtowc.c
       @@ -1,5 +1,6 @@
        #include <errno.h>
        #include <stdlib.h>
       +#include <string.h>
        #include <wchar.h>
        
        #include "../libc.h"
       @@ -10,43 +11,88 @@ size_t
        mbrtowc(wchar_t *restrict pwc, const char *restrict s, size_t n,
                mbstate_t *restrict ps)
        {
       +        static mbstate_t state;
                const unsigned char *t = (const unsigned char *) s;
       +        wchar_t dummy;
                unsigned long wc;
       -        unsigned c;
       -        int i, len, maxlen;
       -
       -        if (t == NULL)
       -                return 0;
       -        if ((wc = *t) == 0)
       -                goto return_code;
       -
       -        c = *t++;
       -        for (len = 0; n > 0 && c & 0x80; --n, ++len)
       -                c <<= 1;
       -        if (n == 0 && c & 0x80)
       +        unsigned c, oc;
       +        int sh, max;
       +
       +        if (!ps)
       +                ps  = &state;
       +
       +        if (t == NULL) {
       +                if (ps->sh != 0)
       +                        goto return_error;
       +                pwc = &dummy;
       +                goto return_code_set;
       +        }
       +        if (n == 0)
                        return -2;
       -        if (len == 1 || len > MB_CUR_MAX)
       -                goto return_error;
       -        if (len == 0)
       -                goto return_code;
       -
       -        wc = (c & 0xFF) >> len;
       -        for (i = 0; i < len-1; i++) {
       -                if (((c = *t++) & 0xC0) != 0x80)
       +
       +        oc = ps->oc;
       +        wc = ps->wc;
       +        sh = ps->sh;
       +
       +        /* initial state? */
       +        if (sh == 0) {
       +                /* NUL character? */
       +                if ((c = wc = *t) == 0)
       +                        goto return_code;
       +                t++;
       +                n--;
       +
       +                /* fast track for ascii? */
       +                if (c < 0x80)
       +                        goto return_code;
       +
       +                /* out of sequence multibyte? */
       +                if ((c & 0xc0) != 0xc0)
                                goto return_error;
       +
       +                /* in sequence multibyte! */
       +                oc = c << 1;
       +                wc = 0;
       +                sh = 1;
       +        }
       +
       +        for ( ; n > 0; --n) {
       +                if (sh > MB_CUR_MAX)
       +                        goto return_error;
       +
       +                c = *t++;
       +                if ((c & 0xc0) != 0x80)
       +                        goto return_error;
       +
                        wc <<= 6;
       -                wc |= c & 0x3F;
       +                wc |= c & 0x3f;
       +                oc <<= 1;
       +                sh++;
       +
       +                if ((oc & 0x80) == 0) {
       +                        oc = (oc & 0xff) >> sh;
       +                        wc |= oc << (sh-1) * 6;
       +        
       +                        if (!_validutf8(wc, &max) || sh != max)
       +                                goto return_error;
       +                        goto return_code_set;
       +                }
                }
        
       -        if (!_validutf8(wc, &maxlen) || len != maxlen)
       -                goto return_error;
       +        ps->sh = sh;
       +        ps->oc = oc;
       +        ps->wc = wc;
       +        return -2;
        
       +return_code_set:
       +        memset(ps, 0, sizeof(*ps));
        return_code:
                if (pwc)
                        *pwc = wc;
                return t - (unsigned char *) s;
        
        return_error:
       +        memset(ps, 0, sizeof(*ps));
                errno = EILSEQ;
                return -1;
        }
 (DIR) diff --git a/src/libc/wchar/mbsinit.c b/src/libc/wchar/mbsinit.c
       @@ -1,7 +1,5 @@
        #include <wchar.h>
        
       -#include "../libc.h"
       -
        #undef mbsinit
        
        int
       @@ -9,5 +7,5 @@ mbsinit(const mbstate_t *ps)
        {
                if (!ps)
                        return 1;
       -        return _mbsget(ps) == 0;
       +        return ps->oc == 0;
        }
 (DIR) diff --git a/src/libc/wchar/mbsrtowcs.c b/src/libc/wchar/mbsrtowcs.c
       @@ -1,4 +1,5 @@
        #include <limits.h>
       +#include <string.h>
        #include <wchar.h>
        
        #undef mbsrtowcs
       @@ -8,24 +9,39 @@ mbsrtowcs(wchar_t *restrict dest, const char **restrict src, size_t len,
                  mbstate_t *restrict ps)
        {
                wchar_t wc;
       +        const char *s = *src;
                size_t cnt, n;
       +        static mbstate_t st;
       +
       +        if (!ps)
       +                ps = &st;
        
                for (n = 0; ; n++) {
       -                cnt = mbrtowc(&wc, *src, MB_LEN_MAX, ps);
       +                cnt = mbrtowc(&wc, s, MB_LEN_MAX, ps);
       +                if (cnt == (size_t) -2) {
       +                        s += MB_LEN_MAX;
       +                        continue;
       +                }
                        if (cnt == (size_t) -1)
                                return -1;
        
                        if (dest) {
       -                        if (n == len)
       +                        if (n == len) {
       +                                *src = s;
                                        return n;
       +                        }
                                *dest++ = wc;
                        }
       -                *src += cnt;
       +                s += cnt;
        
       -                if (wc == L'\0')
       +                if (wc == 0)
                                break;
                }
       -        *src = NULL;
       +
       +        if (dest) {
       +                memset(ps, 0, sizeof(mbstate_t));
       +                *src = NULL;
       +        }
        
                return n;
        }
 (DIR) diff --git a/src/libc/wchar/wcscmp.c b/src/libc/wchar/wcscmp.c
       @@ -0,0 +1,15 @@
       +#include <wchar.h>
       +
       +#undef wcscmp
       +
       +int
       +wcscmp(const wchar_t *s1, const wchar_t *s2)
       +{
       +        unsigned long l1, l2;
       +
       +        while (*s1 && *s1 == *s2)
       +                ++s1, ++s2;
       +        l1 = *s1, l2 = *s2;
       +
       +        return l1 - l2;
       +}
 (DIR) diff --git a/src/libc/wchar/wcscoll.c b/src/libc/wchar/wcscoll.c
       @@ -0,0 +1,9 @@
       +#include <wchar.h>
       +
       +#undef wcscoll
       +
       +int
       +wcscoll(const wchar_t *s1, const wchar_t *s2)
       +{
       +        return wcscmp(s1, s2);
       +}
 (DIR) diff --git a/src/libc/wchar/wcscpy.c b/src/libc/wchar/wcscpy.c
       @@ -0,0 +1,16 @@
       +#include <wchar.h>
       +
       +#undef wcscpy
       +
       +wchar_t *
       +wcscpy(wchar_t * restrict s1, const wchar_t * restrict s2)
       +{
       +        wchar_t *ret = s1;
       +
       +        while ((*s1++ = *s2++) != '\0')
       +                ;
       +
       +        return ret;
       +
       +}
       +
 (DIR) diff --git a/src/libc/wchar/wcsncmp.c b/src/libc/wchar/wcsncmp.c
       @@ -0,0 +1,18 @@
       +#include <wchar.h>
       +
       +#undef wcsncmp
       +
       +int
       +wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n)
       +{
       +        unsigned long l1, l2;
       +
       +        for ( ; n > 0 && *s1 == *s2; --n)
       +                ++s1, ++s2;
       +
       +        if (n == 0)
       +                return 0;
       +        l1 = *s1, l2 = *s2;
       +
       +        return l1 - l2;
       +}
 (DIR) diff --git a/tests/libc/execute/.gitignore b/tests/libc/execute/.gitignore
       @@ -35,4 +35,14 @@
        0035-setlocale
        0036-localeconv
        0037-malloc
       +0038-mbsinit
       +0039-mbrtowc
       +0040-wcrtomb
       +0041-mbrlen
       +0042-mbsrtowcs
       +0044-wcslen
       +0045-wcscmp
       +0046-wcsncmp
       +0047-wcscoll
       +0048-wcscpy
        test.log
 (DIR) diff --git a/tests/libc/execute/0038-mbsinit.c b/tests/libc/execute/0038-mbsinit.c
       @@ -0,0 +1,29 @@
       +#include <assert.h>
       +#include <stdio.h>
       +#include <string.h>
       +#include <wchar.h>
       +
       +/*
       +output:
       +testing
       +done
       +end:
       +*/
       +
       +void
       +tests_mbsinit(void)
       +{
       +        mbstate_t s;
       +
       +        assert(mbsinit(NULL) != 0);
       +        assert(mbsinit(memset(&s, 0, sizeof(s))) != 0);
       +}
       +
       +int
       +main()
       +{
       +        puts("testing");
       +        tests_mbsinit();
       +        puts("done");
       +        return 0;
       +}
 (DIR) diff --git a/tests/libc/execute/0039-mbrtowc.c b/tests/libc/execute/0039-mbrtowc.c
       @@ -0,0 +1,84 @@
       +#include <assert.h>
       +#include <errno.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <wchar.h>
       +
       +#include "mbtest.h"
       +
       +/*
       +output:
       +testing
       +testing mbrtowc1
       +testing mbrtowc2
       +testing mbtowc
       +done
       +end:
       +*/
       +
       +#define NELEM(x) (sizeof(x)/sizeof(x[0]))
       +
       +void
       +tests_mbrtowc(void)
       +{
       +        struct mbtest *tp;
       +        int r;
       +        mbstate_t s;
       +
       +        puts("testing mbrtowc1");
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                wc = -1;
       +                errno = 0;
       +                r = mbrtowc(tp->pwc, tp->s, tp->l, NULL);
       +                assert(tp->r == r);
       +                assert(tp->syserr == errno);
       +                if (tp->r != -1)
       +                        assert(tp->wc == wc);
       +        }
       +
       +        puts("testing mbrtowc2");
       +        memset(&s, 0, sizeof(s));
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                wc = -1;
       +                errno = 0;
       +                r = mbrtowc(tp->pwc, tp->s, tp->l, &s);
       +                assert(tp->r == r);
       +                assert(tp->syserr == errno);
       +                if (tp->r != -1)
       +                        assert(tp->wc == wc);
       +                assert(mbsinit(&s) != 0 == tp->mbstate);
       +        }
       +}
       +
       +void
       +tests_mbtowc(void)
       +{
       +        struct mbtest *tp;
       +        int r, rt;
       +
       +        puts("testing mbtowc");
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                wc = -1;
       +                errno = 0;
       +                r = mbtowc(tp->pwc, tp->s, tp->l);
       +                assert(tp->syserr == errno);
       +                if (tp->r >= 0) {
       +                        rt = tp->r;
       +                        assert(tp->wc == wc);
       +                } else {
       +                        rt = -1;
       +                }
       +                assert(rt == r);
       +        }
       +}
       +
       +int
       +main()
       +{
       +        puts("testing");
       +        tests_mbrtowc();
       +        tests_mbtowc();
       +        puts("done");
       +        return 0;
       +}
 (DIR) diff --git a/tests/libc/execute/0040-wcrtomb.c b/tests/libc/execute/0040-wcrtomb.c
       @@ -0,0 +1,102 @@
       +#include <assert.h>
       +#include <errno.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <wchar.h>
       +
       +/*
       +output:
       +testing
       +testing wcrtomb1
       +testing wcrtomb2
       +testing wctomb
       +done
       +end:
       +*/
       +
       +#define NELEM(x) (sizeof(x)/sizeof(x[0]))
       +
       +static char str[MB_CUR_MAX+1];
       +
       +static struct wctest {
       +        wchar_t wc;
       +        char *s;
       +        char exp[MB_CUR_MAX+1];
       +        int r;
       +        int syserr;
       +        int mbstate;
       +} tests[] = {
       +        {0,        NULL, "",                 1, 0,      1},
       +        {0,         str, "\0",               1, 0,      1},
       +        {0x21,      str, "\x21",             1, 0,      1},
       +        {0x00A1,    str, "\xc2\xa1",         2, 0,      1},
       +        {0x2014,    str, "\xe2\x80\x94",     3, 0,      1},
       +        {0x01F4A9,  str, "\xf0\x9f\x92\xa9", 4, 0,      1},
       +
       +        {0xd800,    str, "",                -1, EILSEQ, 1},
       +        {0xDCFF,    str, "",                -1, EILSEQ, 1},
       +        {0xDD00,    str, "\xed\xb4\x80",     3, 0,      1},
       +        {0x10ffff,  str, "\xf4\x8f\xbf\xbf", 4, 0,      1},
       +        {0x110000,  str, "",                -1, EILSEQ, 1},
       +};
       +
       +void
       +tests_wcrtomb(void)
       +{
       +        struct wctest *tp;
       +        int r;
       +        mbstate_t s;
       +
       +        puts("testing wcrtomb1");
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                memset(str, 0, MB_CUR_MAX+1);
       +                errno = 0;
       +                r = wcrtomb(tp->s, tp->wc, NULL);
       +                assert(tp->r == r);
       +                assert(tp->syserr == errno);
       +                if (tp->s && tp->r != -1)
       +                        assert(!memcmp(tp->s, tp->exp, MB_CUR_MAX+1));
       +        }
       +
       +        puts("testing wcrtomb2");
       +        memset(&s, 0, sizeof(s));
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                memset(str, 0, MB_CUR_MAX+1);
       +                errno = 0;
       +                r = wcrtomb(tp->s, tp->wc, &s);
       +                assert(tp->r == r);
       +                assert(tp->syserr == errno);
       +                if (tp->s && tp->r != -1)
       +                        assert(!memcmp(tp->s, tp->exp, MB_CUR_MAX+1));
       +                assert(mbsinit(&s) != 0 == tp->mbstate);
       +        }
       +}
       +
       +void
       +tests_wctomb(void)
       +{
       +        struct wctest *tp;
       +        int r;
       +
       +        puts("testing wctomb");
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                memset(str, 0, MB_CUR_MAX+1);
       +                errno = 0;
       +                r = wctomb(tp->s, tp->wc);
       +                assert(tp->r == r);
       +                assert(tp->syserr == errno);
       +                if (tp->s && tp->r != -1)
       +                        assert(!memcmp(tp->s, tp->exp, MB_CUR_MAX+1));
       +        }
       +}
       +
       +int
       +main(void)
       +{
       +        puts("testing");
       +        tests_wcrtomb();
       +        tests_wctomb();
       +        puts("done");
       +        return 0;
       +}
 (DIR) diff --git a/tests/libc/execute/0041-mbrlen.c b/tests/libc/execute/0041-mbrlen.c
       @@ -0,0 +1,75 @@
       +#include <assert.h>
       +#include <errno.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <wchar.h>
       +
       +#include "mbtest.h"
       +
       +/*
       +output:
       +testing
       +testing mbrlen1
       +testing mbrlen2
       +testing mblen
       +done
       +end:
       +*/
       +
       +#define NELEM(x) (sizeof(x)/sizeof(x[0]))
       +
       +void
       +tests_mbrlen(void)
       +{
       +        struct mbtest *tp;
       +        int r;
       +        mbstate_t s;
       +
       +        puts("testing mbrlen1");
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                wc = -1;
       +                errno = 0;
       +                r = mbrlen(tp->s, tp->l, NULL);
       +                assert(tp->r == r);
       +                assert(tp->syserr == errno);
       +        }
       +
       +        puts("testing mbrlen2");
       +        memset(&s, 0, sizeof(s));
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                wc = -1;
       +                errno = 0;
       +                r = mbrlen(tp->s, tp->l, &s);
       +                assert(tp->r == r);
       +                assert(tp->syserr == errno);
       +                assert(mbsinit(&s) != 0 == tp->mbstate);
       +        }
       +}
       +
       +void
       +tests_mblen(void)
       +{
       +        struct mbtest *tp;
       +        int r, rt;
       +
       +        puts("testing mblen");
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                wc = -1;
       +                errno = 0;
       +                r = mblen(tp->s, tp->l);
       +                assert(tp->syserr == errno);
       +                rt = (tp->r >= 0) ? tp->r : -1;
       +                assert(rt == r);
       +        }
       +}
       +
       +int
       +main()
       +{
       +        puts("testing");
       +        tests_mbrlen();
       +        tests_mblen();
       +        puts("done");
       +        return 0;
       +}
 (DIR) diff --git a/tests/libc/execute/0042-mbsrtowcs.c b/tests/libc/execute/0042-mbsrtowcs.c
       @@ -0,0 +1,126 @@
       +#include <assert.h>
       +#include <errno.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <wchar.h>
       +
       +/*
       +output:
       +testing
       +testing mbsrtowcs1
       +testing mbsrtowcs2
       +testing mbstowcs
       +done
       +end:
       +*/
       +
       +#define NELEM(x) (sizeof(x)/sizeof(x[0]))
       +
       +static char str[20];
       +static wchar_t wcs[20];
       +static struct mbstests {
       +        char *s;
       +        char *sexp;
       +
       +        wchar_t *wcs;
       +        wchar_t *wcsexp;
       +
       +        size_t n;
       +        int r;
       +        int syserr;
       +        int mbstate;
       +} tests[] = {
       +        /* s       sexp    wcs  wcsexp                      n  r  syserr  mbstate */
       +        {"\0",     NULL,   wcs, (wchar_t[]) {0},            1, 0,      0,       1},
       +        {"\0",      str,   wcs, (wchar_t[]) {0},            0, 0,      0,       1},
       +        {"\0",      str,  NULL, (wchar_t[]) {0},            1, 0,      0,       1},
       +        {"\0",      str,  NULL, (wchar_t[]) {0},            0, 0,      0,       1},
       +
       +        {"\x31",   NULL,   wcs, (wchar_t[]) {0x31, 0},      2, 1,      0,       1},
       +        {"\x31",  str+1,   wcs, (wchar_t[]) {0x31, 0},      1, 1,      0,       1},
       +        {"\x31",    str,  NULL, (wchar_t[]) {0x31, 0},      1, 1,      0,       1},
       +        {"\x31",    str,  NULL, (wchar_t[]) {0x31, 0},      0, 1,      0,       1},
       +
       +        {"\x21\xc2\xa1\xe2\x80\x94\xf0\x9f\x92\xa9",
       +               NULL,   wcs,
       +               (wchar_t[]) {0x21,0xa1,0x2014,0x1f4A9}, 20, 4,      0,       1},
       +
       +        {"\xf0\x9f",str,  wcs, NULL,                       20,-1, EILSEQ,       0},
       +};
       +
       +void
       +tests_mbsrtowcs(void)
       +{
       +        int r;
       +        const char *s;
       +        mbstate_t st;
       +        struct mbstests *tp;
       +
       +        puts("testing mbsrtowcs1");
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                errno = 0;
       +                if (tp->s != NULL)
       +                        s = strcpy(str, tp->s);                        
       +                memset(wcs, -1, sizeof(wcs));
       +
       +                r = mbsrtowcs(tp->wcs, &s, tp->n, NULL);
       +                assert(tp->r == r);
       +                assert(tp->syserr == errno);
       +                if (tp->r >= 0) {
       +                        assert(s == tp->sexp);
       +                        if (tp->wcs)
       +                                assert(!wcsncmp(tp->wcsexp, tp->wcs, tp->r));
       +                }
       +        }
       +
       +        puts("testing mbsrtowcs2");
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                errno = 0;
       +                if (tp->s != NULL)
       +                        s = strcpy(str, tp->s);                        
       +                memset(wcs, -1, sizeof(wcs));
       +                memset(&st, 0, sizeof(st));
       +
       +                r = mbsrtowcs(tp->wcs, &s, tp->n, &st);
       +                assert(tp->r == r);
       +                assert(tp->syserr == errno);
       +                if (tp->r >= 0) {
       +                        assert(s == tp->sexp);
       +                        if (tp->wcs)
       +                                assert(!wcsncmp(tp->wcsexp, tp->wcs, tp->r));
       +                        assert(mbsinit(&st) != 0 == tp->mbstate);
       +                }
       +        }
       +}
       +
       +void
       +tests_mbstowcs(void)
       +{
       +        int r;
       +        struct mbstests *tp;
       +
       +        puts("testing mbstowcs");
       +        for (tp = tests; tp < &tests[NELEM(tests)]; ++tp) {
       +                errno = 0;
       +                memset(wcs, -1, sizeof(wcs));
       +
       +                r = mbstowcs(tp->wcs, tp->s, tp->n);
       +                assert(tp->r == r);
       +                assert(tp->syserr == errno);
       +                if (tp->r >= 0) {
       +                        if (tp->wcs)
       +                                assert(!wcsncmp(tp->wcsexp, tp->wcs, tp->r));
       +                }
       +        }
       +}
       +
       +int
       +main(void)
       +{
       +        puts("testing");
       +        tests_mbsrtowcs();
       +        tests_mbstowcs();
       +        puts("done");
       +        return 0;
       +}
 (DIR) diff --git a/tests/libc/execute/0044-wcslen.c b/tests/libc/execute/0044-wcslen.c
       @@ -0,0 +1,28 @@
       +#include <assert.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +
       +/*
       +output:
       +testing
       +done
       +end:
       +*/
       +
       +int
       +main(void)
       +{
       +        wchar_t t1[] = {0, 0};
       +        wchar_t t2[] = {0};
       +        wchar_t t3[] = {0x31, 0};
       +        wchar_t t4[] = {0x31, 0x32, 0, 0x33, 0};
       +
       +        puts("testing");
       +        assert(wcslen(t1) == 0);
       +        assert(wcslen(t2) == 0);
       +        assert(wcslen(t3) == 1);
       +        assert(wcslen(t4) == 2);
       +        puts("done");
       +
       +        return 0;
       +}
 (DIR) diff --git a/tests/libc/execute/0045-wcscmp.c b/tests/libc/execute/0045-wcscmp.c
       @@ -0,0 +1,36 @@
       +#include <assert.h>
       +#include <stdio.h>
       +#include <wchar.h>
       +
       +/*
       +output:
       +testing
       +done
       +end:
       +*/
       +
       +int
       +main(void)
       +{
       +        wchar_t t1[] = {0};
       +        wchar_t t2[] = {0};
       +        wchar_t t3[] = {0x31, 0};
       +        wchar_t t4[] = {0x31, 0};
       +        wchar_t t5[] = {0x31, 0x32, 0};
       +        wchar_t t6[] = {0, 0x31, 0};
       +
       +        puts("testing");
       +        assert(wcscmp(t1, t1) == 0);
       +        assert(wcscmp(t1, t2) == 0);
       +        assert(wcscmp(t1, t3) < 0);
       +        assert(wcscmp(t3, t1) > 0);
       +        assert(wcscmp(t3, t3) == 0);
       +        assert(wcscmp(t3, t4) == 0);
       +        assert(wcscmp(t3, t5) < 0);
       +        assert(wcscmp(t5, t3) > 0);
       +        assert(wcscmp(t3, t6) > 0);
       +        assert(wcscmp(t6, t3) < 0);
       +        puts("done");
       +
       +        return 0;
       +}
 (DIR) diff --git a/tests/libc/execute/0046-wcsncmp.c b/tests/libc/execute/0046-wcsncmp.c
       @@ -0,0 +1,30 @@
       +#include <assert.h>
       +#include <stdio.h>
       +#include <wchar.h>
       +
       +/*
       +output:
       +testing
       +done
       +end:
       +*/
       +
       +int
       +main(void)
       +{
       +        wchar_t t1[] = {0};
       +        wchar_t t2[] = {0};
       +        wchar_t t3[] = {0x31, 0};
       +        wchar_t t4[] = {0x31, 0};
       +        wchar_t t5[] = {0x32, 0x33, 0};
       +
       +        puts("testing");
       +        assert(wcsncmp(t1, t1, 0) == 0);
       +        assert(wcsncmp(t1, t2, 0) == 0);
       +        assert(wcsncmp(t3, t4, 1) == 0);
       +        assert(wcsncmp(t3, t5, 1) < 0);
       +        assert(wcsncmp(t5, t3, 1) > 0);
       +        puts("done");
       +
       +        return 0;
       +}
 (DIR) diff --git a/tests/libc/execute/0047-wcscoll.c b/tests/libc/execute/0047-wcscoll.c
       @@ -0,0 +1,36 @@
       +#include <assert.h>
       +#include <stdio.h>
       +#include <wchar.h>
       +
       +/*
       +output:
       +testing
       +done
       +end:
       +*/
       +
       +int
       +main(void)
       +{
       +        wchar_t t1[] = {0};
       +        wchar_t t2[] = {0};
       +        wchar_t t3[] = {0x31, 0};
       +        wchar_t t4[] = {0x31, 0};
       +        wchar_t t5[] = {0x31, 0x32, 0};
       +        wchar_t t6[] = {0, 0x31, 0};
       +
       +        puts("testing");
       +        assert(wcscoll(t1, t1) == 0);
       +        assert(wcscoll(t1, t2) == 0);
       +        assert(wcscoll(t1, t3) < 0);
       +        assert(wcscoll(t3, t1) > 0);
       +        assert(wcscoll(t3, t3) == 0);
       +        assert(wcscoll(t3, t4) == 0);
       +        assert(wcscoll(t3, t5) < 0);
       +        assert(wcscoll(t5, t3) > 0);
       +        assert(wcscoll(t3, t6) > 0);
       +        assert(wcscoll(t6, t3) < 0);
       +        puts("done");
       +
       +        return 0;
       +}
 (DIR) diff --git a/tests/libc/execute/0048-wcscpy.c b/tests/libc/execute/0048-wcscpy.c
       @@ -0,0 +1,31 @@
       +#include <assert.h>
       +#include <stdio.h>
       +#include <wchar.h>
       +
       +/*
       +output:
       +testing
       +done
       +end:
       +*/
       +
       +int
       +main()
       +{
       +        wchar_t test[]= {'t', 'e', 's', 't', 0};
       +        wchar_t *s, buf[40];
       +
       +        puts("testing");
       +
       +        s = wcscpy(buf, test);
       +        assert(s == buf);
       +        assert(!wcscmp(s, test));
       +
       +        s = wcscpy(buf, "");
       +        assert(s == buf);
       +        assert(!wcscmp(s, ""));
       +
       +        puts("done");
       +
       +        return 0;
       +}
       +\ No newline at end of file
 (DIR) diff --git a/tests/libc/execute/libc-tests.lst b/tests/libc/execute/libc-tests.lst
       @@ -34,3 +34,13 @@
        0035-setlocale
        0036-localeconv
        0037-malloc [TODO]
       +0038-mbsinit
       +0039-mbrtowc
       +0040-wcrtomb
       +0041-mbrlen
       +0042-mbsrtowcs
       +0044-wcslen
       +0045-wcscmp
       +0046-wcsncmp
       +0047-wcscoll
       +0048-wcscpy
 (DIR) diff --git a/tests/libc/execute/mbtest.h b/tests/libc/execute/mbtest.h
       @@ -0,0 +1,44 @@
       +static wchar_t wc;
       +static struct mbtest {
       +        char *s;
       +        int l;
       +        int r;
       +        int mbstate;
       +        int syserr;
       +        wchar_t *pwc;
       +        wchar_t wc;
       +} tests[] = {
       +        {"\0",                             2,  0, 1, 0,      &wc,  0},
       +        {"\x21",                           2,  1, 1, 0,      &wc,  0x21},
       +        {"\xc2\xa1",                       3,  2, 1, 0,      &wc,  0x00A1},
       +        {"\xc2\xa1",                       2,  2, 1, 0,      &wc,  0x00A1},
       +        {"\xe2\x80\x94",                   4,  3, 1, 0,      &wc,  0x2014},
       +        {"\xf0\x9f\x92\xa9",               5,  4, 1, 0,      &wc,  0x01F4A9},
       +        {"\xf0\x9f\x92\xa9",               5,  4, 1, 0,      NULL, -1},
       +        {"\xf0\x9f\x92\xa9",              -1,  4, 1, 0,      &wc,  0x01F4A9},
       +
       +        {NULL,                             4,  0, 1, 0,      NULL, -1},
       +        {"\xed\x9f\xbf",                   4,  3, 1, 0,      &wc,  0xd7ff},
       +        {"\xed\xa0\x80",                   4, -1, 1, EILSEQ, &wc,  -1},
       +        {"\xed\xb3\xbf",                   4, -1, 1, EILSEQ, &wc,  -1},
       +        {"\xed\xb4\x80",                   4,  3, 1, 0,      &wc,  0xdd00},
       +
       +        {"\xf0\x9f\x92\xa9",               3, -2, 0, 0,      &wc, -1},
       +        {"\xa9",                           2,  1, 1, 0,      &wc, 0x01F4A9},
       +        {"\xf0\x9f\x92\xa9",               3, -2, 0, 0,      &wc, -1},
       +        {NULL,                             4, -1, 1, EILSEQ, &wc, -1},
       +        {"\xa9",                           2, -1, 1, EILSEQ, &wc, -1},
       +        {"\xf0\x9f\x92\xa9",               3, -2, 0, 0,      &wc, -1},
       +        {NULL,                             4, -1, 1, EILSEQ, &wc, -1},
       +        {"\x21",                           2,  1, 1, 0,      &wc,  0x21},
       +        {"\xf0\x9f\x92\xa9",               2, -2, 0, 0,      &wc, -1},
       +        {"\xf0\x9f\x92\xa9",               0, -2, 0, 0,      &wc, -1},
       +        {"\x92\xa9",                       2,  2, 1, 0,      &wc, 0x01F4A9},
       +
       +        {"\x80",                           2, -1, 1, EILSEQ, &wc, -1},
       +        {"\xc0\x80",                       2, -1, 1, EILSEQ, &wc, -1},
       +        {"\xc0\x00",                       2, -1, 1, EILSEQ, &wc, -1},
       +        {"\xc1\x81",                       2, -1, 1, EILSEQ, &wc, -1},
       +        {"\xf8\x81\x82\x83\x84\x85",      -1, -1, 1, EILSEQ, &wc, -1},
       +        {"\xfe\x81\x82\x83\x84\x85\x86",   8, -1, 1, EILSEQ, &wc, -1},
       +};
 (DIR) diff --git a/tests/make/execute/0107-inference.sh b/tests/make/execute/0107-inference.sh
       @@ -0,0 +1,31 @@
       +#!/bin/sh
       +
       +trap 'rm -f $tmp1 $tmp2 f f.?' EXIT INT TERM QUIT HUP
       +
       +tmp1=tmp1.$$
       +tmp2=tmp2.$$
       +
       +cat >$tmp1 <<EOF
       +c99 -O  -o f f.c
       +EOF
       +
       +cat >f.c <<'EOF'
       +int
       +main(void)
       +{
       +        return 0;
       +}
       +EOF
       +
       +touch -d '1970-01-01 00:00:01' f.h
       +touch -d '1970-01-01 00:00:03' f
       +touch -d '1970-01-01 00:00:04' f.c
       +
       +scc make -f- <<'EOF' > $tmp2  2>&1
       +f: f.h
       +
       +f.h:
       +        touch $@
       +EOF
       +
       +diff $tmp1 $tmp2