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 **********************************************************************/ |