summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
Diffstat (limited to 'libc')
-rw-r--r--libc/misc/locale/locale.c4
-rw-r--r--libc/misc/time/time.c7
-rw-r--r--libc/misc/wchar/Makefile15
-rw-r--r--libc/misc/wchar/wchar.c658
-rw-r--r--libc/misc/wchar/wstdio.c21
-rw-r--r--libc/stdio/Makefile10
-rw-r--r--libc/stdio/printf.c1134
-rw-r--r--libc/stdio/stdio.c58
-rw-r--r--libc/stdlib/Makefile11
-rw-r--r--libc/stdlib/stdlib.c215
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_locale.h2
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_stdio.h5
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
**********************************************************************/