diff options
| -rw-r--r-- | libc/misc/wchar/Makefile | 47 | ||||
| -rw-r--r-- | libc/misc/wchar/wchar.c | 723 | ||||
| -rw-r--r-- | libc/stdlib/Makefile | 6 | ||||
| -rw-r--r-- | libc/stdlib/stdlib.c | 133 | 
4 files changed, 909 insertions, 0 deletions
diff --git a/libc/misc/wchar/Makefile b/libc/misc/wchar/Makefile new file mode 100644 index 000000000..23a1e9bba --- /dev/null +++ b/libc/misc/wchar/Makefile @@ -0,0 +1,47 @@ +# Makefile for uClibc +# +# Copyright (C) 2000 by Lineo, inc. +# Copyright (C) 2000,2001 Erik Andersen <andersen@uclibc.org> +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU Library General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more +# details. +# +# You should have received a copy of the GNU Library General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Derived in part from the Linux-8086 C library, the GNU C Library, and several +# other sundry sources.  Files within this library are copyright by their +# respective copyright holders. + +TOPDIR=../../../ +include $(TOPDIR)Rules.mak + +MSRC=  wchar.c +MOBJ=  btowc.o wctob.o mbsinit.o mbrlen.o mbrtowc.o wcrtomb.o mbsrtowcs.o \ +	wcsrtombs.o _wchar_utf8sntowcs.o _wchar_wcstoutf8s.o \ +	__mbsnrtowcs.o __wcsnrtombs.o + +OBJS=$(MOBJ) + +all: $(OBJS) $(LIBC) + +$(LIBC): ar-target + +ar-target: $(OBJS) +	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) + +$(MOBJ): $(MSRC) +	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o +	$(STRIPTOOL) -x -R .note -R .comment $*.o + +clean: +	rm -f *.[oa] *~ core + diff --git a/libc/misc/wchar/wchar.c b/libc/misc/wchar/wchar.c new file mode 100644 index 000000000..f2d9f4a7d --- /dev/null +++ b/libc/misc/wchar/wchar.c @@ -0,0 +1,723 @@ +/*  Copyright (C) 2002     Manuel Novoa III + * + *  This library is free software; you can redistribute it and/or + *  modify it under the terms of the GNU Library General Public + *  License as published by the Free Software Foundation; either + *  version 2 of the License, or (at your option) any later version. + * + *  This library is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  Library General Public License for more details. + * + *  You should have received a copy of the GNU Library General Public + *  License along with this library; if not, write to the Free + *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! + * + *  Besides uClibc, I'm using this code in my libc for elks, which is + *  a 16-bit environment with a fairly limited compiler.  It would make + *  things much easier for me if this file isn't modified unnecessarily. + *  In particular, please put any new or replacement functions somewhere + *  else, and modify the makefile to use your version instead. + *  Thanks.  Manuel + * + *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! */ + + +/* May 23, 2002     Initial Notes: + * + * I'm still tweaking this stuff, but it passes the tests I've thrown + * at it, and Erik needs it for the gcc port.  The glibc extension + * __wcsnrtombs() hasn't been tested, as I didn't find a test for it + * in the glibc source.  I also need to fix the behavior of + * _wchar_utf8sntowcs() if the max number of wchars to convert is 0. + * + * UTF-8 -> wchar -> UTF-8 conversion tests on Markus Kuhn's UTF-8-demo.txt + * file on my platform (x86) show about 5-10% faster conversion speed than + * glibc with mbsrtowcs()/wcsrtombs() and almost twice as fast as glibc with + * individual mbrtowc()/wcrtomb() calls. + * + * If 'DECODER' is defined, then _wchar_utf8sntowcs() will be compiled + * as a fail-safe UTF-8 decoder appropriate for a terminal, etc.  which + * needs to deal gracefully with whatever is sent to it.  In that mode, + * it passes Markus Kuhn's UTF-8-test.txt stress test.  I plan to add + * an arg to force that behavior, so the interface will be changing. + * + * I need to fix the error checking for 16-bit wide chars.  This isn't + * an issue for uClibc, but may be for ELKS.  I'm currently not sure + * if I'll use 16-bit, 32-bit, or configureable wchars in ELKS. + * + * Manuel + */ + +#define _GNU_SOURCE +#define _ISOC99_SOURCE +#include <errno.h> +#include <stddef.h> +#include <limits.h> +#include <stdint.h> +#include <inttypes.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <locale.h> +#include <wchar.h> + +#define ENCODING (__global_locale.encoding) + +#if WCHAR_MAX > 0xffffU +#define UTF_8_MAX_LEN 6 +#else +#define UTF_8_MAX_LEN 3 +#endif + +/*  #define KUHN */ + +#warning implement __CTYPE_HAS_UTF_8_LOCALES! +#define __CTYPE_HAS_UTF_8_LOCALES + +/* Implementation-specific work functions. */ + +extern size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn, +								 const char **__restrict src, size_t n, +								 mbstate_t *ps, int allow_continuation); + +extern size_t _wchar_wcsntoutf8s(char *__restrict s, size_t n, +								 const wchar_t **__restrict src, size_t wn); + +/* glibc extensions. */ + +extern size_t __mbsnrtowcs(wchar_t *__restrict dst, +						   const char **__restrict src, +						   size_t NMC, size_t len, mbstate_t *__restrict ps); + +extern size_t __wcsnrtombs(char *__restrict dst, +						   const wchar_t **__restrict src, +						   size_t NWC, size_t len, mbstate_t *__restrict ps); + +/**********************************************************************/ +#ifdef L_btowc + +wint_t btowc(int c) +{ +	wchar_t wc; +	unsigned char buf[1]; +	mbstate_t mbstate; + +	if (c != EOF) { +		*buf = (unsigned char) c; +		mbstate.mask = 0;		/* Initialize the mbstate. */ +		if (mbrtowc(&wc, buf, 1, &mbstate) == 1) { +			return wc; +		} +	} +	return WEOF; +} + +#endif +/**********************************************************************/ +#ifdef L_wctob + +/* Note: We completely ignore ps in all currently supported conversions. */ + +int wctob(wint_t c) +{ +	unsigned char buf[MB_LEN_MAX]; + +	return (wcrtomb(buf, c, NULL) == 1) ? *buf : EOF; +} + +#endif +/**********************************************************************/ +#ifdef L_mbsinit + +int mbsinit(const mbstate_t *ps) +{ +	return !ps || !ps->mask; +} + +#endif +/**********************************************************************/ +#ifdef L_mbrlen + +size_t mbrlen(const char *__restrict s, size_t n, mbstate_t *__restrict ps) +{ +	static mbstate_t mbstate;	/* Rely on bss 0-init. */ + +	return mbrtowc(NULL, s, n, (ps != NULL) ? ps : &mbstate); +} + +#endif +/**********************************************************************/ +#ifdef L_mbrtowc + +size_t mbrtowc(wchar_t *__restrict pwc, const char *__restrict s, +			   size_t n, mbstate_t *__restrict ps) +{ +	static mbstate_t mbstate;	/* Rely on bss 0-init. */ +	wchar_t wcbuf[1]; +	const char *p; +	size_t r; +	char empty_string[1];		/* Avoid static to be fPIC friendly. */ + +	if (!ps) { +		ps = &mbstate; +	} + +	if (!s) { +		pwc = (wchar_t *) s;	/* NULL */ +		empty_string[0] = 0;	/* Init the empty string when necessary. */ +		s = empty_string; +		n = 1; +	} else if (!n) { +		return (ps->mask && (ps->wc == 0xffffU)) /* TODO: change error code? */ +			? ((size_t) -1) : ((size_t) -2); +	} + +	p = s; + +#ifdef __CTYPE_HAS_UTF_8_LOCALES +	/* Need to do this here since mbsrtowcs doesn't allow incompletes. */ +	if (ENCODING == __ctype_encoding_utf8) { +		r = _wchar_utf8sntowcs(pwc, 1, &p, n, ps, 1); +		return (r == 1) ? (p-s) : r; +	} +#endif + +	r = __mbsnrtowcs(wcbuf, &p, SIZE_MAX, 1, ps); + +	if (((ssize_t) r) >= 0) { +		if (pwc) { +			*pwc = *wcbuf; +		} +	} +	return (size_t) r; +} + +#endif +/**********************************************************************/ +#ifdef L_wcrtomb + +/* Note: We completely ignore ps in all currently supported conversions. */ +/* TODO: Check for valid state anyway? */ + +size_t wcrtomb(register char *__restrict s, wchar_t wc, +			   mbstate_t *__restrict ps) +{ +	wchar_t wcbuf[2]; +	const wchar_t *pwc; +	size_t r; +	char buf[MB_LEN_MAX]; + +	if (!s) { +		s = buf; +		wc = 0; +	} + +	pwc = wcbuf; +	wcbuf[0] = wc; +	wcbuf[1] = 0; + +	r = __wcsnrtombs(s, &pwc, SIZE_MAX, MB_LEN_MAX, ps); +	return (r != 0) ? r : 1; +} + +#endif +/**********************************************************************/ +#ifdef L_mbsrtowcs + +size_t mbsrtowcs(wchar_t *__restrict dst, const char **__restrict src, +				 size_t len, mbstate_t *__restrict ps) +{ +	static mbstate_t mbstate;	/* Rely on bss 0-init. */ + +	return __mbsnrtowcs(dst, src, SIZE_MAX, len, +						((ps != NULL) ? ps : &mbstate)); +} + +#endif +/**********************************************************************/ +#ifdef L_wcsrtombs + +/* Note: We completely ignore ps in all currently supported conversions. + + * TODO: Check for valid state anyway? */ + +size_t wcsrtombs(char *__restrict dst, const wchar_t **__restrict src, +				 size_t len, mbstate_t *__restrict ps) +{ +	return __wcsnrtombs(dst, src, SIZE_MAX, len, ps); +} + +#endif +/**********************************************************************/ +#ifdef L__wchar_utf8sntowcs + +/* Define DECODER to generate a UTF-8 decoder which passes Markus Kuhn's + * UTF-8-test.txt strss test. + */ +/*  #define DECODER */ + +#ifdef DECODER +#ifndef KUHN +#define KUHN +#endif +#endif + +size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn, +						  const char **__restrict src, size_t n, +						  mbstate_t *ps, int allow_continuation) +{ +	register const char *s; +	__uwchar_t mask; +	__uwchar_t wc; +	wchar_t wcbuf[1]; +	size_t count; +	int incr; + +	s = *src; + +	assert(s != NULL); +	assert(ps != NULL); + +	incr = 1; +	if (!pwc) { +		pwc = wcbuf; +		wn = SIZE_MAX; +		incr = 0; +	} +#warning fix _wchar_utf8sntowcs to allow wn == 0! +	assert(wn > 0);				/* TODO: fix this!! */ + +	count = wn; + +	if ((mask = (__uwchar_t) ps->mask) != 0) { /* A continuation... */ +#ifdef DECODER +		wc = (__uwchar_t) ps->wc; +		if (n) { +			goto CONTINUE; +		} +		goto DONE; +#else +		if ((wc = (__uwchar_t) ps->wc) != 0xffffU) { +			/* TODO: change error code here and below? */ +			if (n) { +				goto CONTINUE; +			} +			goto DONE; +		} +		return (size_t) -1;		/* We're in an error state. */ +#endif +	} + +	do { +		if (!n) { +			goto DONE; +		} +		--n; +		if ((wc = ((unsigned char) *s++)) >= 0x80) { /* Not ASCII... */ +			mask = 0x40; +#warning fix range for 16 bit wides +			if ( ((unsigned char)(s[-1] - 0xc0)) < (0xfe - 0xc0) ) { +				goto START; +			} +		BAD: +#ifdef DECODER +			wc = 0xfffd; +			goto COMPLETE; +#else +			ps->mask = mask; +			ps->wc = 0xffffU; +			return (size_t) -1;	/* Illegal start byte! */ +#endif + +		CONTINUE: +			while (n) { +				--n; +				if ((*s & 0xc0) != 0x80) { +					goto BAD; +				} +				mask <<= 5; +				wc <<= 6; +				wc += (*s & 0x3f);	/* keep seperate for bcc (smaller code) */ +				++s; +			START: +				wc &= ~(mask << 1); + +				if ((wc & mask) == 0) {	/* Character completed. */ +					if ((mask >>= 5) == 0x40) { +						mask += mask; +					} +					/* Check for invalid sequences (longer than necessary) +					 * and invalid chars.  */ +					if ( (wc < mask) /* Sequence not minimal length. */ +#ifdef KUHN +#if UTF_8_MAX_LEN == 3 +#error broken since mask can overflow!! +						 /* For plane 0, these are the only defined values.*/ +						 || (wc > 0xfffdU) +#else +						 /* Note that we don't need to worry about exceeding */ +						 /* 31 bits as that is the most that UTF-8 provides. */ +						 || ( ((__uwchar_t)(wc - 0xfffeU)) < 2) +#endif +						 || ( ((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U) ) +#endif /* KUHN */ +						 ) { +						goto BAD; +					} +					goto COMPLETE; +				} +			} +			/* Character potentially valid but incomplete. */ +			if (!allow_continuation) { +				if (count != wn) { +					return 0; +				} +				/* NOTE: The following can fail if you allow and then disallow +				 * continuation!!! */ +#if UTF_8_MAX_LEN == 3 +#error broken since mask can overflow!! +#endif +				/* Need to back up... */ +				do { +					--s; +				} while ((mask >>= 5) >= 0x40); +				goto DONE; +			} +			ps->mask = (wchar_t) mask; +			ps->wc = (wchar_t) wc; +			*src = s; +			return (size_t) -2; +		} +	COMPLETE: +		*pwc = wc; +		pwc += incr; + +	} +#ifdef DECODER +	while (--count); +#else +	while (wc && --count); + +	if (!wc) { +		s = NULL; +	} +#endif + + DONE: +	/* ps->wc is irrelavent here. */ +	ps->mask = 0; +	if (pwc != wcbuf) { +		*src = s; +	} + +	return wn - count; +} + +#endif +/**********************************************************************/ +#ifdef L__wchar_wcstoutf8s + +size_t _wchar_wcsntoutf8s(char *__restrict s, size_t n, +						  const wchar_t **__restrict src, size_t wn) +{ +	register char *p; +	size_t len, t; +	__uwchar_t wc; +	const __uwchar_t *swc; +	int store; +	char buf[MB_LEN_MAX]; +	char m; + +	store = 1; +	if (!s) { +		s = buf; +		n = SIZE_MAX; +		store = 0; +	} + +	t = n; +	swc = (const __uwchar_t *) *src; + +	assert(swc != NULL); + +	while (wn && t) { +		wc = *swc; + +		*s = wc; +		len = 1; + +		if (wc >= 0x80) { +#ifdef KUHN +			if ( +#if UTF_8_MAX_LEN == 3 +				/* For plane 0, these are the only defined values.*/ +				/* Note that we don't need to worry about exceeding */ +				/* 31 bits as that is the most that UTF-8 provides. */ +				(wc > 0xfffdU) +#else +				/* UTF_8_MAX_LEN == 6 */ +				(wc > 0x7fffffffUL) +				|| ( ((__uwchar_t)(wc - 0xfffeU)) < 2) +#endif +				|| ( ((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U) ) +				) { +				return (size_t) -1; +			} +#else  /* KUHN */ +#if UTF_8_MAX_LEN != 3 +			if (wc > 0x7fffffffUL) { /* Value too large. */ +				return (size_t) -1; +			} +#endif +#endif /* KUHN */ + +			wc >>= 1; +			p = s; +			do { +				++p; +			} while (wc >>= 5); +			wc = *swc; +			if ((len = p - s) > t) { /* Not enough space. */ +				break; +			} + +			m = 0x80; +			while( p>s ) { +				m = (m >> 1) | 0x80; +				*--p = (wc & 0x3f) | 0x80; +				wc >>= 6; +			} +			*s |= (m << 1); +		} else if (wc == 0) {	/* End of string. */ +			swc = NULL; +			break; +		} + +		++swc; +		--wn; +		t -= len; +		if (store) { +			s += len; +		} +	} + +	*src = (const wchar_t *) swc; + +	return n - t; +} + + +#endif +/**********************************************************************/ +#ifdef L___mbsnrtowcs + +/* WARNING: We treat len as SIZE_MAX when dst is NULL! */ + +size_t mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src, +				  size_t NMC, size_t len, mbstate_t *__restrict ps) +	 __attribute__ ((__weak__, __alias__("__mbsnrtowcs"))); + +size_t __mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src, +					size_t NMC, size_t len, mbstate_t *__restrict ps) +{ +	static mbstate_t mbstate;	/* Rely on bss 0-init. */ +	wchar_t wcbuf[1]; +	const char *s; +	size_t count, r; +	int incr; + +	if (!ps) { +		ps = &mbstate; +	} + +#ifdef __CTYPE_HAS_UTF_8_LOCALES +	if (ENCODING == __ctype_encoding_utf8) { +		return ((r = _wchar_utf8sntowcs(dst, len, src, NMC, ps, 1)) +				!= (size_t) -2) ? r : 0; +	} +#endif +	incr = 1; +	if (!dst) { +		dst = wcbuf; +		len = SIZE_MAX; +		incr = 0; +	} + +	/* Since all the following encodings are single-byte encodings... */ +	if (len > NMC) { +		len = NMC; +	} + +	count = len; +	s = *src; + +#ifdef __CTYPE_HAS_8_BIT_LOCALES +	if (ENCODING == __ctype_encoding_8_bit) { +		wchar_t wc; +		while (count) { +			if ((wc = ((unsigned char)(*s))) >= 0x80) {	/* Non-ASCII... */ +				wc -= 0x80; +				wc = __global_locale.tbl8c2wc[ +						  (__global_locale.idx8c2wc[wc >> Cc2wc_IDX_SHIFT] +						   << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))]; +				if (!wc) { +					goto BAD; +				} +			} else if (!wc) { +				s = NULL; +				break; +			} +			++s; +			*dst = wc; +			dst += incr; +			--count; +		} +		if (dst != wcbuf) { +			*src = s; +		} +		return len - count; +	} +#endif + +	assert(ENCODING == __ctype_encoding_7_bit); + +	while (count) { +		if ((*dst = (unsigned char) *s) == 0) { +			s = NULL; +			break; +		} +		if (*dst >= 0x80) { +#ifdef __CTYPE_HAS_8_BIT_LOCALES +		BAD: +#endif +			__set_errno(EILSEQ); +			return (size_t) -1; +		} +		++s; +		dst += incr; +		--count; +	} +	if (dst != wcbuf) { +		*src = s; +	} +	return len - count; +} + +#endif +/**********************************************************************/ +#ifdef L___wcsnrtombs + +/* WARNING: We treat len as SIZE_MAX when dst is NULL! */ + +/* Note: We completely ignore ps in all currently supported conversions. + * TODO: Check for valid state anyway? */ + +size_t wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src, +				  size_t NWC, size_t len, mbstate_t *__restrict ps) +	 __attribute__ ((__weak__, __alias__("__wcsnrtombs"))); + +size_t __wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src, +					size_t NWC, size_t len, mbstate_t *__restrict ps) +{ +	const __uwchar_t *s; +	size_t count; +	int incr; +	char buf[MB_LEN_MAX]; + +#ifdef __CTYPE_HAS_UTF_8_LOCALES +	if (ENCODING == __ctype_encoding_utf8) { +		return _wchar_wcsntoutf8s(dst, len, src, NWC); +	} +#endif + +	incr = 1; +	if (!dst) { +		dst = buf; +		len = SIZE_MAX; +		incr = 0; +	} + +	/* Since all the following encodings are single-byte encodings... */ +	if (len > NWC) { +		len = NWC; +	} + +	count = len; +	s = (const __uwchar_t *) *src; + +#ifdef __CTYPE_HAS_8_BIT_LOCALES +	if (ENCODING == __ctype_encoding_8_bit) { +		__uwchar_t wc; +		__uwchar_t u; +		while (count) { +			if ((wc = *s) <= 0x7f) { +				if (!(*dst = (unsigned char) wc)) { +					s = NULL; +					break; +				} +			} else { +				u = 0; +				if (wc <= Cwc2c_DOMAIN_MAX) { +					u = __global_locale.idx8wc2c[wc >> (Cwc2c_TI_SHIFT +														+ Cwc2c_TT_SHIFT)]; +					u = __global_locale.tbl8wc2c[(u << Cwc2c_TI_SHIFT) +									+ ((wc >> Cwc2c_TT_SHIFT) +									   & ((1 << Cwc2c_TI_SHIFT)-1))]; +					u = __global_locale.tbl8wc2c[Cwc2c_TI_LEN +									+ (u << Cwc2c_TT_SHIFT) +									+ (wc & ((1 << Cwc2c_TT_SHIFT)-1))]; +				} + +/*  #define __WCHAR_REPLACEMENT_CHAR '?' */ +#ifdef __WCHAR_REPLACEMENT_CHAR +				*dst = (unsigned char) ( u ? u : __WCHAR_REPLACEMENT_CHAR ); +#else +				if (!u) { +					goto BAD; +				} +				*dst = (unsigned char) u; +#endif +			} +			++s; +			dst += incr; +			--count; +		} +		if (dst != buf) { +			*src = (const wchar_t *) s; +		} +		return len - count; +	} +#endif + +	assert(ENCODING == __ctype_encoding_7_bit); + +	while (count) { +		if (*s >= 0x80) { +#if defined(__CTYPE_HAS_8_BIT_LOCALES) && !defined(__WCHAR_REPLACEMENT_CHAR) +		BAD: +#endif +			__set_errno(EILSEQ); +			return (size_t) -1; + +		} +		if ((*dst = (unsigned char) *s) == 0) { +			s = NULL; +			break; +		} +		++s; +		dst += incr; +		--count; +	} +	if (dst != buf) { +		*src = (const wchar_t *) s; +	} +	return len - count; +} + +#endif +/**********************************************************************/ diff --git a/libc/stdlib/Makefile b/libc/stdlib/Makefile index 64ae75d18..e69ec4ea8 100644 --- a/libc/stdlib/Makefile +++ b/libc/stdlib/Makefile @@ -35,6 +35,12 @@ ifeq ($(HAS_LONG_LONG),true)  	MOBJ +=  llabs.o atoll.o strtoll.o strtoull.o _stdlib_strto_ll.o  endif +ifeq ($(HAS_WCHAR),true) +	MOBJ += mblen.o mbtowc.o wctomb.o mbstowcs.o wcstombs.o \ +		_stdlib_mb_cur_max.o  +endif + +  MSRC2=atexit.c  MOBJ2=atexit.o on_exit.o __exit_handler.o exit.o diff --git a/libc/stdlib/stdlib.c b/libc/stdlib/stdlib.c index 1cd350c31..4c9e8f039 100644 --- a/libc/stdlib/stdlib.c +++ b/libc/stdlib/stdlib.c @@ -623,3 +623,136 @@ void ssort (void  *base,  #endif  /**********************************************************************/ +/* Multibyte and wchar stuff follows. */ + +#ifdef __UCLIBC_HAS_WCHAR__ + +#include <locale.h> +#include <wchar.h> + +/* TODO: clean up the following... */ + +#if WCHAR_MAX > 0xffffU +#define UTF_8_MAX_LEN 6 +#else +#define UTF_8_MAX_LEN 3 +#endif + +#define ENCODING (__global_locale.encoding) + +#endif + +/**********************************************************************/ +#ifdef L__stdlib_mb_cur_max + +size_t _stdlib_mb_cur_max(void) +{ +	return __global_locale.mb_cur_max; +} + +#endif +/**********************************************************************/ +#ifdef L_mblen + +#warning implement __CTYPE_HAS_UTF_8_LOCALES! +#define __CTYPE_HAS_UTF_8_LOCALES + +int mblen(register const char *s, size_t n) +{ +	static mbstate_t state; +	size_t r; + +	if (!s) { +		state.mask = 0; +#ifdef __CTYPE_HAS_UTF_8_LOCALES +		return ENCODING == __ctype_encoding_utf8; +#else +		return 0; +#endif +	} + +	if ((r = mbrlen(s, n, &state)) == (size_t) -2) { +		/* TODO: Should we set an error state? */ +		state.wc = 0xffffU;		/* Make sure we're in an error state. */ +		return (size_t) -1;		/* TODO: Change error code above? */ +	} +	return r; +} + +#endif +/**********************************************************************/ +#ifdef L_mbtowc + +#warning implement __CTYPE_HAS_UTF_8_LOCALES! +#define __CTYPE_HAS_UTF_8_LOCALES + +int mbtowc(wchar_t *__restrict pwc, register const char *__restrict s, size_t n) +{ +	static mbstate_t state; +	size_t r; + +	if (!s) { +		state.mask = 0; +#ifdef __CTYPE_HAS_UTF_8_LOCALES +		return ENCODING == __ctype_encoding_utf8; +#else +		return 0; +#endif +	} + +	if ((r = mbrtowc(pwc, s, n, &state)) == (size_t) -2) { +		/* TODO: Should we set an error state? */ +		state.wc = 0xffffU;		/* Make sure we're in an error state. */ +		return (size_t) -1;		/* TODO: Change error code above? */ +	} +	return r; +} + +#endif +/**********************************************************************/ +#ifdef L_wctomb + +#warning implement __CTYPE_HAS_UTF_8_LOCALES! +#define __CTYPE_HAS_UTF_8_LOCALES + +/* Note: We completely ignore state in all currently supported conversions. */ + +int wctomb(register char *__restrict s, wchar_t swc) +{ +	return (!s) +		? +#ifdef __CTYPE_HAS_UTF_8_LOCALES +		(ENCODING == __ctype_encoding_utf8) +#else +		0						/* Encoding is stateless. */ +#endif +		: ((ssize_t) wcrtomb(s, swc, NULL)); +} + +#endif +/**********************************************************************/ +#ifdef L_mbstowcs + +size_t mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n) +{ +	mbstate_t state; + +	state.mask = 0;				/* Always start in initial shift state. */ + +	return mbsrtowcs(pwcs, &s, n, &state); +} + +#endif +/**********************************************************************/ +#ifdef L_wcstombs + +/* Note: We completely ignore state in all currently supported conversions. */ + +size_t wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n) +{ +	return wcsrtombs(s, &pwcs, n, NULL); +} + +#endif +/**********************************************************************/ +  | 
