diff options
Diffstat (limited to 'libc')
| -rw-r--r-- | libc/misc/locale/locale.c | 4 | ||||
| -rw-r--r-- | libc/misc/time/time.c | 7 | ||||
| -rw-r--r-- | libc/misc/wchar/Makefile | 15 | ||||
| -rw-r--r-- | libc/misc/wchar/wchar.c | 658 | ||||
| -rw-r--r-- | libc/misc/wchar/wstdio.c | 21 | ||||
| -rw-r--r-- | libc/stdio/Makefile | 10 | ||||
| -rw-r--r-- | libc/stdio/printf.c | 1134 | ||||
| -rw-r--r-- | libc/stdio/stdio.c | 58 | ||||
| -rw-r--r-- | libc/stdlib/Makefile | 11 | ||||
| -rw-r--r-- | libc/stdlib/stdlib.c | 215 | ||||
| -rw-r--r-- | libc/sysdeps/linux/common/bits/uClibc_locale.h | 2 | ||||
| -rw-r--r-- | libc/sysdeps/linux/common/bits/uClibc_stdio.h | 5 | 
12 files changed, 1667 insertions, 473 deletions
diff --git a/libc/misc/locale/locale.c b/libc/misc/locale/locale.c index 0ff359d3d..0875a4e5b 100644 --- a/libc/misc/locale/locale.c +++ b/libc/misc/locale/locale.c @@ -454,8 +454,8 @@ void _locale_init(void)  		= (const unsigned char *) &__locale_mmap->tblwuplow;  	__global_locale.tblwuplow_diff  		= (const uint16_t *) &__locale_mmap->tblwuplow_diff; -	__global_locale.tblwcomb -		= (const unsigned char *) &__locale_mmap->tblwcomb; +/* 	__global_locale.tblwcomb */ +/* 		= (const unsigned char *) &__locale_mmap->tblwcomb; */  	/* width?? */  #endif /* __WCHAR_ENABLED */ diff --git a/libc/misc/time/time.c b/libc/misc/time/time.c index 378854adc..838a3a025 100644 --- a/libc/misc/time/time.c +++ b/libc/misc/time/time.c @@ -90,6 +90,9 @@   * Defining __TIME_TZ_OPT_SPEED will cause a tzset() to keep a copy of the   * last TZ setting string and do a "fast out" if the current string is the   * same. + * + * Nov 21, 2002   Fix an error return case in _time_mktime. + *    */ @@ -2022,6 +2025,10 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)  	localtime_r(&t, (struct tm *)p); +	if (t < 0) { +	    return -1; +	} +  	if (store_on_success) {  		memcpy(timeptr, p, sizeof(struct tm));  	} diff --git a/libc/misc/wchar/Makefile b/libc/misc/wchar/Makefile index 7ac27b6ea..acc852195 100644 --- a/libc/misc/wchar/Makefile +++ b/libc/misc/wchar/Makefile @@ -23,12 +23,17 @@  TOPDIR=../../../  include $(TOPDIR)Rules.mak +TARGET_CC = $(TOPDIR)extra/gcc-uClibc/$(TARGET_ARCH)-uclibc-gcc  MSRC1=  wchar.c  MOBJ1=  btowc.o wctob.o mbsinit.o mbrlen.o mbrtowc.o wcrtomb.o mbsrtowcs.o \  	wcsrtombs.o _wchar_utf8sntowcs.o _wchar_wcsntoutf8s.o \  	__mbsnrtowcs.o __wcsnrtombs.o wcwidth.o wcswidth.o +ifeq ($(UCLIBC_HAS_LOCALE),y) +	MOBJ1 += iconv.o +endif +  MSRC2=  wstdio.c  MOBJ2=  fwide.o \  	fgetwc.o getwchar.o fgetws.o \ @@ -37,10 +42,6 @@ MOBJ2=  fwide.o \  # getwc (fgetwc alias) getwc_unlocked (fgetwc_unlocked alias)  # putwc (fputwc alias) putwc_unlocked (fputwc_unlocked alias) -# wcwidth wcswidth -# wcstod wcstof wcstold -# wcstol wcstoul wcstoq wcstouq wcstoll wcstoull -# fwprintf wprintf swprintf vfwprintf vwprintf vswprintf  # fwscanf  wscanf  swscanf  vfwscanf  vwscanf  vswscanf  # wcsftime @@ -61,6 +62,10 @@ $(MOBJ2): $(MSRC2)  	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o  	$(STRIPTOOL) -x -R .note -R .comment $*.o +iconv.target: wchar.c +	$(TARGET_CC) $(CFLAGS) -DL_iconv_main wchar.c -o $@ +	$(STRIPTOOL) -x -R .note -R .comment $@ +  clean: -	rm -f *.[oa] *~ core +	rm -f *.[oa] *~ core iconv.target diff --git a/libc/misc/wchar/wchar.c b/libc/misc/wchar/wchar.c index 7da3b1a50..a6e5fc616 100644 --- a/libc/misc/wchar/wchar.c +++ b/libc/misc/wchar/wchar.c @@ -1,3 +1,4 @@ +  /*  Copyright (C) 2002     Manuel Novoa III   *   *  This library is free software; you can redistribute it and/or @@ -79,6 +80,12 @@   *   framework.  Minimally tested at the moment, but the stub C-locale   *   version (which most people would probably be using) should be fine.   * + * Nov 21, 2002 + * + * Revert the wc<->mb changes from earlier this month involving the C-locale. + * Add a couple of ugly hacks to support *wprintf. + * Add a mini iconv() and iconv implementation (requires locale support). + *   * Manuel   */ @@ -97,13 +104,17 @@  #ifdef __UCLIBC_HAS_LOCALE__  #define ENCODING (__global_locale.encoding) -#ifdef __UCLIBC_MJN3_ONLY__ -#warning implement __CTYPE_HAS_UTF_8_LOCALES! +#ifndef __CTYPE_HAS_UTF_8_LOCALES +#warning __CTYPE_HAS_UTF_8_LOCALES not set!  #endif -#define __CTYPE_HAS_UTF_8_LOCALES  #else -#undef __CTYPE_HAS_8_BIT_LOCALES -#undef __CTYPE_HAS_UTF_8_LOCALES +#define ENCODING (__ctype_encoding_7_bit) +#ifdef __CTYPE_HAS_8_BIT_LOCALES +#error __CTYPE_HAS_8_BIT_LOCALES is defined! +#endif +#ifdef __CTYPE_HAS_UTF_8_LOCALES +#error __CTYPE_HAS_UTF_8_LOCALES is defined! +#endif  #undef L__wchar_utf8sntowcs  #undef L__wchar_wcsntoutf8s  #endif @@ -114,7 +125,7 @@  #define UTF_8_MAX_LEN 3  #endif -/*  #define KUHN */ +#define KUHN 1  /* Implementation-specific work functions. */ @@ -157,17 +168,14 @@ wint_t btowc(int c)  #else  /*  __CTYPE_HAS_8_BIT_LOCALES */ -#ifdef __CTYPE_HAS_UTF_8_LOCALES -	if (ENCODING == __ctype_encoding_utf8) { -		return (((unsigned int)c) < 0x80) ? c : WEOF; -	} -#endif /* __CTYPE_HAS_UTF_8_LOCALES */ -  #ifdef __UCLIBC_HAS_LOCALE__ -	assert(ENCODING == __ctype_encoding_7_bit); -#endif +	assert((ENCODING == __ctype_encoding_7_bit) +		   || (ENCODING == __ctype_encoding_utf8)); +#endif /* __UCLIBC_HAS_LOCALE__ */ -	return (((unsigned int)c) <= UCHAR_MAX) ? c : WEOF; +	/* If we don't have 8-bit locale support, then this is trivial since +	 * anything outside of 0-0x7f is illegal in C/POSIX and UTF-8 locales. */ +	return (((unsigned int)c) < 0x80) ? c : WEOF;  #endif /*  __CTYPE_HAS_8_BIT_LOCALES */  } @@ -188,17 +196,18 @@ int wctob(wint_t c)  #else  /*  __CTYPE_HAS_8_BIT_LOCALES */ -#ifdef __CTYPE_HAS_UTF_8_LOCALES -	if (ENCODING == __ctype_encoding_utf8) { -		return ((c >= 0) && (c < 0x80)) ? c : EOF; -	} -#endif /* __CTYPE_HAS_UTF_8_LOCALES */ -  #ifdef __UCLIBC_HAS_LOCALE__ -	assert(ENCODING == __ctype_encoding_7_bit); -#endif +	assert((ENCODING == __ctype_encoding_7_bit) +		   || (ENCODING == __ctype_encoding_utf8)); +#endif /* __UCLIBC_HAS_LOCALE__ */ + +	/* If we don't have 8-bit locale support, then this is trivial since +	 * anything outside of 0-0x7f is illegal in C/POSIX and UTF-8 locales. */ +	 +	/* TODO: need unsigned version of wint_t... */ +/*  	return (((unsigned int)c) < 0x80) ? c : WEOF; */ +	return ((c >= 0) && (c < 0x80)) ? c : EOF; -	return ((c >= 0) && (c <= UCHAR_MAX)) ? c : EOF;  #endif /*  __CTYPE_HAS_8_BIT_LOCALES */  } @@ -359,9 +368,19 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,  	assert(ps != NULL);  	incr = 1; -	if (!pwc) { +	/* NOTE: The following is an AWFUL HACK!  In order to support %s in +	 * wprintf, we need to be able to compute the number of wchars needed +	 * for the mbs conversion, not to exceed the precision specified. +	 * But if dst is NULL, the return value is the length assuming a +	 * sufficiently sized buffer.  So, we allow passing of (wchar_t *) ps +	 * as pwc in order to flag that we really want the length, subject +	 * to the restricted buffer size and no partial conversions. +	 * See mbsnrtowcs() as well. */ +	if (!pwc || (pwc == ((wchar_t *)ps))) { +		if (!pwc) { +			wn = SIZE_MAX; +		}  		pwc = wcbuf; -		wn = SIZE_MAX;  		incr = 0;  	} @@ -406,7 +425,7 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,  			}  		BAD:  #ifdef DECODER -			wc = 0xfffd; +			wc = 0xfffdU;  			goto COMPLETE;  #else  			ps->mask = mask; @@ -635,9 +654,19 @@ size_t __mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src,  	}  #endif  	incr = 1; -	if (!dst) { +	/* NOTE: The following is an AWFUL HACK!  In order to support %s in +	 * wprintf, we need to be able to compute the number of wchars needed +	 * for the mbs conversion, not to exceed the precision specified. +	 * But if dst is NULL, the return value is the length assuming a +	 * sufficiently sized buffer.  So, we allow passing of ((wchar_t *)ps) +	 * as dst in order to flag that we really want the length, subject +	 * to the restricted buffer size and no partial conversions. +	 * See _wchar_utf8sntowcs() as well. */ +	if (!dst || (dst == ((wchar_t *)ps))) { +		if (!dst) { +			len = SIZE_MAX; +		}  		dst = wcbuf; -		len = SIZE_MAX;  		incr = 0;  	} @@ -659,8 +688,7 @@ size_t __mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src,  						  (__global_locale.idx8c2wc[wc >> Cc2wc_IDX_SHIFT]  						   << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];  				if (!wc) { -					__set_errno(EILSEQ); -					return (size_t) -1; +					goto BAD;  				}  			}  			if (!(*dst = wc)) { @@ -687,6 +715,13 @@ size_t __mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src,  			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; @@ -772,7 +807,7 @@ size_t __wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src,  									+ (wc & ((1 << Cwc2c_TT_SHIFT)-1))];  				} -/*  #define __WCHAR_REPLACEMENT_CHAR '?' */ +#define __WCHAR_REPLACEMENT_CHAR '?'  #ifdef __WCHAR_REPLACEMENT_CHAR  				*dst = (unsigned char) ( u ? u : __WCHAR_REPLACEMENT_CHAR );  #else  /* __WCHAR_REPLACEMENT_CHAR */ @@ -798,13 +833,12 @@ size_t __wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src,  #endif  	while (count) { -		if (*s > UCHAR_MAX) { +		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; @@ -1068,3 +1102,559 @@ int wcwidth(wchar_t wc)  #endif  /**********************************************************************/ + + +typedef struct { +	mbstate_t tostate; +	mbstate_t fromstate; +	int tocodeset; +	int fromcodeset; +	int frombom; +	int tobom; +	int fromcodeset0; +	int frombom0; +	int tobom0; +	int skip_invalid_input;		/* To support iconv -c option. */ +} _UC_iconv_t; + + + +#ifdef L_iconv + +#include <iconv.h> +#include <string.h> +#include <endian.h> +#include <byteswap.h> + +#if (__BYTE_ORDER != __BIG_ENDIAN) && (__BYTE_ORDER != __LITTLE_ENDIAN) +#error unsupported endianness for iconv +#endif + +#ifndef __CTYPE_HAS_8_BIT_LOCALES +#error currently iconv requires 8 bit locales +#endif +#ifndef __CTYPE_HAS_UTF_8_LOCALES +#error currently iconv requires UTF-8 locales +#endif + + +enum { +	IC_WCHAR_T = 0xe0, +	IC_MULTIBYTE = 0xe0, +#if __BYTE_ORDER == __BIG_ENDIAN +	IC_UCS_4 =	0xec, +	IC_UTF_32 = 0xe4, +	IC_UCS_2 =	0xe2, +	IC_UTF_16 = 0xea, +#else +	IC_UCS_4 =	0xed, +	IC_UTF_32 = 0xe5, +	IC_UCS_2 =	0xe3, +	IC_UTF_16 = 0xeb, +#endif +	IC_UTF_8 = 2, +	IC_ASCII = 1 +}; + +/* For the multibyte + * bit 0 means swap endian + * bit 1 means 2 byte + * bit 2 means 4 byte + * + */ + +const unsigned char codesets[] = +	"\x0a\xe0""WCHAR_T\x00"		/* superset of UCS-4 but platform-endian */ +#if __BYTE_ORDER == __BIG_ENDIAN +	"\x08\xec""UCS-4\x00"		/* always BE */ +	"\x0a\xec""UCS-4BE\x00" +	"\x0a\xed""UCS-4LE\x00" +	"\x09\fe4""UTF-32\x00"		/* platform endian with BOM */ +	"\x0b\xe4""UTF-32BE\x00" +	"\x0b\xe5""UTF-32LE\x00" +	"\x08\xe2""UCS-2\x00"		/* always BE */ +	"\x0a\xe2""UCS-2BE\x00" +	"\x0a\xe3""UCS-2LE\x00" +	"\x09\xea""UTF-16\x00"		/* platform endian with BOM */ +	"\x0b\xea""UTF-16BE\x00" +	"\x0b\xeb""UTF-16LE\x00" +#elif __BYTE_ORDER == __LITTLE_ENDIAN +	"\x08\xed""UCS-4\x00"		/* always BE */ +	"\x0a\xed""UCS-4BE\x00" +	"\x0a\xec""UCS-4LE\x00" +	"\x09\xf4""UTF-32\x00"		/* platform endian with BOM */ +	"\x0b\xe5""UTF-32BE\x00" +	"\x0b\xe4""UTF-32LE\x00" +	"\x08\xe3""UCS-2\x00"		/* always BE */ +	"\x0a\xe3""UCS-2BE\x00" +	"\x0a\xe2""UCS-2LE\x00" +	"\x09\xfa""UTF-16\x00"		/* platform endian with BOM */ +	"\x0b\xeb""UTF-16BE\x00" +	"\x0b\xea""UTF-16LE\x00" +#endif +	"\x08\x02""UTF-8\x00" +	"\x0b\x01""US-ASCII\x00" +	"\x07\x01""ASCII";			/* Must be last! (special case to save a nul) */ + +static int find_codeset(const char *name) +{ +	const unsigned char *s; +	int codeset; + +	for (s = codesets ; *s ; s += *s) { +		if (!strcasecmp(s+2, name)) { +			return s[1]; +		} +	} + +	/* The following is ripped from find_locale in locale.c. */ + +	/* TODO: maybe CODESET_LIST + *s ??? */ +	/* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */ +	codeset = 2; +	s = CODESET_LIST; +	do { +		++codeset;		/* Increment codeset first. */ +		if (!strcasecmp(CODESET_LIST+*s, name)) { +			return codeset; +		} +	} while (*++s); + +	return 0;			/* No matching codeset! */ +} + +iconv_t iconv_open(const char *tocode, const char *fromcode) +{ +	register _UC_iconv_t *px; +	int tocodeset, fromcodeset; + +	if (((tocodeset = find_codeset(tocode)) != 0) +		&& ((fromcodeset = find_codeset(fromcode)) != 0)) { +		if ((px = malloc(sizeof(_UC_iconv_t))) != NULL) { +			px->tocodeset = tocodeset; +			px->tobom0 = px->tobom = (tocodeset & 0x10) >> 4; +			px->fromcodeset0 = px->fromcodeset = fromcodeset; +			px->frombom0 = px->frombom = (fromcodeset & 0x10) >> 4; +			px->skip_invalid_input = px->tostate.mask = px->fromstate.mask = 0; +			return (iconv_t) px; +		} +	} else { +		__set_errno(EINVAL); +	} +	return (iconv_t)(-1); +} + +int iconv_close(iconv_t cd) +{ +	free(cd); + +	return 0; +} + +size_t iconv(iconv_t cd, char **__restrict inbuf, +			 size_t *__restrict inbytesleft, +		     char **__restrict outbuf, size_t *__restrict outbytesleft) +{ +	_UC_iconv_t *px = (_UC_iconv_t *) cd; +	size_t nrcount, r; +	wchar_t wc, wc2; +	int inci, inco; + +	assert(px != (_UC_iconv_t *)(-1)); +	assert(sizeof(wchar_t) == 4); + +	if (!inbuf || !*inbuf) {	/* Need to reinitialze conversion state. */ +		/* Note: For shift-state encodings we possibly need to output the +		 * shift sequence to return to initial state! */ +		if ((px->fromcodeset & 0xf0) == 0xe0) { +		} +		px->tostate.mask = px->fromstate.mask = 0; +		px->fromcodeset = px->fromcodeset0; +		px->tobom = px->tobom0; +		px->frombom = px->frombom0; +		return 0; +	} + +	nrcount = 0; +	while (*inbytesleft) { +		if (!*outbytesleft) { +		TOO_BIG: +			__set_errno(E2BIG); +			return (size_t) -1; +		} + +		inci = inco = 1; +		if (px->fromcodeset >= IC_MULTIBYTE) { +			inci = (px->fromcodeset == IC_WCHAR_T) ? 4: (px->fromcodeset & 6); +			if (*inbytesleft < inci) goto INVALID; +			wc = (((unsigned int)((unsigned char)((*inbuf)[0]))) << 8) +				+ ((unsigned char)((*inbuf)[1])); +			if (inci == 4) { +				wc = (((unsigned int)((unsigned char)((*inbuf)[2]))) << 8) +					+ ((unsigned char)((*inbuf)[3])) + (wc << 16); +				if (!(px->fromcodeset & 1)) wc = bswap_32(wc); +			} else { +				if (!(px->fromcodeset & 1)) wc = bswap_16(wc); +				if (((px->fromcodeset & IC_UTF_16) == IC_UTF_16) +					 && (((__uwchar_t)(wc - 0xd800U)) < (0xdc00U - 0xd800U)) +					) {			/* surrogate */ +					wc =- 0xd800U; +					if (*inbytesleft < 4) goto INVALID; +					wc2 = (((unsigned int)((unsigned char)((*inbuf)[2]))) << 8) +						+ ((unsigned char)((*inbuf)[3])); +					if (!(px->fromcodeset & 1)) wc = bswap_16(wc2); +					if (((__uwchar_t)(wc2 -= 0xdc00U)) < (0xe0000U - 0xdc00U)) { +						goto ILLEGAL; +					} +					inci = 4;	/* Change inci here in case skipping illegals. */ +					wc = 0x10000UL + (wc << 10) + wc2; +				} +			} + +			if (px->frombom) { +				px->frombom = 0; +				if ((wc == 0xfeffU) +					|| (wc == ((inci == 4) +							   ? (((wchar_t) 0xfffe0000UL)) +							   : ((wchar_t)(0xfffeUL)))) +					) { +					if (wc != 0xfeffU) { +						px->fromcodeset ^= 1; /* toggle endianness */ +						wc = 0xfeffU; +					} +					if (!px->frombom) { +						goto BOM_SKIP_OUTPUT; +					} +					goto GOT_BOM; +				} +			} + +			if (px->fromcodeset != IC_WCHAR_T) { +				if (((__uwchar_t) wc) > (((px->fromcodeset & IC_UCS_4) == IC_UCS_4) +										 ? 0x7fffffffUL : 0x10ffffUL) +#ifdef KUHN +					|| (((__uwchar_t)(wc - 0xfffeU)) < 2) +					|| (((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U)) +#endif +					) { +					goto ILLEGAL; +				} +			} +		} else if (px->fromcodeset == IC_UTF_8) { +			const char *p = *inbuf; +			r = _wchar_utf8sntowcs(&wc, 1, &p, *inbytesleft, &px->fromstate, 0); +			if (((ssize_t) r) <= 0) { /* either EILSEQ or incomplete or nul */ +				if (((ssize_t) r) < 0) { /* either EILSEQ or incomplete or nul */ +					assert((r == (size_t)(-1)) || (r == (size_t)(-2))); +					if (r == (size_t)(-2)) { +					INVALID: +						__set_errno(EINVAL); +					} else { +						px->fromstate.mask = 0; +						inci = 1; +					ILLEGAL: +						if (px->skip_invalid_input) { +							px->skip_invalid_input = 2;	/* flag for iconv utility */ +							goto BOM_SKIP_OUTPUT; +						} +						__set_errno(EILSEQ); +					} +					return (size_t)(-1); +				} +#ifdef __UCLIBC_MJN3_ONLY__ +#warning optimize this +#endif +				if (p != NULL) { /* incomplet char case */ +					goto INVALID; +				} +				p = *inbuf + 1;	/* nul */ +			} +			inci = p - *inbuf; +		} else if ((wc = ((unsigned char)(**inbuf))) >= 0x80) {	/* Non-ASCII... */ +			if (px->fromcodeset == IC_ASCII) { /* US-ASCII codeset */ +				goto ILLEGAL; +			} else {			/* some other 8-bit ascii-extension codeset */ +				const codeset_8_bit_t *c8b +					= __locale_mmap->codeset_8_bit + px->fromcodeset - 3; +				wc -= 0x80; +				wc = __global_locale.tbl8c2wc[ +							 (c8b->idx8c2wc[wc >> Cc2wc_IDX_SHIFT] +							  << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))]; +				if (!wc) { +					goto ILLEGAL; +				} +			} +		} else { +			fprintf(stderr, "ARG!! %d\n", px->fromcodeset); +		} + + +		if (px->tobom) { +			inci = 0; +			wc = 0xfeffU; +	GOT_BOM: +			px->tobom = 0; +		} + +		if (px->tocodeset >= IC_MULTIBYTE) { +			inco = (px->tocodeset == IC_WCHAR_T) ? 4: (px->tocodeset & 6); +			if (*outbytesleft < inci) goto TOO_BIG; +			if (px->tocodeset != IC_WCHAR_T) { +				if (((__uwchar_t) wc) > (((px->tocodeset & IC_UCS_4) == IC_UCS_4) +										 ? 0x7fffffffUL : 0x10ffffUL) +#ifdef KUHN +					|| (((__uwchar_t)(wc - 0xfffeU)) < 2) +					|| (((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U)) +#endif +					) { +				REPLACE_32: +					wc = 0xfffd; +					++nrcount; +				} +			} +			if (inco == 4) { +				if (px->tocodeset & 1) wc = bswap_32(wc); +			} else { +				if (((__uwchar_t)wc ) > 0xffffU) { +					if ((px->tocodeset & IC_UTF_16) != IC_UTF_16) { +						goto REPLACE_32; +					} +					if (*outbytesleft < (inco = 4)) goto TOO_BIG; +					wc2 = 0xdc00U + (wc & 0x3ff); +					wc = 0xd800U + ((wc >> 10) & 0x3ff); +					if (px->tocodeset & 1) { +						wc = bswap_16(wc); +						wc2 = bswap_16(wc2); +					} +					wc += (wc2 << 16); +				} else if (px->tocodeset & 1) wc = bswap_16(wc); +			}				 +			(*outbuf)[0] = (char)((unsigned char)(wc)); +			(*outbuf)[1] = (char)((unsigned char)(wc >> 8)); +			if (inco == 4) { +				(*outbuf)[2] = (char)((unsigned char)(wc >> 16)); +				(*outbuf)[3] = (char)((unsigned char)(wc >> 24)); +			} +		} else if (px->tocodeset == IC_UTF_8) { +			const wchar_t *pw = &wc; +			do { +				r = _wchar_wcsntoutf8s(*outbuf, *outbytesleft, &pw, 1); +				if (r != (size_t)(-1)) { +#ifdef __UCLIBC_MJN3_ONLY__ +#warning what happens for a nul? +#endif +					if (r == 0) { +						if (wc != 0) { +							goto TOO_BIG; +						} +						++r; +					} +					break; +				} +				wc = 0xfffdU; +				++nrcount; +			} while (1); +			inco = r; +		} else if (((__uwchar_t)(wc)) < 0x80) { +		CHAR_GOOD: +				**outbuf = wc; +		} else { +			if ((px->tocodeset != 0x01) && (wc <= Cwc2c_DOMAIN_MAX)) { +				const codeset_8_bit_t *c8b +					= __locale_mmap->codeset_8_bit + px->tocodeset - 3; +				__uwchar_t u; +				u = c8b->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))]; +				wc = __global_locale.tbl8wc2c[Cwc2c_TI_LEN +						 + (u << Cwc2c_TT_SHIFT) +						 + (wc & ((1 << Cwc2c_TT_SHIFT)-1))]; +				if (wc) { +					goto CHAR_GOOD; +				} +			} +			**outbuf = '?'; +			++nrcount; +		} + +		*outbuf += inco; +		*outbytesleft -= inco; +	BOM_SKIP_OUTPUT: +		*inbuf += inci; +		*inbytesleft -= inci; +	} +	return nrcount; +} + +#endif +/**********************************************************************/ +#ifdef L_iconv_main + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include <iconv.h> +#include <stdarg.h> +#include <libgen.h> + +extern const unsigned char codesets[]; + +#define IBUF BUFSIZ +#define OBUF BUFSIZ + +char *progname; +int hide_errors; + +static void error_msg(const char *fmt, ...)  +	 __attribute__ ((noreturn, format (printf, 1, 2))); + +static void error_msg(const char *fmt, ...)  +{ +	va_list arg; + +	if (!hide_errors) { +		fprintf(stderr, "%s: ", progname); +		va_start(arg, fmt); +		vfprintf(stderr, fmt, arg); +		va_end(arg); +	} + +	exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ +	FILE *ifile; +	FILE *ofile = stdout; +	const char *p; +	const char *s; +	static const char opt_chars[] = "tfocsl"; +	                              /* 012345 */ +	const char *opts[sizeof(opt_chars)]; /* last is infile name */ +	iconv_t ic; +	char ibuf[IBUF]; +	char obuf[OBUF]; +	char *pi; +	char *po; +	size_t ni, no, r, pos; + +	hide_errors = 0; + +	for (s = opt_chars ; *s ; s++) { +		opts[ s - opt_chars ] = NULL; +	} + +	progname = *argv; +	while (--argc) { +		p = *++argv; +		if ((*p != '-') || (*++p == 0)) { +			break; +		} +		do { +			if ((s = strchr(opt_chars,*p)) == NULL) { +			USAGE: +				s = basename(progname); +				fprintf(stderr, +						"%s [-cs] -f fromcode -t tocode [-o outputfile] [inputfile ...]\n" +						"  or\n%s -l\n", s, s); +				return EXIT_FAILURE; +			} +			if ((s - opt_chars) < 3) { +				if ((--argc == 0) || opts[s - opt_chars]) { +					goto USAGE; +				} +				opts[s - opt_chars] = *++argv; +			} else { +				opts[s - opt_chars] = p; +			} +		} while (*++p); +	} + +	if (opts[5]) {				/* -l */ +		fprintf(stderr, "Recognized codesets:\n"); +		for (s = codesets ; *s ; s += *s) { +			fprintf(stderr,"  %s\n", s+2); +		} +		s = CODESET_LIST; +		do { +			fprintf(stderr,"  %s\n", CODESET_LIST+ (unsigned char)(*s)); +		} while (*++s); + +		return EXIT_SUCCESS; +	} + +	if (opts[4]) { +		hide_errors = 1; +	} + +	if (!opts[0] || !opts[1]) { +		goto USAGE; +	} +	if ((ic = iconv_open(opts[0],opts[1])) == ((iconv_t)(-1))) { +		error_msg( "unsupported codeset in %s -> %s conversion\n", opts[0], opts[1]); +	} +	if (opts[3]) {				/* -c */ +		((_UC_iconv_t *) ic)->skip_invalid_input = 1; +	} + +	if ((s = opts[2]) != NULL) { +		if (!(ofile = fopen(s, "w"))) { +			error_msg( "couldn't open %s for writing\n", s); +		} +	} + +	pos = ni = 0; +	do { +		if (!argc || ((**argv == '-') && !((*argv)[1]))) { +			ifile = stdin;		/* we don't check for duplicates */ +		} else if (!(ifile = fopen(*argv, "r"))) { +			error_msg( "couldn't open %s for reading\n", *argv); +		} + +		while ((r = fread(ibuf + ni, 1, IBUF - ni, ifile)) > 0) { +			pos += r; +			ni += r; +			no = OBUF; +			pi = ibuf; +			po = obuf; +			if ((r = iconv(ic, &pi, &ni, &po, &no)) == ((size_t)(-1))) { +				if ((errno != EINVAL) && (errno != E2BIG)) { +					error_msg( "iconv failed at pos %lu : %m\n", (unsigned long) (pos - ni)); +				} +			} +			if ((r = OBUF - no) > 0) { +				if (fwrite(obuf, 1, OBUF - no, ofile) < r) { +					error_msg( "write error\n"); +				} +			} +			if (ni) {			/* still bytes in buffer! */ +				memmove(ibuf, pi, ni); +			} +		} + +		if (ferror(ifile)) { +			error_msg( "read error\n"); +		} + +		++argv; + +		if (ifile != stdin) { +			fclose(ifile); +		} + +	} while (--argc > 0); + +	iconv_close(ic); + +	if (ni) { +		error_msg( "incomplete sequence\n"); +	} + +	return (((_UC_iconv_t *) ic)->skip_invalid_input < 2) +		? EXIT_SUCCESS : EXIT_FAILURE; +} + +#endif +/**********************************************************************/ diff --git a/libc/misc/wchar/wstdio.c b/libc/misc/wchar/wstdio.c index a4984f3c1..dfeb35c30 100644 --- a/libc/misc/wchar/wstdio.c +++ b/libc/misc/wchar/wstdio.c @@ -26,6 +26,13 @@   *   *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! */ +/* Nov 21, 2002 + * + * Reimplement fputwc and fputws in terms of internal function _wstdio_fwrite. + */ + + +  /*   * ANSI/ISO C99 says @@ -288,6 +295,9 @@ UNLOCKED(wchar_t *,fgetws,(wchar_t *__restrict ws, int n,  UNLOCKED(wint_t,fputwc,(wchar_t wc, FILE *stream),(wc, stream))  { +#if 1 +	return _wstdio_fwrite(&wc, 1, stream) ? wc : WEOF; +#else  	size_t n;  	char buf[MB_LEN_MAX]; @@ -298,9 +308,10 @@ UNLOCKED(wint_t,fputwc,(wchar_t wc, FILE *stream),(wc, stream))  	}  	stream->modeflags |= __FLAG_WIDE; -	return (((n = wcrtomb(buf, wc, &stream->state)) != ((size_t)-1)) /* EILSEQ */ -			&& (_stdio_fwrite(buf, n, stream) != n))/* Didn't write everything. */ +	return (((n = wcrtomb(buf, wc, &stream->state)) != ((size_t)-1)) /* !EILSEQ */ +			&& (_stdio_fwrite(buf, n, stream) == n))/* and wrote everything. */  		? wc : WEOF; +#endif  }  strong_alias(fputwc_unlocked,putwc_unlocked); @@ -324,6 +335,11 @@ UNLOCKED_STREAM(wint_t,putwchar,(wchar_t wc),(wc),stdout)  UNLOCKED(int,fputws,(const wchar_t *__restrict ws,  					 register FILE *__restrict stream),(ws, stream))  { +#if 1 +	size_t n = wcslen(ws); + +	return (_wstdio_fwrite(ws, n, stream) == n) ? 0 : -1; +#else  	size_t n;  	char buf[64]; @@ -347,6 +363,7 @@ UNLOCKED(int,fputws,(const wchar_t *__restrict ws,  	}  	return 1; +#endif  }  #endif diff --git a/libc/stdio/Makefile b/libc/stdio/Makefile index 09cb0710a..9f8af9e4c 100644 --- a/libc/stdio/Makefile +++ b/libc/stdio/Makefile @@ -51,13 +51,19 @@ MSRC2= printf.c  MOBJ2=  vsnprintf.o vdprintf.o vasprintf.o vprintf.o vsprintf.o \  	fprintf.o  snprintf.o  dprintf.o  asprintf.o  printf.o  sprintf.o +ifeq ($(UCLIBC_HAS_WCHAR),y) +	MOBJ += _wstdio_fwrite.o +	MOBJ2 += fwprintf.o wprintf.o swprintf.o vwprintf.o vswprintf.o \ +		vfwprintf.o +endif +  ifneq ($(USE_OLD_VFPRINTF),y)  	MOBJ2 += _ppfs_init.o _ppfs_prepargs.o _ppfs_setargs.o \ -		 _ppfs_parsespec.o _do_one_spec.o vfprintf.o \ +		 _ppfs_parsespec.o vfprintf.o \  		 _store_inttype.o _load_inttype.o \  		 register_printf_function.o parse_printf_format.o  endif - +# _do_one_spec.o   ifeq ($(UCLIBC_HAS_FLOATS),y) diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index ddf282e7e..054d2ca6d 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -59,6 +59,10 @@   * Add printf wchar support for %lc (%C) and %ls (%S).   * Require printf format strings to be valid multibyte strings beginning and   *   ending in their initial shift state, as per the stds. + * + * Nov 21, 2002 + * Add *wprintf functions.  Currently they don't support floating point + *   conversions.  That will wait until the rewrite of _dtostr.   */  /* TODO: @@ -177,7 +181,8 @@ enum {  	FLAG_MINUS		=	0x08,	/* must be 2 * FLAG_ZERO */  	FLAG_HASH		=	0x10,  	FLAG_THOUSANDS	=	0x20, -	FLAG_I18N		=	0x40	/* only works for d, i, u */ +	FLAG_I18N		=	0x40,	/* only works for d, i, u */ +	FLAG_WIDESTREAM =   0x80  };	    /**********************************************************************/ @@ -359,15 +364,14 @@ typedef struct {  extern size_t _dtostr(FILE * fp, long double x, struct printf_info *info);  #endif -#define _outnstr(stream, string, len)	_stdio_fwrite(string, len, stream)	/* TODO */ - -extern int _do_one_spec(FILE * __restrict stream, ppfs_t *ppfs, int *count); -  extern int _ppfs_init(ppfs_t *ppfs, const char *fmt0); /* validates */  extern void _ppfs_prepargs(ppfs_t *ppfs, va_list arg); /* sets posargptrs */  extern void _ppfs_setargs(ppfs_t *ppfs); /* sets argptrs for current spec */  extern int _ppfs_parsespec(ppfs_t *ppfs); /* parses specifier */ +extern void _store_inttype(void *dest, int desttype, uintmax_t val); +extern uintmax_t _load_inttype(int desttype, const void *src, int uflag); +  /**********************************************************************/  #ifdef L_parse_printf_format @@ -435,72 +439,6 @@ size_t parse_printf_format(register const char *template,  #endif  /**********************************************************************/ -#ifdef L_vfprintf - -/* We only support ascii digits (or their USC equivalent codes) in - * precision and width settings in *printf (wide) format strings. - * In other words, we don't currently support glibc's 'I' flag. - * We do accept it, but it is currently ignored. */ - -int vfprintf(FILE * __restrict stream, register const char * __restrict format, -			 va_list arg) -{ -	ppfs_t ppfs; -	int count, r; -	register const char *s; - -	__STDIO_THREADLOCK(stream); - -	count = 0; -	s = format; - -	if (_ppfs_init(&ppfs, format) < 0) { /* Bad format string. */ -		_outnstr(stream, ppfs.fmtpos, strlen(ppfs.fmtpos)); -		count = -1; -	} else { -		_ppfs_prepargs(&ppfs, arg);	/* This did a va_copy!!! */ - -		do { -			while (*format && (*format != '%')) { -				++format; -			} - -			if (format-s) {		/* output any literal text in format string */ -				if ( (r = _outnstr(stream, s, format-s)) < 0) { -					count = -1; -					break; -				} -				count += r; -			} - -			if (!*format) {			/* we're done */ -				break; -			} -		 -			if (format[1] != '%') {	/* if we get here, *format == '%' */ -				/* TODO: _do_one_spec needs to know what the output funcs are!!! */ -				ppfs.fmtpos = ++format; -				/* TODO: check -- should only fail on stream error */ -				if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) { -					count = -1; -					break; -				} -				s = format = ppfs.fmtpos; -			} else {			/* %% means literal %, so start new string */ -				s = ++format; -				++format; -			} -		} while (1); - -		va_end(ppfs.arg);		/* Need to clean up after va_copy! */ -	} - -	__STDIO_THREADUNLOCK(stream); - -	return count; -} -#endif -/**********************************************************************/  #ifdef L__ppfs_init  int _ppfs_init(register ppfs_t *ppfs, const char *fmt0) @@ -514,9 +452,7 @@ int _ppfs_init(register ppfs_t *ppfs, const char *fmt0)  	memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */  	--ppfs->maxposarg;			/* set to -1 */  	ppfs->fmtpos = fmt0; -#if defined(__UCLIBC_HAS_WCHAR__) && defined(__UCLIBC_HAS_LOCALE__) -	/* Note: We don't need to check if we don't have wide chars or we only -	 * support the C locale. */ +#ifdef __UCLIBC_HAS_WCHAR__  	{  		mbstate_t mbstate;  		const char *p; @@ -527,7 +463,7 @@ int _ppfs_init(register ppfs_t *ppfs, const char *fmt0)  			return -1;  		}  	} -#endif /* defined(__UCLIBC_HAS_WCHAR__) && defined(__UCLIBC_HAS_LOCALE__) */ +#endif /* __UCLIBC_HAS_WCHAR__ */  	/* now set all argtypes to no-arg */  	{  #if 1 @@ -810,6 +746,7 @@ static char _bss_custom_printf_spec[MAX_USER_SPEC]; /* 0-init'd for us.  */  char *_custom_printf_spec = _bss_custom_printf_spec;  printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC]; +printf_function _custom_printf_handler[MAX_USER_SPEC];  extern int _ppfs_parsespec(ppfs_t *ppfs)  { @@ -833,17 +770,44 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)  	static const short spec_or_mask[] = SPEC_OR_MASK;  	static const short spec_and_mask[] = SPEC_AND_MASK;  	static const char qual_chars[] = QUAL_CHARS; +#ifdef __UCLIBC_HAS_WCHAR__ +	char buf[32]; +#endif /* __UCLIBC_HAS_WCHAR__ */  	/* WIDE note: we can test against '%' here since we don't allow */  	/* WIDE note: other mappings of '%' in the wide char set. */  	preci = -1; -	width = flags = dpoint = 0;  	argnumber[0] = 0;  	argnumber[1] = 0;  	argtype[0] = __PA_NOARG;  	argtype[1] = __PA_NOARG;  	maxposarg = ppfs->maxposarg; +#ifdef __UCLIBC_HAS_WCHAR__ +	/* This is somewhat lame, but saves a lot of code.  If we're dealing with +	 * a wide stream, that means the format is a wchar string.  So, copy it +	 * char-by-char into a normal char buffer for processing.  Make the buffer +	 * (buf) big enough so that any reasonable format specifier will fit. +	 * While there a legal specifiers that won't, the all involve duplicate +	 * flags or outrageous field widths/precisions. */ +	width = dpoint = 0; +	if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) { +		fmt = ppfs->fmtpos; +	} else { +		fmt = buf + 1; +		i = 0; +		do { +			if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1])) +				!= (((wchar_t *) ppfs->fmtpos)[i-1]) +				) { +				return -1; +			} +		} while (buf[i++]); +		buf[sizeof(buf)-1] = 0; +	} +#else  /* __UCLIBC_HAS_WCHAR__ */ +	width = flags = dpoint = 0;  	fmt = ppfs->fmtpos; +#endif /* __UCLIBC_HAS_WCHAR__ */  	assert(fmt[-1] == '%');  	assert(fmt[0] != '%'); @@ -877,6 +841,16 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)  			/* Now fall through to check flags. */  		} else {  			if (maxposarg > 0) { +#ifdef __STDIO_PRINTF_M_SUPPORT +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: Support prec and width for %m when positional args used +				/* Actually, positional arg processing will fail in general +				 * for specifiers that don't require an arg. */ +#endif +				if (*fmt == 'm') { +					goto PREC_WIDTH; +				} +#endif /* __STDIO_PRINTF_M_SUPPORT */  				return -1;  			}  			maxposarg = 0;		/* Possible redundant store, but cuts size. */ @@ -1045,9 +1019,19 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)  	}  	ppfs->maxposarg = maxposarg; -	ppfs->fmtpos = ++fmt;  	ppfs->conv_num = conv_num; +#ifdef __UCLIBC_HAS_WCHAR__ +	if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) { +		ppfs->fmtpos = ++fmt; +	} else { +		ppfs->fmtpos = (const char *) (((const wchar_t *)(ppfs->fmtpos)) +									   + (fmt - buf) ); +	} +#else  /* __UCLIBC_HAS_WCHAR__ */ +	ppfs->fmtpos = ++fmt; +#endif /* __UCLIBC_HAS_WCHAR__ */ +   	return ppfs->num_data_args + 2;  } @@ -1094,306 +1078,6 @@ int register_printf_function(int spec, printf_function handler,  }  #endif  /**********************************************************************/ -#ifdef L__do_one_spec - -printf_function _custom_printf_handler[MAX_USER_SPEC]; - -extern void _store_inttype(void *dest, int desttype, uintmax_t val); -extern uintmax_t _load_inttype(int desttype, const void *src, int uflag); -extern void _charpad(FILE * __restrict stream, char padchar, size_t numpad); -extern void output(FILE * __restrict stream, const char *s); - -#define output(F,S)			fputs(S,F) - -#undef putc -void _charpad(FILE * __restrict stream, char padchar, size_t numpad) -{ -	/* TODO -- Use a buffer to cut down on function calls... */ -	char pad[1]; - -	*pad = padchar; -	while (numpad) { -		_stdio_fwrite(pad, 1, stream); -		--numpad; -	} -} - -/* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */ - -int _do_one_spec(FILE * __restrict stream, register ppfs_t *ppfs, int *count) -{ -	static const char spec_base[] = SPEC_BASE; -	static const char prefix[] = "+\0-\0 \0000x\0000X"; -	/*                            0  2  4  6   9 11*/ -	enum { -		PREFIX_PLUS = 0, -		PREFIX_MINUS = 2, -		PREFIX_SPACE = 4, -		PREFIX_LWR_X = 6, -		PREFIX_UPR_X = 9, -		PREFIX_NONE = 11 -	}; - -#ifdef __va_arg_ptr -	const void * const *argptr; -#else -	const void * argptr[MAX_ARGS_PER_SPEC]; -#endif -	int *argtype; -#ifdef __UCLIBC_HAS_WCHAR__ -	const wchar_t *ws = NULL; -	mbstate_t mbstate; -#endif /* __UCLIBC_HAS_WCHAR__ */ -	size_t slen; -	int base; -	int numpad; -	int alphacase; -	int numfill = 0;			/* TODO: fix */ -	int prefix_num = PREFIX_NONE; -	char padchar = ' '; -#ifdef __UCLIBC_MJN3_ONLY__ -#warning REMINDER: buf size -#endif -	/* TODO: buf needs to be big enough for any possible error return strings -	 * and also for any locale-grouped long long integer strings generated. -	 * This should be large enough for any of the current archs/locales, but -	 * eventually this should be handled robustly. */ -	char buf[128]; - -#ifdef NDEBUG -	_ppfs_parsespec(ppfs); -#else -	if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */ -		abort(); -	} -#endif -	_ppfs_setargs(ppfs); - -	argtype = ppfs->argtype + ppfs->argnumber[2] - 1; -	/* Deal with the argptr vs argvalue issue. */ -#ifdef __va_arg_ptr -	argptr = (const void * const *) ppfs->argptr; -	if (ppfs->maxposarg > 0) {	/* Using positional args... */ -		argptr += ppfs->argnumber[2] - 1; -	} -#else -	/* Need to build a local copy... */ -	{ -		register argvalue_t *p = ppfs->argvalue; -		int i; -		if (ppfs->maxposarg > 0) {	/* Using positional args... */ -			p += ppfs->argnumber[2] - 1; -		} -		for (i = 0 ; i < ppfs->num_data_args ; i++ ) { -			argptr[i] = (void *) p++; -		} -	} -#endif -	{ -		register char *s;		/* TODO: Should s be unsigned char * ? */ - -		if (ppfs->conv_num == CONV_n) { -			_store_inttype(*(void **)*argptr, -						   ppfs->info._flags & __PA_INTMASK, -						   (intmax_t) (*count)); -			return 0; -		} -		if (ppfs->conv_num <= CONV_i) {	/* pointer or (un)signed int */ -			alphacase = __UIM_LOWER; -			if (((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10) -				&& (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) -				) { -				alphacase = __UIM_GROUP; -			} -			if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */ -				if (ppfs->conv_num == CONV_X) { -					alphacase = __UIM_UPPER; -				} -				if (ppfs->conv_num == CONV_p) { /* pointer */ -					prefix_num = PREFIX_LWR_X; -				} else {		/* unsigned int */ -				} -			} else {			/* signed int */ -				base = -base; -			} -			if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */ -				padchar = ppfs->info.pad; -			} -			s = _uintmaxtostr(buf + sizeof(buf) - 1, -							  (uintmax_t) -							  _load_inttype(*argtype & __PA_INTMASK, -											*argptr, base), base, alphacase); -			if (ppfs->conv_num > CONV_u) { /* signed int */ -				if (*s == '-') { -					PRINT_INFO_SET_FLAG(&(ppfs->info),showsign); -					++s;		/* handle '-' in the prefix string */ -					prefix_num = PREFIX_MINUS; -				} else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) { -					prefix_num = PREFIX_PLUS; -				} else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) { -					prefix_num = PREFIX_SPACE; -				} -			} -			slen = (char *)(buf + sizeof(buf) - 1) - s; -			numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec); -			if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) { -				if (ppfs->conv_num <= CONV_x) {	/* x or p */ -					prefix_num = PREFIX_LWR_X; -				} -				if (ppfs->conv_num == CONV_X) { -					prefix_num = PREFIX_UPR_X; -				} -				if ((ppfs->conv_num == CONV_o) && (numfill <= slen)) { -					numfill = ((*s == '0') ? 1 : slen + 1); -				} -			} -			if (*s == '0') { -				if (prefix_num >= PREFIX_LWR_X) { -					prefix_num = PREFIX_NONE; -				} -				if (ppfs->conv_num == CONV_p) {/* null pointer */ -					s = "(nil)"; -					slen = 5; -					numfill = 0; -				} else if (numfill == 0) {	/* if precision 0, no output */ -					slen = 0; -				} -			} -			numfill = ((numfill > slen) ? numfill - slen : 0); -		} else if (ppfs->conv_num <= CONV_A) {	/* floating point */ -#ifdef __STDIO_PRINTF_FLOAT -			*count += _dtostr(stream, -							  (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double) -							   ? *(long double *) *argptr -							   : (long double) (* (double *) *argptr)), -							  &ppfs->info); -			return 0; -#else  /* __STDIO_PRINTF_FLOAT */ -			return -1;			/* TODO -- try to continue? */ -#endif /* __STDIO_PRINTF_FLOAT */ -		} else if (ppfs->conv_num <= CONV_S) {	/* wide char or string */ -#ifdef __UCLIBC_HAS_WCHAR__ -			mbstate.mask = 0;	/* Initialize the mbstate. */ -			if (ppfs->conv_num == CONV_S) { /* wide string */ -				if (!(ws = *((const wchar_t **) *argptr))) { -					goto NULL_STRING; -				} -				/* We use an awful uClibc-specific hack here, passing -				 * (char*) &ws as the conversion destination.  This signals -				 * uClibc's wcsrtombs that we want a "restricted" length -				 * such that the mbs fits in a buffer of the specified -				 * size with no partial conversions. */ -				if ((slen = wcsrtombs((char *) &ws, &ws, /* Use awful hack! */ -									  ((ppfs->info.prec >= 0) -									   ? ppfs->info.prec -									   : SIZE_MAX), &mbstate)) -					== ((size_t)-1) -					) { -					return -1;	/* EILSEQ */ -				} -			} else {			/* wide char */ -				s = buf; -				slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate); -				if (slen == ((size_t)-1)) { -					return -1;	/* EILSEQ */ -				} -				s[slen] = 0;	/* TODO - Is this necessary? */ -			} -#else  /* __UCLIBC_HAS_WCHAR__ */ -			return -1; -#endif /* __UCLIBC_HAS_WCHAR__ */ -		} else if (ppfs->conv_num <= CONV_s) {	/* char or string */ -			if (ppfs->conv_num == CONV_s) { /* string */ -				s = *((char **) (*argptr)); -				if (s) { -				SET_STRING_LEN: -					slen = strnlen(s, ((ppfs->info.prec >= 0) -									   ? ppfs->info.prec : SIZE_MAX)); -				} else { -				NULL_STRING: -					s = "(null)"; -					slen = 6; -				} -			} else {			/* char */ -				s = buf; -				*s = (unsigned char)(*((const int *) *argptr)); -				s[1] = 0; -				slen = 1; -			} -#ifdef __STDIO_PRINTF_M_SUPPORT -		} else if (ppfs->conv_num == CONV_m) { -			s = _glibc_strerror_r(errno, buf, sizeof(buf)); -			goto SET_STRING_LEN; -#endif -		} else { -			assert(ppfs->conv_num == CONV_custom0); - -			s = _custom_printf_spec; -			do { -				if (*s == ppfs->info.spec) { -					int rv; -					/* TODO -- check return value for sanity? */ -					rv = (*_custom_printf_handler -						  [(int)(s-_custom_printf_spec)]) -						(stream, &ppfs->info, argptr); -					if (rv < 0) { -						return -1; -					} -					*count += rv; -					return 0; -				} -			} while (++s < (_custom_printf_spec + MAX_USER_SPEC)); -			assert(0); -			return -1; -		} - -		{ -			size_t t; - -			t = slen + numfill; -			if (prefix_num != PREFIX_NONE) { -				t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2); -			} -			numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0); -			*count += t + numpad; -		} -		if (padchar == '0') { /* TODO: check this */ -			numfill += numpad; -			numpad = 0; -		} - -		/* Now handle the output itself. */ -		if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) { -			_charpad(stream, ' ', numpad); -			numpad = 0; -		} -		output(stream, prefix + prefix_num); -		_charpad(stream, '0', numfill); -#ifdef __UCLIBC_HAS_WCHAR__ -		if (!ws) { -			_outnstr(stream, s, slen); -		} else {				/* wide string */ -			size_t t; -			mbstate.mask = 0;	/* Initialize the mbstate. */ -			while (slen) { -				t = (slen <= sizeof(buf)) ? slen : sizeof(buf); -				t = wcsrtombs(buf, &ws, t, &mbstate); -				assert (t != ((size_t)(-1))); -				_outnstr(stream, buf, t); -				slen -= t; -			} -			ws = NULL;			/* Reset ws. */ -		} -#else  /* __UCLIBC_HAS_WCHAR__ */ -		_outnstr(stream, s, slen); -#endif /* __UCLIBC_HAS_WCHAR__ */ -		_charpad(stream, ' ', numpad); -	} - -	return 0; -} -#endif -/**********************************************************************/  #ifdef L_vsnprintf  #ifdef __STDIO_BUFFERS @@ -1751,6 +1435,124 @@ int sprintf(char *__restrict buf, const char * __restrict format, ...)  #endif  #endif  /**********************************************************************/ +#ifdef L_vswprintf + +#ifdef __STDIO_BUFFERS +int vswprintf(wchar_t *__restrict buf, size_t size, +			  const wchar_t * __restrict format, va_list arg) +{ +	FILE f; +	int rv; + +#ifdef __STDIO_GETC_MACRO +	f.bufgetc = +#endif +	f.bufpos = f.bufread = f.bufstart = (char *) buf; + +/* 	if (size > SIZE_MAX - (size_t) buf) { */ +/* 		size = SIZE_MAX - (size_t) buf; */ +/* 	} */ +#ifdef __STDIO_PUTC_MACRO +	f.bufputc = +#endif +	f.bufend = (char *)(buf + size); + +#if 0							/* shouldn't be necessary */ +/*  #ifdef __STDIO_GLIBC_CUSTOM_STREAMS */ +	f.cookie = &(f.filedes); +	f.gcs.read = 0; +	f.gcs.write = 0; +	f.gcs.seek = 0; +	f.gcs.close = 0; +#endif +	f.filedes = -3;				/* for debugging */ +	f.modeflags = (__FLAG_WIDE|__FLAG_WRITEONLY|__FLAG_WRITING); + +#ifdef __STDIO_MBSTATE +	__INIT_MBSTATE(&(f.state)); +#endif /* __STDIO_MBSTATE */ + +#ifdef __STDIO_THREADSAFE +	f.user_locking = 0; +	__stdio_init_mutex(&f.lock); +#endif + +	rv = vfwprintf(&f, format, arg); + +	/* NOTE: Return behaviour differs from snprintf... */ +	if (f.bufpos == f.bufend) { +		rv = -1; +		if (size) { +			f.bufpos = (char *)(((wchar_t *) f.bufpos) - 1); +		} +	} +	if (size) { +		*((wchar_t *) f.bufpos) = 0; +	} +	return rv; +} +#else  /* __STDIO_BUFFERS */ +#warning skipping vswprintf since no buffering! +#endif /* __STDIO_BUFFERS */ +#endif +/**********************************************************************/ +#ifdef L_swprintf +#ifdef __STDIO_BUFFERS + +int swprintf(wchar_t *__restrict buf, size_t size, +			 const wchar_t * __restrict format, ...) +{ +	va_list arg; +	int rv; + +	va_start(arg, format); +	rv = vswprintf(buf, size, format, arg); +	va_end(arg); +	return rv; +} + +#else  /* __STDIO_BUFFERS */ +#warning skipping vsWprintf since no buffering! +#endif /* __STDIO_BUFFERS */ +#endif +/**********************************************************************/ +#ifdef L_fwprintf + +int fwprintf(FILE * __restrict stream, const wchar_t * __restrict format, ...) +{ +	va_list arg; +	int rv; + +	va_start(arg, format); +	rv = vfwprintf(stream, format, arg); +	va_end(arg); + +	return rv; +} + +#endif +/**********************************************************************/ +#ifdef L_vwprintf +int vwprintf(const wchar_t * __restrict format, va_list arg) +{ +	return vfwprintf(stdout, format, arg); +} +#endif +/**********************************************************************/ +#ifdef L_wprintf +int wprintf(const wchar_t * __restrict format, ...) +{ +	va_list arg; +	int rv; + +	va_start(arg, format); +	rv = vfwprintf(stdout, format, arg); +	va_end(arg); + +	return rv; +} +#endif +/**********************************************************************/  #ifdef L__dtostr  /*   * Copyright (C) 2000, 2001 Manuel Novoa III @@ -2298,3 +2100,581 @@ extern uintmax_t _load_inttype(int desttype, register const void *src,  #endif  /**********************************************************************/ +#if defined(L_vfprintf) || defined(L_vfwprintf) + +/* We only support ascii digits (or their USC equivalent codes) in + * precision and width settings in *printf (wide) format strings. + * In other words, we don't currently support glibc's 'I' flag. + * We do accept it, but it is currently ignored. */ + + +#ifdef L_vfprintf + +#define VFPRINTF vfprintf +#define FMT_TYPE char +#define OUTNSTR _outnstr +#define STRLEN  strlen +#define _PPFS_init _ppfs_init +#define OUTPUT(F,S)			fputs(S,F) +#define _outnstr(stream, string, len)	_stdio_fwrite(string, len, stream) + +#else  /* L_vfprintf */ + +#define VFPRINTF vfwprintf +#define FMT_TYPE wchar_t +#define OUTNSTR _outnwcs +#define STRLEN  wcslen +#define _PPFS_init _ppwfs_init +#define OUTPUT(F,S)			fputws(S,F) +#define _outnwcs(stream, wstring, len)	_wstdio_fwrite(wstring, len, stream) + +static void _outnstr(FILE *stream, const char *s, size_t wclen) +{ +	/* NOTE!!! len here is the number of wchars we want to generate!!! */ +	wchar_t wbuf[64]; +	mbstate_t mbstate; +	size_t todo, r; + +	mbstate.mask = 0; +	todo = wclen; +	 +	while (todo) { +		r = mbsrtowcs(wbuf, &s, sizeof(wbuf)/sizeof(wbuf[0]), &mbstate); +		assert(((ssize_t)r) > 0); +		_outnwcs(stream, wbuf, r); +		todo -= r; +	} +} + +static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0) +{ +	static const wchar_t invalid_wcs[] = L"Invalid wide format string."; +	int r; + +	/* First, zero out everything... argnumber[], argtype[], argptr[] */ +	memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */ +	--ppfs->maxposarg;			/* set to -1 */ +	ppfs->fmtpos = (const char *) fmt0; +	ppfs->info._flags = FLAG_WIDESTREAM; + +	{ +		mbstate_t mbstate; +		const wchar_t *p; +		mbstate.mask = 0;	/* Initialize the mbstate. */ +		p = fmt0; +		if (wcsrtombs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) { +			ppfs->fmtpos = (const char *) invalid_wcs; +			return -1; +		} +	} + +	/* now set all argtypes to no-arg */ +	{ +#if 1 +		/* TODO - use memset here since already "paid for"? */ +		register int *p = ppfs->argtype; +		 +		r = MAX_ARGS; +		do { +			*p++ = __PA_NOARG; +		} while (--r); +#else +		/* TODO -- get rid of this?? */ +		register char *p = (char *) ((MAX_ARGS-1) * sizeof(int)); + +		do { +			*((int *)(((char *)ppfs) + ((int)p) + offsetof(ppfs_t,argtype))) = __PA_NOARG; +			p -= sizeof(int); +		} while (p); +#endif +	} + +	/* +	 * Run through the entire format string to validate it and initialize +	 * the positional arg numbers (if any). +	 */ +	{ +		register const wchar_t *fmt = fmt0; + +		while (*fmt) { +			if ((*fmt == '%') && (*++fmt != '%')) { +				ppfs->fmtpos = (const char *) fmt; /* back up to the '%' */ +				if ((r = _ppfs_parsespec(ppfs)) < 0) { +					return -1; +				} +				fmt = (const wchar_t *) ppfs->fmtpos; /* update to one past end of spec */ +			} else { +				++fmt; +			} +		} +		ppfs->fmtpos = (const char *) fmt0; /* rewind */ +	} + +	/* If we have positional args, make sure we know all the types. */ +	{ +		register int *p = ppfs->argtype; +		r = ppfs->maxposarg; +		while (--r >= 0) { +			if ( *p == __PA_NOARG ) { /* missing arg type!!! */ +				return -1; +			} +			++p; +		} +	} + +	return 0; +} + +#endif /* L_vfprintf */ + +static void _charpad(FILE * __restrict stream, int padchar, size_t numpad) +{ +	/* TODO -- Use a buffer to cut down on function calls... */ +	FMT_TYPE pad[1]; + +	*pad = padchar; +	while (numpad) { +		OUTNSTR(stream, pad, 1); +		--numpad; +	} +} + +/* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */ +static int _do_one_spec(FILE * __restrict stream, +						 register ppfs_t *ppfs, int *count) +{ +	static const char spec_base[] = SPEC_BASE; +#ifdef L_vfprintf +	static const char prefix[] = "+\0-\0 \0000x\0000X"; +	/*                            0  2  4  6   9 11*/ +#else  /* L_vfprintf */ +	static const wchar_t prefix[] = L"+\0-\0 \0000x\0000X"; +#endif /* L_vfprintf */ +	enum { +		PREFIX_PLUS = 0, +		PREFIX_MINUS = 2, +		PREFIX_SPACE = 4, +		PREFIX_LWR_X = 6, +		PREFIX_UPR_X = 9, +		PREFIX_NONE = 11 +	}; + +#ifdef __va_arg_ptr +	const void * const *argptr; +#else +	const void * argptr[MAX_ARGS_PER_SPEC]; +#endif +	int *argtype; +#ifdef __UCLIBC_HAS_WCHAR__ +	const wchar_t *ws = NULL; +	mbstate_t mbstate; +#endif /* __UCLIBC_HAS_WCHAR__ */ +	size_t slen; +#ifdef L_vfprintf +#define SLEN slen +#else +	size_t SLEN; +	wchar_t wbuf[2]; +#endif +	int base; +	int numpad; +	int alphacase; +	int numfill = 0;			/* TODO: fix */ +	int prefix_num = PREFIX_NONE; +	char padchar = ' '; +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: buf size +#endif +	/* TODO: buf needs to be big enough for any possible error return strings +	 * and also for any locale-grouped long long integer strings generated. +	 * This should be large enough for any of the current archs/locales, but +	 * eventually this should be handled robustly. */ +	char buf[128]; + +#ifdef NDEBUG +	_ppfs_parsespec(ppfs); +#else +	if (_ppfs_parsespec(ppfs) < 0) { /* TODO: just for debugging */ +		abort(); +	} +#endif +	_ppfs_setargs(ppfs); + +	argtype = ppfs->argtype + ppfs->argnumber[2] - 1; +	/* Deal with the argptr vs argvalue issue. */ +#ifdef __va_arg_ptr +	argptr = (const void * const *) ppfs->argptr; +	if (ppfs->maxposarg > 0) {	/* Using positional args... */ +		argptr += ppfs->argnumber[2] - 1; +	} +#else +	/* Need to build a local copy... */ +	{ +		register argvalue_t *p = ppfs->argvalue; +		int i; +		if (ppfs->maxposarg > 0) {	/* Using positional args... */ +			p += ppfs->argnumber[2] - 1; +		} +		for (i = 0 ; i < ppfs->num_data_args ; i++ ) { +			argptr[i] = (void *) p++; +		} +	} +#endif +	{ +		register char *s;		/* TODO: Should s be unsigned char * ? */ + +		if (ppfs->conv_num == CONV_n) { +			_store_inttype(*(void **)*argptr, +						   ppfs->info._flags & __PA_INTMASK, +						   (intmax_t) (*count)); +			return 0; +		} +		if (ppfs->conv_num <= CONV_i) {	/* pointer or (un)signed int */ +			alphacase = __UIM_LOWER; +			if (((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10) +				&& (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) +				) { +				alphacase = __UIM_GROUP; +			} +			if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */ +				if (ppfs->conv_num == CONV_X) { +					alphacase = __UIM_UPPER; +				} +				if (ppfs->conv_num == CONV_p) { /* pointer */ +					prefix_num = PREFIX_LWR_X; +				} else {		/* unsigned int */ +				} +			} else {			/* signed int */ +				base = -base; +			} +			if (ppfs->info.prec < 0) { /* Ignore '0' flag if prec specified. */ +				padchar = ppfs->info.pad; +			} +			s = _uintmaxtostr(buf + sizeof(buf) - 1, +							  (uintmax_t) +							  _load_inttype(*argtype & __PA_INTMASK, +											*argptr, base), base, alphacase); +			if (ppfs->conv_num > CONV_u) { /* signed int */ +				if (*s == '-') { +					PRINT_INFO_SET_FLAG(&(ppfs->info),showsign); +					++s;		/* handle '-' in the prefix string */ +					prefix_num = PREFIX_MINUS; +				} else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),showsign)) { +					prefix_num = PREFIX_PLUS; +				} else if (PRINT_INFO_FLAG_VAL(&(ppfs->info),space)) { +					prefix_num = PREFIX_SPACE; +				} +			} +			slen = (char *)(buf + sizeof(buf) - 1) - s; +#ifdef L_vfwprintf +			{ +				const char *q = s; +				mbstate.mask = 0; /* Initialize the mbstate. */ +				SLEN = mbsrtowcs(NULL, &q, 0, &mbstate); +			} +#endif +			numfill = ((ppfs->info.prec < 0) ? 1 : ppfs->info.prec); +			if (PRINT_INFO_FLAG_VAL(&(ppfs->info),alt)) { +				if (ppfs->conv_num <= CONV_x) {	/* x or p */ +					prefix_num = PREFIX_LWR_X; +				} +				if (ppfs->conv_num == CONV_X) { +					prefix_num = PREFIX_UPR_X; +				} +				if ((ppfs->conv_num == CONV_o) && (numfill <= SLEN)) { +					numfill = ((*s == '0') ? 1 : SLEN + 1); +				} +			} +			if (*s == '0') { +				if (prefix_num >= PREFIX_LWR_X) { +					prefix_num = PREFIX_NONE; +				} +				if (ppfs->conv_num == CONV_p) {/* null pointer */ +					s = "(nil)"; +#ifdef L_vfwprintf +					SLEN = +#endif +					slen = 5; +					numfill = 0; +				} else if (numfill == 0) {	/* if precision 0, no output */ +#ifdef L_vfwprintf +					SLEN = +#endif +					slen = 0; +				} +			} +			numfill = ((numfill > SLEN) ? numfill - SLEN : 0); +		} else if (ppfs->conv_num <= CONV_A) {	/* floating point */ +#ifdef L_vfwprintf +#ifdef __UCLIBC_MJN3_ONLY__ +#warning fix dtostr +#endif +			return -1; +#else  /* L_vfwprintf */ +#ifdef __STDIO_PRINTF_FLOAT +			*count += _dtostr(stream, +							  (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double) +							   ? *(long double *) *argptr +							   : (long double) (* (double *) *argptr)), +							  &ppfs->info); +			return 0; +#else  /* __STDIO_PRINTF_FLOAT */ +			return -1;			/* TODO -- try to continue? */ +#endif /* __STDIO_PRINTF_FLOAT */ +#endif /* L_vfwprintf */ +		} else if (ppfs->conv_num <= CONV_S) {	/* wide char or string */ +#ifdef L_vfprintf + +#ifdef __UCLIBC_HAS_WCHAR__ +			mbstate.mask = 0;	/* Initialize the mbstate. */ +			if (ppfs->conv_num == CONV_S) { /* wide string */ +				if (!(ws = *((const wchar_t **) *argptr))) { +					goto NULL_STRING; +				} +				/* We use an awful uClibc-specific hack here, passing +				 * (char*) &ws as the conversion destination.  This signals +				 * uClibc's wcsrtombs that we want a "restricted" length +				 * such that the mbs fits in a buffer of the specified +				 * size with no partial conversions. */ +				if ((slen = wcsrtombs((char *) &ws, &ws, /* Use awful hack! */ +									  ((ppfs->info.prec >= 0) +									   ? ppfs->info.prec +									   : SIZE_MAX), &mbstate)) +					== ((size_t)-1) +					) { +					return -1;	/* EILSEQ */ +				} +			} else {			/* wide char */ +				s = buf; +				slen = wcrtomb(s, (*((const wchar_t *) *argptr)), &mbstate); +				if (slen == ((size_t)-1)) { +					return -1;	/* EILSEQ */ +				} +				s[slen] = 0;	/* TODO - Is this necessary? */ +			} +#else  /* __UCLIBC_HAS_WCHAR__ */ +			return -1; +#endif /* __UCLIBC_HAS_WCHAR__ */ +		} else if (ppfs->conv_num <= CONV_s) {	/* char or string */ +			if (ppfs->conv_num == CONV_s) { /* string */ +				s = *((char **) (*argptr)); +				if (s) { +				SET_STRING_LEN: +					slen = strnlen(s, ((ppfs->info.prec >= 0) +									   ? ppfs->info.prec : SIZE_MAX)); +				} else { +#ifdef __UCLIBC_HAS_WCHAR__ +				NULL_STRING: +#endif +					s = "(null)"; +					slen = 6; +				} +			} else {			/* char */ +				s = buf; +				*s = (unsigned char)(*((const int *) *argptr)); +				s[1] = 0; +				slen = 1; +			} + +#else  /* L_vfprintf */ + +			if (ppfs->conv_num == CONV_S) { /* wide string */ +				ws = *((wchar_t **) (*argptr)); +				if (!ws) { +					goto NULL_STRING; +				} +				SLEN = wcsnlen(ws, ((ppfs->info.prec >= 0) +									? ppfs->info.prec : SIZE_MAX)); +			} else {			/* wide char */ +				*wbuf = (wchar_t)(*((const wint_t *) *argptr)); +			CHAR_CASE: +				ws = wbuf; +				wbuf[1] = 0; +				SLEN = 1; +			} + +		} else if (ppfs->conv_num <= CONV_s) {	/* char or string */ + +			if (ppfs->conv_num == CONV_s) { /* string */ +#ifdef __UCLIBC_MJN3_ONLY__ +#warning Fix %s for vfwprintf... output upto illegal sequence? +#endif +				s = *((char **) (*argptr)); +				if (s) { +				SET_STRING_LEN: +					/* We use an awful uClibc-specific hack here, passing +					 * (wchar_t*) &mbstate as the conversion destination. +					 *  This signals uClibc's mbsrtowcs that we want a +					 * "restricted" length such that the mbs fits in a buffer +					 * of the specified size with no partial conversions. */ +					{ +						const char *q = s; +						mbstate.mask = 0;	/* Initialize the mbstate. */ +						SLEN = mbsrtowcs((wchar_t *) &mbstate, &q, +										 ((ppfs->info.prec >= 0) +										  ? ppfs->info.prec : SIZE_MAX), +										 &mbstate); +					} +					if (SLEN == ((size_t)(-1))) { +						return -1;	/* EILSEQ */ +					} +				} else { +				NULL_STRING: +					s = "(null)"; +					SLEN = slen = 6; +				} +			} else {			/* char */ +				*wbuf = btowc( (unsigned char)(*((const int *) *argptr)) ); +				goto CHAR_CASE; +			} + +#endif /* L_vfprintf */ + +#ifdef __STDIO_PRINTF_M_SUPPORT +		} else if (ppfs->conv_num == CONV_m) { +			s = _glibc_strerror_r(errno, buf, sizeof(buf)); +			goto SET_STRING_LEN; +#endif +		} else { +			assert(ppfs->conv_num == CONV_custom0); + +			s = _custom_printf_spec; +			do { +				if (*s == ppfs->info.spec) { +					int rv; +					/* TODO -- check return value for sanity? */ +					rv = (*_custom_printf_handler +						  [(int)(s-_custom_printf_spec)]) +						(stream, &ppfs->info, argptr); +					if (rv < 0) { +						return -1; +					} +					*count += rv; +					return 0; +				} +			} while (++s < (_custom_printf_spec + MAX_USER_SPEC)); +			assert(0); +			return -1; +		} + +		{ +			size_t t; + +			t = SLEN + numfill; +			if (prefix_num != PREFIX_NONE) { +				t += ((prefix_num < PREFIX_LWR_X) ? 1 : 2); +			} +			numpad = ((ppfs->info.width > t) ? (ppfs->info.width - t) : 0); +			*count += t + numpad; +		} +		if (padchar == '0') { /* TODO: check this */ +			numfill += numpad; +			numpad = 0; +		} + +		/* Now handle the output itself. */ +		if (!PRINT_INFO_FLAG_VAL(&(ppfs->info),left)) { +			_charpad(stream, ' ', numpad); +			numpad = 0; +		} +		OUTPUT(stream, prefix + prefix_num); +		_charpad(stream, '0', numfill); + +#ifdef L_vfprintf + +#ifdef __UCLIBC_HAS_WCHAR__ +		if (!ws) { +			_outnstr(stream, s, slen); +		} else {				/* wide string */ +			size_t t; +			mbstate.mask = 0;	/* Initialize the mbstate. */ +			while (slen) { +				t = (slen <= sizeof(buf)) ? slen : sizeof(buf); +				t = wcsrtombs(buf, &ws, t, &mbstate); +				assert (t != ((size_t)(-1))); +				_outnstr(stream, buf, t); +				slen -= t; +			} +			ws = NULL;			/* Reset ws. */ +		} +#else  /* __UCLIBC_HAS_WCHAR__ */ +		_outnstr(stream, s, slen); +#endif /* __UCLIBC_HAS_WCHAR__ */ + +#else  /* L_vfprintf */ + +		if (!ws) { +			_outnstr(stream, s, SLEN); +		} else { +			_outnwcs(stream, ws, SLEN); +			ws = NULL;			/* Reset ws. */ +		} + +#endif /* L_vfprintf */ +		_charpad(stream, ' ', numpad); +	} + +	return 0; +} + +int VFPRINTF (FILE * __restrict stream, +			  register const FMT_TYPE * __restrict format, +			  va_list arg) +{ +	ppfs_t ppfs; +	int count, r; +	register const FMT_TYPE *s; + +	__STDIO_THREADLOCK(stream); + +	count = 0; +	s = format; + +	if (_PPFS_init(&ppfs, format) < 0) { /* Bad format string. */ +		OUTNSTR(stream, (const FMT_TYPE *) ppfs.fmtpos, +				STRLEN((const FMT_TYPE *)(ppfs.fmtpos))); +		count = -1; +	} else { +		_ppfs_prepargs(&ppfs, arg);	/* This did a va_copy!!! */ + +		do { +			while (*format && (*format != '%')) { +				++format; +			} + +			if (format-s) {		/* output any literal text in format string */ +				if ( (r = OUTNSTR(stream, s, format-s)) < 0) { +					count = -1; +					break; +				} +				count += r; +			} + +			if (!*format) {			/* we're done */ +				break; +			} +		 +			if (format[1] != '%') {	/* if we get here, *format == '%' */ +				/* TODO: _do_one_spec needs to know what the output funcs are!!! */ +				ppfs.fmtpos = (const char *)(++format); +				/* TODO: check -- should only fail on stream error */ +				if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) { +					count = -1; +					break; +				} +				s = format = (const FMT_TYPE *) ppfs.fmtpos; +			} else {			/* %% means literal %, so start new string */ +				s = ++format; +				++format; +			} +		} while (1); + +		va_end(ppfs.arg);		/* Need to clean up after va_copy! */ +	} + +	__STDIO_THREADUNLOCK(stream); + +	return count; +} +#endif +/**********************************************************************/ diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c index 8b9b3167c..cf72a5ccc 100644 --- a/libc/stdio/stdio.c +++ b/libc/stdio/stdio.c @@ -45,6 +45,9 @@   *     function pointers are set to that it is a "normal" file with a   *     file descriptor of -1.  Note: The cookie pointer is reset to NULL   *     if the FILE struct is free'd by fclose. + * + *  Nov 21, 2002 + *  Added internal function _wstdio_fwrite.   */  /* Before we include anything, convert L_ctermid to L_ctermid_function @@ -3449,3 +3452,58 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,  #endif  /**********************************************************************/ +#ifdef L__wstdio_fwrite + +#include <wchar.h> + +size_t _wstdio_fwrite(const wchar_t *__restrict ws, size_t n, +					  register FILE *__restrict stream) +{ +	size_t r, count; +	char buf[64]; +	const wchar_t *pw; + +#ifdef __STDIO_BUFFERS +	if (stream->filedes == -3) { /* Special case to support {v}swprintf. */ +		count = ((wchar_t *)(stream->bufend)) - ((wchar_t *)(stream->bufpos)); +		if (count > n) { +			count = n; +		} +		if (count) { +			wmemcpy((wchar_t *)(stream->bufpos), ws, count); +			stream->bufpos = (char *)(((wchar_t *)(stream->bufpos)) + count); +		} +		return n; +	} +#endif + +	if (stream->modeflags & __FLAG_NARROW) { +		stream->modeflags |= __FLAG_ERROR; +		__set_errno(EBADF); +		return 0; +	} +	stream->modeflags |= __FLAG_WIDE; + +	pw = ws; +	count = 0; +	while (n > count) { +		r = wcsnrtombs(buf, &pw, n, sizeof(buf), &stream->state); +		if (r != ((size_t) -1)) { /* No encoding errors */ +			if (!r) { +				++r;		  /* 0 is returned when nul is reached. */ +				pw = ws + count + r; /* pw was set to NULL, so correct. */ +			} +			if (_stdio_fwrite(buf, r, stream) == r) { +				count = pw - ws; +				continue; +			} +		} +		break; +	} + +	/* Note: The count is incorrect if 0 < _stdio_fwrite return < r!!! */ +	return count; +} + +#endif +/**********************************************************************/ diff --git a/libc/stdlib/Makefile b/libc/stdlib/Makefile index fdbe615d3..e00929f39 100644 --- a/libc/stdlib/Makefile +++ b/libc/stdlib/Makefile @@ -35,18 +35,21 @@ endif  MSRC = stdlib.c  MOBJ = abs.o labs.o atoi.o atol.o strtol.o strtoul.o _stdlib_strto_l.o \ -       qsort.o bsearch.o -MOBJ +=  llabs.o atoll.o strtoll.o strtoull.o _stdlib_strto_ll.o +       qsort.o bsearch.o \ +       llabs.o atoll.o strtoll.o strtoull.o _stdlib_strto_ll.o +# (aliases) strtoq.o strtouq.o  ifeq ($(UCLIBC_HAS_FLOATS),y)  	MOBJ += atof.o  endif  ifeq ($(UCLIBC_HAS_WCHAR),y)  	MOBJ += mblen.o mbtowc.o wctomb.o mbstowcs.o wcstombs.o \ -		_stdlib_mb_cur_max.o  +		_stdlib_mb_cur_max.o _stdlib_wcsto_l.o _stdlib_wcsto_ll.o \ +		wcstol.o wcstoul.o wcstoll.o wcstoull.o +# (aliases) wcstoq.o wcstouq.o +# wcstod wcstof wcstold  endif -  MSRC2=atexit.c  MOBJ2=atexit.o on_exit.o __exit_handler.o exit.o  CSRC =	abort.c getenv.c mkdtemp.c mktemp.c realpath.c mkstemp.c mkstemp64.c \ diff --git a/libc/stdlib/stdlib.c b/libc/stdlib/stdlib.c index e9e6e1c32..122289c2c 100644 --- a/libc/stdlib/stdlib.c +++ b/libc/stdlib/stdlib.c @@ -26,8 +26,10 @@   *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! */  /* Oct 29, 2002 - *   * Fix a couple of 'restrict' bugs in mbstowcs and wcstombs. + * + * Nov 21, 2002 + * Add wscto{inttype} functions.   */  #define _ISOC99_SOURCE			/* for ULLONG primarily... */ @@ -52,10 +54,46 @@  #define atoll __ignore_atoll  #define strtoll __ignore_strtoll  #define strtoull __ignore_strtoull +#define wcstoll __ignore_wcstoll +#define wcstoull __ignore_wcstoull  #endif  #include <stdlib.h> +#ifdef __UCLIBC_HAS_WCHAR__ + +#include <locale.h> +#include <wchar.h> +#include <wctype.h> + +/* TODO: clean up the following... */ + +#if WCHAR_MAX > 0xffffUL +#define UTF_8_MAX_LEN 6 +#else +#define UTF_8_MAX_LEN 3 +#endif + +#ifdef __UCLIBC_HAS_LOCALE__ +#define ENCODING (__global_locale.encoding) +#ifndef __CTYPE_HAS_UTF_8_LOCALES +#warning __CTYPE_HAS_UTF_8_LOCALES not set! +#endif +#else +#ifdef __UCLIBC_MJN3_ONLY__ +#warning devel checks +#endif +#define ENCODING (__ctype_encoding_7_bit) +#ifdef __CTYPE_HAS_8_BIT_LOCALES +#error __CTYPE_HAS_8_BIT_LOCALES is defined! +#endif +#ifdef __CTYPE_HAS_UTF_8_LOCALES +#error __CTYPE_HAS_UTF_8_LOCALES is defined! +#endif +#endif + +#endif +  #if UINT_MAX == ULONG_MAX  #undef atoi  #undef abs @@ -65,7 +103,11 @@  #undef atoll  #undef strtoll  #undef strtoull -#endif +#undef wcstoll +#undef wcstoull +#endif /* __UCLIBC_HAS_WCHAR__ */ + +/**********************************************************************/  extern unsigned long  _stdlib_strto_l(register const char * __restrict str, @@ -77,6 +119,18 @@ _stdlib_strto_ll(register const char * __restrict str,  				 char ** __restrict endptr, int base, int sflag);  #endif +#ifdef __UCLIBC_HAS_WCHAR__ +extern unsigned long +_stdlib_wcsto_l(register const wchar_t * __restrict str, +				wchar_t ** __restrict endptr, int base, int sflag); + +#if defined(ULLONG_MAX) +extern unsigned long long +_stdlib_wcsto_ll(register const wchar_t * __restrict str, +				 wchar_t ** __restrict endptr, int base, int sflag); +#endif +#endif /* __UCLIBC_HAS_WCHAR__ */ +  /**********************************************************************/  #ifdef L_atof @@ -205,6 +259,7 @@ long strtol(const char * __restrict str, char ** __restrict endptr, int base)  #if (ULLONG_MAX == UINTMAX_MAX)  strong_alias(strtoll,strtoimax)  #endif +strong_alias(strtoll,strtoq)  long long strtoll(const char * __restrict str,  				  char ** __restrict endptr, int base) @@ -241,6 +296,7 @@ unsigned long strtoul(const char * __restrict str,  #if (ULLONG_MAX == UINTMAX_MAX)  strong_alias(strtoull,strtoumax)  #endif +strong_alias(strtoull,strtouq)  unsigned long long strtoull(const char * __restrict str,  							char ** __restrict endptr, int base) @@ -271,28 +327,41 @@ unsigned long long strtoull(const char * __restrict str,  #endif  /**********************************************************************/ +#ifdef L__stdlib_wcsto_l +#define L__stdlib_strto_l +#endif +  #ifdef L__stdlib_strto_l +#ifdef L__stdlib_wcsto_l +#define _stdlib_strto_l _stdlib_wcsto_l +#define Wchar wchar_t +#define ISSPACE iswspace +#else +#define Wchar char +#define ISSPACE isspace +#endif +  /* This is the main work fuction which handles both strtol (sflag = 1) and   * strtoul (sflag = 0). */ -unsigned long _stdlib_strto_l(register const char * __restrict str, -							  char ** __restrict endptr, int base, int sflag) +unsigned long _stdlib_strto_l(register const Wchar * __restrict str, +							  Wchar ** __restrict endptr, int base, int sflag)  {      unsigned long number, cutoff;  #if _STRTO_ENDPTR -    const char *fail_char; +    const Wchar *fail_char;  #define SET_FAIL(X)       fail_char = (X)  #else  #define SET_FAIL(X)       ((void)(X)) /* Keep side effects. */  #endif      unsigned char negative, digit, cutoff_digit; -	assert((sflag == 0) || (sflag == 1)); +	assert(((unsigned int)sflag) <= 1);  	SET_FAIL(str); -    while (isspace(*str)) {		/* Skip leading whitespace. */ +    while (ISSPACE(*str)) {		/* Skip leading whitespace. */  		++str;      } @@ -350,7 +419,7 @@ unsigned long _stdlib_strto_l(register const char * __restrict str,  #if _STRTO_ENDPTR      if (endptr) { -		*endptr = (char *) fail_char; +		*endptr = (Wchar *) fail_char;      }  #endif @@ -369,20 +438,33 @@ unsigned long _stdlib_strto_l(register const char * __restrict str,  #endif  /**********************************************************************/ +#ifdef L__stdlib_wcsto_ll +#define L__stdlib_strto_ll +#endif +  #ifdef L__stdlib_strto_ll  #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) +#ifdef L__stdlib_wcsto_ll +#define _stdlib_strto_ll _stdlib_wcsto_ll +#define Wchar wchar_t +#define ISSPACE iswspace +#else +#define Wchar char +#define ISSPACE isspace +#endif +  /* This is the main work fuction which handles both strtoll (sflag = 1) and   * strtoull (sflag = 0). */ -unsigned long long _stdlib_strto_ll(register const char * __restrict str, -									char ** __restrict endptr, int base, +unsigned long long _stdlib_strto_ll(register const Wchar * __restrict str, +									Wchar ** __restrict endptr, int base,  									int sflag)  {      unsigned long long number;  #if _STRTO_ENDPTR -    const char *fail_char; +    const Wchar *fail_char;  #define SET_FAIL(X)       fail_char = (X)  #else  #define SET_FAIL(X)       ((void)(X)) /* Keep side effects. */ @@ -390,11 +472,11 @@ unsigned long long _stdlib_strto_ll(register const char * __restrict str,  	unsigned int n1;      unsigned char negative, digit; -	assert((sflag == 0) || (sflag == 1)); +	assert(((unsigned int)sflag) <= 1);  	SET_FAIL(str); -    while (isspace(*str)) {		/* Skip leading whitespace. */ +    while (ISSPACE(*str)) {		/* Skip leading whitespace. */  		++str;      } @@ -461,7 +543,7 @@ unsigned long long _stdlib_strto_ll(register const char * __restrict str,  #if _STRTO_ENDPTR      if (endptr) { -		*endptr = (char *) fail_char; +		*endptr = (Wchar *) fail_char;      }  #endif @@ -628,38 +710,6 @@ 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 > 0xffffUL -#define UTF_8_MAX_LEN 6 -#else -#define UTF_8_MAX_LEN 3 -#endif - -#ifdef __UCLIBC_HAS_LOCALE__ -#define ENCODING (__global_locale.encoding) -#ifdef __UCLIBC_MJN3_ONLY__ -#warning implement __CTYPE_HAS_UTF_8_LOCALES! -#endif -#define __CTYPE_HAS_UTF_8_LOCALES -#else -#define ENCODING (__ctype_encoding_7_bit) -#undef __CTYPE_HAS_8_BIT_LOCALES -#undef __CTYPE_HAS_UTF_8_LOCALES -#undef L__wchar_utf8sntowcs -#undef L__wchar_wcsntoutf8s -#endif - -#endif - -/**********************************************************************/  #ifdef L__stdlib_mb_cur_max  size_t _stdlib_mb_cur_max(void) @@ -774,4 +824,77 @@ size_t wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n)  #endif  /**********************************************************************/ +#ifdef L_wcstol + +#if ULONG_MAX == UINTMAX_MAX +strong_alias(wcstol,wcstoimax) +#endif + +#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) +strong_alias(wcstol,wcstoll) +#endif + +long wcstol(const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base) +{ +    return _stdlib_wcsto_l(str, endptr, base, 1); +} + +#endif +/**********************************************************************/ +#ifdef L_wcstoll + +#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) + +#if (ULLONG_MAX == UINTMAX_MAX) +strong_alias(wcstoll,wcstoimax) +#endif +strong_alias(wcstoll,wcstoq) + +long long wcstoll(const wchar_t * __restrict str, +				  wchar_t ** __restrict endptr, int base) +{ +    return (long long) _stdlib_wcsto_ll(str, endptr, base, 1); +} + +#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ + +#endif +/**********************************************************************/ +#ifdef L_wcstoul + +#if ULONG_MAX == UINTMAX_MAX +strong_alias(wcstoul,wcstoumax) +#endif + +#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) +strong_alias(wcstoul,wcstoull) +#endif + +unsigned long wcstoul(const wchar_t * __restrict str, +					  wchar_t ** __restrict endptr, int base) +{ +    return _stdlib_wcsto_l(str, endptr, base, 0); +} + +#endif +/**********************************************************************/ +#ifdef L_wcstoull + +#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) + +#if (ULLONG_MAX == UINTMAX_MAX) +strong_alias(wcstoull,wcstoumax) +#endif +strong_alias(wcstoull,wcstouq) + +unsigned long long wcstoull(const wchar_t * __restrict str, +							wchar_t ** __restrict endptr, int base) +{ +    return _stdlib_wcsto_ll(str, endptr, base, 0); +} + +#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ + +#endif +/**********************************************************************/ diff --git a/libc/sysdeps/linux/common/bits/uClibc_locale.h b/libc/sysdeps/linux/common/bits/uClibc_locale.h index 9227f5840..8025005ab 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_locale.h +++ b/libc/sysdeps/linux/common/bits/uClibc_locale.h @@ -157,7 +157,7 @@ typedef struct {  #ifdef __WCHAR_ENABLED  	const unsigned char *tblwctype;  	const unsigned char *tblwuplow; -	const unsigned char *tblwcomb; +/* 	const unsigned char *tblwcomb; */  	const int16_t *tblwuplow_diff; /* yes... signed */  	/* width?? */  #endif /* __WCHAR_ENABLED */ diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h b/libc/sysdeps/linux/common/bits/uClibc_stdio.h index f6d27142e..59156eeea 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h +++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h @@ -418,6 +418,11 @@ extern void __stdio_validate_FILE(FILE *stream);  #define __stdio_validate_FILE(stream)		((void)0)  #endif +#ifdef __STDIO_WIDE +extern size_t _wstdio_fwrite(const wchar_t *__restrict ws, size_t n, +							 register FILE *__restrict stream); +#endif +  /**********************************************************************   * UTILITY functions   **********************************************************************/  | 
