summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Rules.mak5
-rw-r--r--include/printf.h2
-rw-r--r--include/stdlib.h26
-rw-r--r--libc/misc/assert/__assert.c2
-rw-r--r--libc/misc/locale/locale.c19
-rw-r--r--libc/misc/time/time.c5
-rw-r--r--libc/misc/wchar/Makefile29
-rw-r--r--libc/misc/wchar/wchar.c76
-rw-r--r--libc/misc/wchar/wstdio.c542
-rw-r--r--libc/misc/wctype/wctype.c123
-rw-r--r--libc/stdio/Makefile6
-rw-r--r--libc/stdio/old_vfprintf.c6
-rw-r--r--libc/stdio/printf.c72
-rw-r--r--libc/stdio/scanf.c38
-rw-r--r--libc/stdio/stdio.c378
-rw-r--r--libc/stdlib/stdlib.c26
-rw-r--r--libc/string/Makefile2
-rw-r--r--libc/string/wstring.c2
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_locale.h14
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_stdio.h53
20 files changed, 1177 insertions, 249 deletions
diff --git a/Rules.mak b/Rules.mak
index e35f9f708..cc9352385 100644
--- a/Rules.mak
+++ b/Rules.mak
@@ -125,11 +125,6 @@ ifeq ($(strip $(INCLUDE_THREADS)),true)
CFLAGS += -D_LIBC_REENTRANT
endif
-# Locale support is required for wide char support.
-ifneq ($(strip $(HAS_LOCALE)),true)
- HAS_WCHAR:=false
-endif
-
# TARGET_PREFIX is the directory under which which the uClibc runtime
# environment will be installed and used on the target system. The
# result will look something like the following:
diff --git a/include/printf.h b/include/printf.h
index 8b0a66c88..96e4afa5c 100644
--- a/include/printf.h
+++ b/include/printf.h
@@ -154,7 +154,7 @@ struct printf_info
The function should return the number of characters written,
or -1 for errors. */
-typedef int printf_function (FILE *__stream,
+typedef int (*printf_function) (FILE *__stream,
__const struct printf_info *__info,
__const void *__const *__args);
diff --git a/include/stdlib.h b/include/stdlib.h
index 1920e418a..235045f33 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -109,6 +109,7 @@ typedef struct
# define __ldiv_t_defined 1
#endif
+#ifdef __UCLIBC_HAS_LONG_LONG__
#if defined __USE_ISOC99 && !defined __lldiv_t_defined
/* Returned by `lldiv'. */
__extension__ typedef struct
@@ -118,6 +119,7 @@ __extension__ typedef struct
} lldiv_t;
# define __lldiv_t_defined 1
#endif
+#endif /* __UCLIBC_HAS_LONG_LONG__ */
/* The largest number rand will return (same as INT_MAX). */
@@ -136,19 +138,24 @@ __extension__ typedef struct
extern size_t _stdlib_mb_cur_max (void) __THROW;
#endif
+#ifdef __UCLIBC_HAS_FLOATS__
/* Convert a string to a floating-point number. */
extern double atof (__const char *__nptr) __THROW __attribute_pure__;
+#endif /* __UCLIBC_HAS_FLOATS__ */
/* Convert a string to an integer. */
extern int atoi (__const char *__nptr) __THROW __attribute_pure__;
/* Convert a string to a long integer. */
extern long int atol (__const char *__nptr) __THROW __attribute_pure__;
+#ifdef __UCLIBC_HAS_LONG_LONG__
#if defined __USE_ISOC99 || (defined __GNUC__ && defined __USE_MISC)
/* Convert a string to a long long integer. */
__extension__ extern long long int atoll (__const char *__nptr)
__THROW __attribute_pure__;
#endif
+#endif /* __UCLIBC_HAS_LONG_LONG__ */
+#ifdef __UCLIBC_HAS_FLOATS__
/* Convert a string to a floating-point number. */
extern double strtod (__const char *__restrict __nptr,
char **__restrict __endptr) __THROW;
@@ -161,6 +168,7 @@ extern float strtof (__const char *__restrict __nptr,
extern long double strtold (__const char *__restrict __nptr,
char **__restrict __endptr) __THROW;
#endif
+#endif /* __UCLIBC_HAS_FLOATS__ */
/* Convert a string to a long integer. */
extern long int strtol (__const char *__restrict __nptr,
@@ -170,6 +178,7 @@ extern unsigned long int strtoul (__const char *__restrict __nptr,
char **__restrict __endptr, int __base)
__THROW;
+#ifdef __UCLIBC_HAS_LONG_LONG__
#if defined __GNUC__ && defined __USE_BSD
/* Convert a string to a quadword integer. */
__extension__
@@ -195,6 +204,7 @@ extern unsigned long long int strtoull (__const char *__restrict __nptr,
char **__restrict __endptr, int __base)
__THROW;
#endif /* ISO C99 or GCC and use MISC. */
+#endif /* __UCLIBC_HAS_LONG_LONG__ */
#if 0
@@ -251,6 +261,7 @@ extern long double __strtold_l (__const char *__restrict __nptr,
/* The internal entry points for `strtoX' take an extra flag argument
saying whether or not to parse locale-dependent number grouping. */
+#ifdef __UCLIBC_HAS_FLOATS__
extern double __strtod_internal (__const char *__restrict __nptr,
char **__restrict __endptr, int __group)
__THROW;
@@ -260,6 +271,7 @@ extern float __strtof_internal (__const char *__restrict __nptr,
extern long double __strtold_internal (__const char *__restrict __nptr,
char **__restrict __endptr,
int __group) __THROW;
+#endif /* __UCLIBC_HAS_FLOATS__ */
#ifndef __strtol_internal_defined
extern long int __strtol_internal (__const char *__restrict __nptr,
char **__restrict __endptr,
@@ -272,6 +284,7 @@ extern unsigned long int __strtoul_internal (__const char *__restrict __nptr,
int __base, int __group) __THROW;
# define __strtoul_internal_defined 1
#endif
+#ifdef __UCLIBC_HAS_LONG_LONG__
#if defined __GNUC__ || defined __USE_ISOC99
# ifndef __strtoll_internal_defined
__extension__
@@ -290,6 +303,7 @@ extern unsigned long long int __strtoull_internal (__const char *
# define __strtoull_internal_defined 1
# endif
#endif /* GCC */
+#endif /* __UCLIBC_HAS_LONG_LONG__ */
#ifdef __USE_EXTERN_INLINES
/* Define inline functions which call the internal entry points. */
@@ -460,9 +474,11 @@ extern int rand_r (unsigned int *__seed) __THROW;
#if defined __USE_SVID || defined __USE_XOPEN
/* System V style 48-bit random number generator functions. */
+#ifdef __UCLIBC_HAS_FLOATS__
/* Return non-negative, double-precision floating-point value in [0.0,1.0). */
extern double drand48 (void) __THROW;
extern double erand48 (unsigned short int __xsubi[3]) __THROW;
+#endif /* __UCLIBC_HAS_FLOATS__ */
/* Return non-negative, long integer in [0,2^31). */
extern long int lrand48 (void) __THROW;
@@ -487,15 +503,19 @@ struct drand48_data
unsigned short int __old_x[3]; /* Old state. */
unsigned short int __c; /* Additive const. in congruential formula. */
unsigned short int __init; /* Flag for initializing. */
+#ifdef __UCLIBC_HAS_LONG_LONG__
unsigned long long int __a; /* Factor in congruential formula. */
+#endif /* __UCLIBC_HAS_LONG_LONG__ */
};
+#ifdef __UCLIBC_HAS_FLOATS__
/* Return non-negative, double-precision floating-point value in [0.0,1.0). */
extern int drand48_r (struct drand48_data *__restrict __buffer,
double *__restrict __result) __THROW;
extern int erand48_r (unsigned short int __xsubi[3],
struct drand48_data *__restrict __buffer,
double *__restrict __result) __THROW;
+#endif /* __UCLIBC_HAS_FLOATS__ */
/* Return non-negative, long integer in [0,2^31). */
extern int lrand48_r (struct drand48_data *__restrict __buffer,
@@ -707,10 +727,12 @@ extern void qsort (void *__base, size_t __nmemb, size_t __size,
/* Return the absolute value of X. */
extern int abs (int __x) __THROW __attribute__ ((__const__));
extern long int labs (long int __x) __THROW __attribute__ ((__const__));
+#ifdef __UCLIBC_HAS_LONG_LONG__
#ifdef __USE_ISOC99
__extension__ extern long long int llabs (long long int __x)
__THROW __attribute__ ((__const__));
#endif
+#endif /* #ifdef __UCLIBC_HAS_LONG_LONG__ */
/* Return the `div_t', `ldiv_t' or `lldiv_t' representation
@@ -720,13 +742,16 @@ extern div_t div (int __numer, int __denom)
__THROW __attribute__ ((__const__));
extern ldiv_t ldiv (long int __numer, long int __denom)
__THROW __attribute__ ((__const__));
+#ifdef __UCLIBC_HAS_LONG_LONG__
#ifdef __USE_ISOC99
__extension__ extern lldiv_t lldiv (long long int __numer,
long long int __denom)
__THROW __attribute__ ((__const__));
#endif
+#endif /* __UCLIBC_HAS_LONG_LONG__ */
+#ifdef __UCLIBC_HAS_FLOATS__
#if defined __USE_SVID || defined __USE_XOPEN_EXTENDED
/* Convert floating point numbers to strings. The returned values are
valid only until another call to the same function. */
@@ -775,6 +800,7 @@ extern int qfcvt_r (long double __value, int __ndigit,
char *__restrict __buf, size_t __len) __THROW;
# endif /* misc */
#endif /* use MISC || use X/Open Unix */
+#endif /* __UCLIBC_HAS_FLOATS__ */
#ifdef __UCLIBC_HAS_WCHAR__
/* Return the length of the multibyte character
diff --git a/libc/misc/assert/__assert.c b/libc/misc/assert/__assert.c
index fba9dc719..db5f9a7a9 100644
--- a/libc/misc/assert/__assert.c
+++ b/libc/misc/assert/__assert.c
@@ -28,7 +28,7 @@
#undef assert
void __assert(const char *assertion, const char * filename,
- int linenumber, const char * function)
+ int linenumber, register const char * function)
{
char buf[__BUFLEN_INT10TOSTR];
diff --git a/libc/misc/locale/locale.c b/libc/misc/locale/locale.c
index fd52782c1..689257b41 100644
--- a/libc/misc/locale/locale.c
+++ b/libc/misc/locale/locale.c
@@ -30,13 +30,7 @@
#include <stdint.h>
#include <assert.h>
-#ifdef __LOCALE_C_ONLY
-
-#ifdef __WCHAR_ENABLED
-#error wide char support requires full locale support
-#endif
-
-#else /* __LOCALE_C_ONLY */
+#ifndef __LOCALE_C_ONLY
#define CUR_LOCALE_SPEC (__global_locale.cur_locale)
#undef CODESET_LIST
@@ -496,14 +490,15 @@ void _locale_set(const unsigned char *p)
* ctype, numeric, monetary, time, collate, messages, all
*/
+#define C_LC_ALL 6
/* Combine the data to avoid size penalty for seperate char arrays when
* compiler aligns objects. The original code is left in as documentation. */
#define cat_start nl_data
-#define C_locale_data nl_data + LC_ALL + 1 + 78
+#define C_locale_data (nl_data + C_LC_ALL + 1 + 78)
-static const unsigned char nl_data[LC_ALL + 1 + 78 + 300] = {
-/* static const unsigned char cat_start[LC_ALL + 1] = { */
+static const unsigned char nl_data[C_LC_ALL + 1 + 78 + 300] = {
+/* static const unsigned char cat_start[C_LC_ALL + 1] = { */
'\x00', '\x01', '\x04', '\x1a', '\x4c', '\x4c', '\x4e',
/* }; */
/* static const unsigned char item_offset[78] = { */
@@ -564,10 +559,10 @@ char *nl_langinfo(nl_item item)
unsigned int c;
unsigned int i;
- if ((c = _NL_ITEM_CATEGORY(item)) < LC_ALL) {
+ if ((c = _NL_ITEM_CATEGORY(item)) < C_LC_ALL) {
if ((i = cat_start[c] + _NL_ITEM_INDEX(item)) < cat_start[c+1]) {
/* return (char *) C_locale_data + item_offset[i] + (i & 64); */
- return (char *) C_locale_data + nl_data[LC_ALL+1+i] + (i & 64);
+ return (char *) C_locale_data + nl_data[C_LC_ALL+1+i] + (i & 64);
}
}
return (char *) cat_start; /* Conveniently, this is the empty string. */
diff --git a/libc/misc/time/time.c b/libc/misc/time/time.c
index 409be3247..e7e3b8414 100644
--- a/libc/misc/time/time.c
+++ b/libc/misc/time/time.c
@@ -94,14 +94,12 @@
#endif
/* TODO - This stuff belongs in some include/bits/ file. */
-#ifndef __BCC__
#undef CLK_TCK
#if (TARGET_ARCH == alpha) || (TARGET_ARCH == ia64)
#define CLK_TCK 1024
#else
#define CLK_TCK 100
#endif
-#endif
/* The era code is currently unfinished. */
/* #define ENABLE_ERA_CODE */
@@ -1855,9 +1853,8 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)
}
#ifdef __BCC__
- /* TODO - check */
d = p[5] - 1;
- days = -719163L + d*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
+ days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
secs = p[0] + 60*( p[1] + 60*((long)(p[2])) )
+ _time_tzinfo[timeptr->tm_isdst > 0].gmt_offset;
if (secs < 0) {
diff --git a/libc/misc/wchar/Makefile b/libc/misc/wchar/Makefile
index 23a1e9bba..ddd701a6d 100644
--- a/libc/misc/wchar/Makefile
+++ b/libc/misc/wchar/Makefile
@@ -24,12 +24,27 @@
TOPDIR=../../../
include $(TOPDIR)Rules.mak
-MSRC= wchar.c
-MOBJ= btowc.o wctob.o mbsinit.o mbrlen.o mbrtowc.o wcrtomb.o mbsrtowcs.o \
- wcsrtombs.o _wchar_utf8sntowcs.o _wchar_wcstoutf8s.o \
+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
-OBJS=$(MOBJ)
+MSRC2= wstdio.c
+MOBJ2= fwide.o \
+ fgetwc.o getwchar.o fgetws.o \
+ fputwc.o putwchar.o fputws.o \
+ ungetwc.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
+
+OBJS=$(MOBJ1) $(MOBJ2)
all: $(OBJS) $(LIBC)
@@ -38,7 +53,11 @@ $(LIBC): ar-target
ar-target: $(OBJS)
$(AR) $(ARFLAGS) $(LIBC) $(OBJS)
-$(MOBJ): $(MSRC)
+$(MOBJ1): $(MSRC1)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+$(MOBJ2): $(MSRC2)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
diff --git a/libc/misc/wchar/wchar.c b/libc/misc/wchar/wchar.c
index f2d9f4a7d..9f08f3312 100644
--- a/libc/misc/wchar/wchar.c
+++ b/libc/misc/wchar/wchar.c
@@ -50,6 +50,14 @@
* an issue for uClibc, but may be for ELKS. I'm currently not sure
* if I'll use 16-bit, 32-bit, or configureable wchars in ELKS.
*
+ * July 1, 2002
+ *
+ * Fixed _wchar_utf8sntowcs() for the max number of wchars == 0 case.
+ * Fixed nul-char bug in btowc(), and another in __mbsnrtowcs() for 8-bit
+ * locales.
+ * Enabled building of a C/POSIX-locale-only version, so full locale support
+ * no longer needs to be enabled.
+ *
* Manuel
*/
@@ -66,7 +74,17 @@
#include <locale.h>
#include <wchar.h>
+#ifdef __UCLIBC_HAS_LOCALE__
#define ENCODING (__global_locale.encoding)
+#warning implement __CTYPE_HAS_UTF_8_LOCALES!
+#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
#if WCHAR_MAX > 0xffffU
#define UTF_8_MAX_LEN 6
@@ -76,9 +94,6 @@
/* #define KUHN */
-#warning implement __CTYPE_HAS_UTF_8_LOCALES!
-#define __CTYPE_HAS_UTF_8_LOCALES
-
/* Implementation-specific work functions. */
extern size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
@@ -103,6 +118,8 @@ extern size_t __wcsnrtombs(char *__restrict dst,
wint_t btowc(int c)
{
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+
wchar_t wc;
unsigned char buf[1];
mbstate_t mbstate;
@@ -110,11 +127,19 @@ wint_t btowc(int c)
if (c != EOF) {
*buf = (unsigned char) c;
mbstate.mask = 0; /* Initialize the mbstate. */
- if (mbrtowc(&wc, buf, 1, &mbstate) == 1) {
+ if (mbrtowc(&wc, buf, 1, &mbstate) <= 1) {
return wc;
}
}
return WEOF;
+
+#else /* __CTYPE_HAS_8_BIT_LOCALES */
+
+ /* 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 */
}
#endif
@@ -125,9 +150,22 @@ wint_t btowc(int c)
int wctob(wint_t c)
{
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+
unsigned char buf[MB_LEN_MAX];
return (wcrtomb(buf, c, NULL) == 1) ? *buf : EOF;
+
+#else /* __CTYPE_HAS_8_BIT_LOCALES */
+
+ /* 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;
+
+#endif /* __CTYPE_HAS_8_BIT_LOCALES */
}
#endif
@@ -144,6 +182,9 @@ int mbsinit(const mbstate_t *ps)
#ifdef L_mbrlen
size_t mbrlen(const char *__restrict s, size_t n, mbstate_t *__restrict ps)
+ __attribute__ ((__weak__, __alias__("__mbrlen")));
+
+size_t __mbrlen(const char *__restrict s, size_t n, mbstate_t *__restrict ps)
{
static mbstate_t mbstate; /* Rely on bss 0-init. */
@@ -183,7 +224,7 @@ size_t mbrtowc(wchar_t *__restrict pwc, const char *__restrict s,
/* Need to do this here since mbsrtowcs doesn't allow incompletes. */
if (ENCODING == __ctype_encoding_utf8) {
r = _wchar_utf8sntowcs(pwc, 1, &p, n, ps, 1);
- return (r == 1) ? (p-s) : r;
+ return (r == 1) ? (p-s) : r; /* Need to return 0 if nul char. */
}
#endif
@@ -289,10 +330,13 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
wn = SIZE_MAX;
incr = 0;
}
-#warning fix _wchar_utf8sntowcs to allow wn == 0!
- assert(wn > 0); /* TODO: fix this!! */
- count = wn;
+ /* This is really here only to support the glibc extension function
+ * __mbsnrtowcs which apparently returns 0 if wn == 0 without any
+ * check on the validity of the mbstate. */
+ if (!(count = wn)) {
+ return 0;
+ }
if ((mask = (__uwchar_t) ps->mask) != 0) { /* A continuation... */
#ifdef DECODER
@@ -420,7 +464,7 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
#endif
/**********************************************************************/
-#ifdef L__wchar_wcstoutf8s
+#ifdef L__wchar_wcsntoutf8s
size_t _wchar_wcsntoutf8s(char *__restrict s, size_t n,
const wchar_t **__restrict src, size_t wn)
@@ -568,13 +612,13 @@ size_t __mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src,
if (!wc) {
goto BAD;
}
- } else if (!wc) {
+ }
+ if (!(*dst = wc)) {
s = NULL;
break;
}
- ++s;
- *dst = wc;
dst += incr;
+ ++s;
--count;
}
if (dst != wcbuf) {
@@ -633,7 +677,7 @@ size_t __wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src,
if (ENCODING == __ctype_encoding_utf8) {
return _wchar_wcsntoutf8s(dst, len, src, NWC);
}
-#endif
+#endif /* __CTYPE_HAS_UTF_8_LOCALES */
incr = 1;
if (!dst) {
@@ -676,12 +720,12 @@ size_t __wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src,
/* #define __WCHAR_REPLACEMENT_CHAR '?' */
#ifdef __WCHAR_REPLACEMENT_CHAR
*dst = (unsigned char) ( u ? u : __WCHAR_REPLACEMENT_CHAR );
-#else
+#else /* __WCHAR_REPLACEMENT_CHAR */
if (!u) {
goto BAD;
}
*dst = (unsigned char) u;
-#endif
+#endif /* __WCHAR_REPLACEMENT_CHAR */
}
++s;
dst += incr;
@@ -692,7 +736,7 @@ size_t __wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src,
}
return len - count;
}
-#endif
+#endif /* __CTYPE_HAS_8_BIT_LOCALES */
assert(ENCODING == __ctype_encoding_7_bit);
diff --git a/libc/misc/wchar/wstdio.c b/libc/misc/wchar/wstdio.c
new file mode 100644
index 000000000..79cf1dfa1
--- /dev/null
+++ b/libc/misc/wchar/wstdio.c
@@ -0,0 +1,542 @@
+
+/*
+ * ANSI/ISO C99 says
+
+ 9 Although both text and binary wide­oriented streams are conceptually sequences of wide
+ characters, the external file associated with a wide­oriented stream is a sequence of
+ multibyte characters, generalized as follows:
+ --- Multibyte encodings within files may contain embedded null bytes (unlike multibyte
+ encodings valid for use internal to the program).
+ --- A file need not begin nor end in the initial shift state. 225)
+
+ * How do we deal with this?
+
+ * Should auto_wr_transition init the mbstate object?
+*/
+
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <wchar.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifndef __STDIO_THREADSAFE
+
+#ifdef __BCC__
+#define UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,STREAM) \
+asm(".text\nexport _" "NAME" "_unlocked\n_" "NAME" "_unlocked = _" "NAME"); \
+RETURNTYPE NAME PARAMS
+#else
+#define UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,STREAM) \
+strong_alias(NAME,NAME##_unlocked) \
+RETURNTYPE NAME PARAMS
+#endif
+
+#define UNLOCKED(RETURNTYPE,NAME,PARAMS,ARGS) \
+ UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,stream)
+
+#ifdef __BCC__
+#define UNLOCKED_VOID_RETURN(NAME,PARAMS,ARGS) \
+asm(".text\nexport _" "NAME" "_unlocked\n_" "NAME" "_unlocked = _" "NAME"); \
+void NAME PARAMS
+#else
+#define UNLOCKED_VOID_RETURN(NAME,PARAMS,ARGS) \
+strong_alias(NAME,NAME##_unlocked) \
+void NAME PARAMS
+#endif
+
+#define __STDIO_THREADLOCK_OPENLIST
+#define __STDIO_THREADUNLOCK_OPENLIST
+
+#else /* __STDIO_THREADSAFE */
+
+#include <pthread.h>
+
+#define UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,STREAM) \
+RETURNTYPE NAME PARAMS \
+{ \
+ RETURNTYPE retval; \
+ __STDIO_THREADLOCK(STREAM); \
+ retval = NAME##_unlocked ARGS ; \
+ __STDIO_THREADUNLOCK(STREAM); \
+ return retval; \
+} \
+RETURNTYPE NAME##_unlocked PARAMS
+
+#define UNLOCKED(RETURNTYPE,NAME,PARAMS,ARGS) \
+ UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,stream)
+
+#define UNLOCKED_VOID_RETURN(NAME,PARAMS,ARGS) \
+void NAME PARAMS \
+{ \
+ __STDIO_THREADLOCK(stream); \
+ NAME##_unlocked ARGS ; \
+ __STDIO_THREADUNLOCK(stream); \
+} \
+void NAME##_unlocked PARAMS
+
+#define __STDIO_THREADLOCK_OPENLIST \
+ pthread_mutex_lock(&_stdio_openlist_lock)
+
+#define __STDIO_THREADUNLOCK_OPENLIST \
+ pthread_mutex_unlock(&_stdio_openlist_lock)
+
+#define __STDIO_THREADTRYLOCK_OPENLIST \
+ pthread_mutex_trylock(&_stdio_openlist_lock)
+
+#endif /* __STDIO_THREADSAFE */
+
+#ifndef __STDIO_BUFFERS
+#error stdio buffers are currently required for wide i/o
+#endif
+
+/**********************************************************************/
+#ifdef L_fwide
+
+/* TODO: According to SUSv3 should return EBADF if invalid stream. */
+
+int fwide(register FILE *stream, int mode)
+{
+ __STDIO_THREADLOCK(stream);
+
+ if (mode && !(stream->modeflags & (__FLAG_WIDE|__FLAG_NARROW))) {
+ stream->modeflags |= ((mode > 0) ? __FLAG_WIDE : __FLAG_NARROW);
+ }
+
+ mode = (stream->modeflags & __FLAG_WIDE)
+ - (stream->modeflags & __FLAG_NARROW);
+
+ __STDIO_THREADUNLOCK(stream);
+
+ return mode;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_fgetwc
+
+static void munge_stream(register FILE *stream, unsigned char *buf)
+{
+#ifdef __STDIO_GETC_MACRO
+ stream->bufgetc =
+#endif
+#ifdef __STDIO_PUTC_MACRO
+ stream->bufputc =
+#endif
+ stream->bufpos = stream->bufread = stream->bufend = stream->bufstart = buf;
+}
+
+UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream))
+{
+ wint_t wi;
+ wchar_t wc[1];
+ int n;
+ size_t r;
+ unsigned char c[1];
+ unsigned char sbuf[1];
+ unsigned char ungot_width; /* Support ftell after wscanf ungetwc. */
+
+ wi = WEOF; /* Prepare for failure. */
+
+ if (stream->modeflags & __FLAG_NARROW) {
+ stream->modeflags |= __FLAG_ERROR;
+ __set_errno(EBADF);
+ goto DONE;
+ }
+ stream->modeflags |= __FLAG_WIDE;
+
+ if (stream->modeflags & __MASK_UNGOT) {/* Any ungetwc()s? */
+ assert( (stream->modeflags & (__FLAG_READING|__FLAG_ERROR))
+ == __FLAG_READING);
+ wi = stream->ungot[(--stream->modeflags) & __MASK_UNGOT];
+ stream->ungot[1] = 0;
+ goto DONE;
+ }
+
+ if (!stream->bufstart) { /* Ugh... stream isn't buffered! */
+ /* Munge the stream temporarily to use a 1-byte buffer. */
+ munge_stream(stream, sbuf);
+ ++stream->bufend;
+ }
+
+ ungot_width = 0;
+
+ LOOP:
+ if ((n = stream->bufread - stream->bufpos) == 0) {
+ goto FILL_BUFFER;
+ }
+
+ r = mbrtowc(wc, stream->bufpos, n, &stream->state);
+ if (((ssize_t) r) >= 0) { /* Single byte... */
+ if (r == 0) { /* Nul wide char... means 0 byte for us so */
+ ++r; /* increment r and handle below as single. */
+ }
+ stream->bufpos += r;
+ stream->ungot_width[0] = ungot_width + r;
+ wi = *wc;
+ goto DONE;
+ }
+
+ if (r == ((size_t) -2)) {
+ /* Potentially valid but incomplete and no more buffered. */
+ stream->bufpos += n; /* Update bufpos for stream. */
+ ungot_width += n;
+ FILL_BUFFER:
+ if (_stdio_fread(c, (size_t) 1, stream) > 0) {
+ assert(stream->bufpos == stream->bufstart + 1);
+ *--stream->bufpos = *c; /* Insert byte into buffer. */
+ goto LOOP;
+ }
+ if (!__FERROR(stream)) { /* EOF with no error. */
+ if (!stream->state.mask) { /* No partially complete wchar. */
+ goto DONE;
+ }
+ /* EOF but partially complete wchar. */
+ /* TODO: should EILSEQ be set? */
+ __set_errno(EILSEQ);
+ }
+ }
+
+ /* If we reach here, either r == ((size_t)-1) and mbrtowc set errno
+ * to EILSEQ, or r == ((size_t)-2) and stream is in an error state
+ * or at EOF with a partially complete wchar. Make sure stream's
+ * error indicator is set. */
+ stream->modeflags |= __FLAG_ERROR;
+
+ DONE:
+ if (stream->bufstart == sbuf) { /* Need to un-munge the stream. */
+ munge_stream(stream, NULL);
+ }
+
+ return wi;
+}
+
+strong_alias(fgetwc_unlocked,getwc_unlocked);
+strong_alias(fgetwc,getwc);
+
+#endif
+/**********************************************************************/
+#ifdef L_getwchar
+
+UNLOCKED_STREAM(wint_t,getwchar,(void),(),stdin)
+{
+ register FILE *stream = stdin; /* This helps bcc optimize. */
+
+ return fgetwc_unlocked(stream);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_fgetws
+
+UNLOCKED(wchar_t *,fgetws,(wchar_t *__restrict ws, int n,
+ FILE *__restrict stream),(ws, n, stream))
+{
+ register wchar_t *p = ws;
+ wint_t wi;
+
+ while ((n > 1)
+ && ((wi = fgetwc_unlocked(stream)) != WEOF)
+ && ((*p++ = wi) != '\n')
+ ) {
+ --n;
+ }
+ if (p == ws) {
+ /* TODO -- should we set errno? */
+/* if (n <= 0) { */
+/* errno = EINVAL; */
+/* } */
+ return NULL;
+ }
+ *p = 0;
+ return ws;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_fputwc
+
+UNLOCKED(wint_t,fputwc,(wchar_t wc, FILE *stream),(wc, stream))
+{
+#if 0
+ size_t r;
+ char buf[MB_LEN_MAX];
+
+ if (stream->modeflags & __FLAG_NARROW) {
+ stream->modeflags |= __FLAG_ERROR;
+ __set_errno(EBADF);
+ return WEOF;
+ }
+ stream->modeflags |= __FLAG_WIDE;
+
+ /* TODO:
+ * If stream is in reading state with bad mbstate object, what to do?
+ * Should we check the state first? Should we check error indicator?
+ * Should we check reading or even read-only?
+ */
+ /* It looks like the only ANSI/ISO C99 - blessed way of manipulating
+ * the stream's mbstate object is through fgetpos/fsetpos. */
+ r = wcrtomb(buf, wc, &stream->state);
+
+ return (r != ((size_t) -1) && (r == _stdio_fwrite(buf, r, stream)))
+ ? wc : WEOF;
+
+#elif 0
+
+ /* this is broken if wc == 0 !!! */
+ wchar_t wbuf[2];
+
+ wbuf[0] = wc;
+ wbuf[1] = 0;
+
+ return (fputws_unlocked(wbuf, stream) > 0) ? wc : WEOF;
+
+#else
+
+ size_t n;
+ char buf[MB_LEN_MAX];
+
+ if (stream->modeflags & __FLAG_NARROW) {
+ stream->modeflags |= __FLAG_ERROR;
+ __set_errno(EBADF);
+ return WEOF;
+ }
+ 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. */
+ ? wc : WEOF;
+
+#endif
+}
+
+strong_alias(fputwc_unlocked,putwc_unlocked);
+strong_alias(fputwc,putwc);
+
+#endif
+/**********************************************************************/
+#ifdef L_putwchar
+
+UNLOCKED_STREAM(wint_t,putwchar,(wchar_t wc),(wc),stdout)
+{
+ register FILE *stream = stdout; /* This helps bcc optimize. */
+
+ return fputwc_unlocked(wc, stream);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_fputws
+
+UNLOCKED(int,fputws,(const wchar_t *__restrict ws,
+ register FILE *__restrict stream),(ws, stream))
+{
+#if 1
+ size_t n;
+ char buf[64];
+
+ if (stream->modeflags & __FLAG_NARROW) {
+ stream->modeflags |= __FLAG_ERROR;
+ __set_errno(EBADF);
+ return -1;
+ }
+ stream->modeflags |= __FLAG_WIDE;
+
+ while ((n = wcsrtombs(buf, &ws, sizeof(buf), &stream->state)) != 0) {
+ /* Wasn't an empty wide string. */
+ if ((n == ((size_t) -1))/* Encoding error! */
+ || (_stdio_fwrite(buf, n, stream) != n)/* Didn't write everything. */
+ ) {
+ return -1;
+ }
+ if (!ws) { /* Done? */
+ break;
+ }
+ }
+
+ return 1;
+
+
+
+
+#elif 1
+ int result;
+ size_t n;
+ size_t len;
+ register char *s;
+ unsigned char *bufend;
+ char sbuf[MB_LEN_MAX];
+
+ if (stream->modeflags & __FLAG_NARROW) {
+ RETURN_BADF:
+ stream->modeflags |= __FLAG_ERROR;
+ __set_errno(EBADF);
+ return -1;
+ }
+ stream->modeflags |= __FLAG_WIDE;
+
+ /* Note: What follows is setup grabbed from _stdio_fwrite and modified
+ * slightly. Since this is a wide stream, we can ignore bufgetc and
+ * bufputc if present. They always == bufstart.
+ * It is unfortunate that we need to duplicate so much code here, but
+ * we need to do the stream setup before starting the wc->mb conversion. */
+
+ if ((stream->modeflags & __FLAG_READONLY)
+#ifndef __STDIO_AUTO_RW_TRANSITION
+ /* ANSI/ISO requires either at EOF or currently not reading. */
+ || ((stream->modeflags & (__FLAG_READING|__FLAG_EOF))
+ == __FLAG_READING)
+#endif /* __STDIO_AUTO_RW_TRANSITION */
+ ) {
+ /* TODO: This is for posix behavior if readonly. To save space, we
+ * use this errno for write attempt while reading, as no errno is
+ * specified by posix for this case, even though the restriction is
+ * mentioned in fopen(). */
+ goto RETURN_BADF;
+ }
+
+#ifdef __STDIO_AUTO_RW_TRANSITION
+ /* If reading, deal with ungots and read-buffered chars. */
+ if (stream->modeflags & __FLAG_READING) {
+ if (((stream->bufpos < stream->bufread)
+ || (stream->modeflags & __MASK_UNGOT))
+ /* If appending, we might as well seek to end to save a seek. */
+ /* TODO: set EOF in fseek when appropriate? */
+ && fseek(stream, 0L,
+ ((stream->modeflags & __FLAG_APPEND)
+ ? SEEK_END : SEEK_CUR))
+ ) {
+ /* Note: This differs from glibc's apparent behavior of
+ not setting the error flag and discarding the buffered
+ read data. */
+ stream->modeflags |= __FLAG_ERROR; /* fseek may not set this. */
+ return -1; /* Fail if we need to fseek but can't. */
+ }
+ /* Always reset even if fseek called (saves a test). */
+ stream->bufpos = stream->bufread = stream->bufstart;
+ stream-