diff options
author | Manuel Novoa III <mjn3@codepoet.org> | 2002-07-03 17:24:17 +0000 |
---|---|---|
committer | Manuel Novoa III <mjn3@codepoet.org> | 2002-07-03 17:24:17 +0000 |
commit | 599ad608ee3297bc1e2bb11656a97335e303877a (patch) | |
tree | c5b59cb5fa2c90f3b0c8b4d9831ae763f2825327 | |
parent | ab579e469c6787df9bd2252b3de8b1700d5097d8 (diff) |
Enable WCHAR support for C/POSIX stub locales.
Implemented unformatted wide i/o functions. (ungetwc still needs testing)
Fix a few bugs in wchar.c.
Modifications for bcc/elks support.
-rw-r--r-- | Rules.mak | 5 | ||||
-rw-r--r-- | include/printf.h | 2 | ||||
-rw-r--r-- | include/stdlib.h | 26 | ||||
-rw-r--r-- | libc/misc/assert/__assert.c | 2 | ||||
-rw-r--r-- | libc/misc/locale/locale.c | 19 | ||||
-rw-r--r-- | libc/misc/time/time.c | 5 | ||||
-rw-r--r-- | libc/misc/wchar/Makefile | 29 | ||||
-rw-r--r-- | libc/misc/wchar/wchar.c | 76 | ||||
-rw-r--r-- | libc/misc/wchar/wstdio.c | 542 | ||||
-rw-r--r-- | libc/misc/wctype/wctype.c | 123 | ||||
-rw-r--r-- | libc/stdio/Makefile | 6 | ||||
-rw-r--r-- | libc/stdio/old_vfprintf.c | 6 | ||||
-rw-r--r-- | libc/stdio/printf.c | 72 | ||||
-rw-r--r-- | libc/stdio/scanf.c | 38 | ||||
-rw-r--r-- | libc/stdio/stdio.c | 378 | ||||
-rw-r--r-- | libc/stdlib/stdlib.c | 26 | ||||
-rw-r--r-- | libc/string/Makefile | 2 | ||||
-rw-r--r-- | libc/string/wstring.c | 2 | ||||
-rw-r--r-- | libc/sysdeps/linux/common/bits/uClibc_locale.h | 14 | ||||
-rw-r--r-- | libc/sysdeps/linux/common/bits/uClibc_stdio.h | 53 |
20 files changed, 1177 insertions, 249 deletions
@@ -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 wideoriented streams are conceptually sequences of wide + characters, the external file associated with a wideoriented 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->modeflags &= ~__FLAG_READING; + } +#endif + + /* Ok, the boilerplate from _stdio_fwrite is done. */ + + if (stream->bufpos > stream->bufstart) { /* Pending writes.. */ + /* This is a performance penalty, but it simplifies the code below. + * If this is removed, the buffer sharing and while loop condition + * need to be modified below (at least). We at least save a little + * on the overhead by calling _stdio_fwrite directly instead of + * fflush_unlocked. */ + if (_stdio_fwrite(NULL, 0, stream) > 0) {/* fflush incomplete! */ + return -1; + } + } + + stream->modeflags |= __FLAG_WRITING; /* Ensure Writing flag is set. */ + + /* Next, we "steal" the stream's buffer and do the wc->mb conversion + * straight into it. This will cause the equivalent of an fflush + * for each string write. :-( */ + + bufend = NULL; + s = stream->bufstart; + + if ((len = stream->bufend - stream->bufstart) < MB_LEN_MAX) { + /* Stream is unbuffered or buffer is too small, so deactivate. */ + bufend = stream->bufend; + stream->bufend = stream->bufstart; + s = sbuf; + len = MB_LEN_MAX; + } + + result = 1; /* Assume success. */ + while (ws && (n = wcsrtombs(s, &ws, len, &stream->state)) != 0) { + if ((n == ((size_t) -1)) /* Encoding error! */ + /* TODO - maybe call write directly? but what about custom streams? */ + || (_stdio_fwrite(s, n, stream) != n)/* Didn't write everything. */ + ) { + result = -1; + break; + } + } + + if (bufend) { /* If deactivated stream buffer, renable it. */ + stream->bufend = bufend; + } + + return result; + +#else /* slow, dumb version */ + while (*ws) { + if (fputwc_unlocked(*ws, stream) == WEOF) { + return -1; + } + ++ws; + } + return 1; +#endif +} + +#endif +/**********************************************************************/ +#ifdef L_ungetwc +/* + * Note: This is the application-callable ungetwc. If wscanf calls this, it + * should also set stream->ungot[1] to 0 if this is the only ungot. + */ + +/* Reentrant. */ + +wint_t ungetwc(wint_t c, register FILE *stream) +{ + __STDIO_THREADLOCK(stream); + + __stdio_validate_FILE(stream); /* debugging only */ + + if (stream->modeflags & __FLAG_NARROW) { + stream->modeflags |= __FLAG_ERROR; + c = WEOF; + goto DONE; + } + stream->modeflags |= __FLAG_WIDE; + + /* If can't read or there's been an error, or c == EOF, or ungot slots + * already filled, then return EOF */ + if ((stream->modeflags + & (__MASK_UNGOT2|__FLAG_WRITEONLY +#ifndef __STDIO_AUTO_RW_TRANSITION + |__FLAG_WRITING /* Note: technically no, but yes in spirit */ +#endif /* __STDIO_AUTO_RW_TRANSITION */ + )) + || ((stream->modeflags & __MASK_UNGOT1) && (stream->ungot[1])) + || (c == WEOF) ) { + c = WEOF; + goto DONE;; + } + +/* ungot_width */ + +#ifdef __STDIO_BUFFERS + /* TODO: shouldn't allow writing??? */ + if (stream->modeflags & __FLAG_WRITING) { + fflush_unlocked(stream); /* Commit any write-buffered chars. */ + } +#endif /* __STDIO_BUFFERS */ + + /* Clear EOF and WRITING flags, and set READING FLAG */ + stream->modeflags &= ~(__FLAG_EOF|__FLAG_WRITING); + stream->modeflags |= __FLAG_READING; + stream->ungot[1] = 1; /* Flag as app ungetc call; wscanf fixes up. */ + stream->ungot[(stream->modeflags++) & __MASK_UNGOT] = c; + + __stdio_validate_FILE(stream); /* debugging only */ + + DONE: + __STDIO_THREADUNLOCK(stream); + + return c; +} + +#endif +/**********************************************************************/ diff --git a/libc/misc/wctype/wctype.c b/libc/misc/wctype/wctype.c index 39ed2cfd5..802e979f1 100644 --- a/libc/misc/wctype/wctype.c +++ b/libc/misc/wctype/wctype.c @@ -34,6 +34,7 @@ #include <string.h> #include <errno.h> #include <locale.h> +#include <ctype.h> /* We know wide char support is enabled. We wouldn't be here otherwise. */ @@ -41,7 +42,9 @@ * towctrans function. */ /* #define SMALL_UPLOW */ +#ifndef __LOCALE_C_ONLY #define __WCTYPE_WITH_LOCALE +#endif /**********************************************************************/ @@ -292,6 +295,10 @@ wctype_t wctype(const char *property) /**********************************************************************/ #ifdef L_iswctype +#warning duh... replace the range-based classification with table lookup! + +#ifdef __WCTYPE_WITH_LOCALE + #warning TODO: need to fix locale ctype table lookup stuff #if 0 extern const char ctype_range[]; @@ -346,6 +353,102 @@ int iswctype(wint_t wc, wctype_t desc) return 0; } +#else + +static const unsigned char WCctype[] = { + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_space_blank << 4), + __CTYPE_cntrl_space_nonblank | (__CTYPE_cntrl_space_nonblank << 4), + __CTYPE_cntrl_space_nonblank | (__CTYPE_cntrl_space_nonblank << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4), + __CTYPE_print_space_blank | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_digit | (__CTYPE_digit << 4), + __CTYPE_digit | (__CTYPE_digit << 4), + __CTYPE_digit | (__CTYPE_digit << 4), + __CTYPE_digit | (__CTYPE_digit << 4), + __CTYPE_digit | (__CTYPE_digit << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4), + __CTYPE_alpha_upper | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4), + __CTYPE_alpha_lower | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_punct << 4), + __CTYPE_punct | (__CTYPE_cntrl_nonspace << 4), +}; + +static const char ctype_range[] = { + __CTYPE_RANGES +}; + +int iswctype(wint_t wc, wctype_t desc) +{ + unsigned char d = __CTYPE_unclassified; + + if (((__uwchar_t) wc) <= 0x7f) { + if (desc < _CTYPE_iswxdigit) { + d = WCctype[wc >> 1]; + d = (wc & 1) ? (d >> 4) : (d & 0xf); + + return ( ((unsigned char)(d - ctype_range[2*desc])) + <= ctype_range[2*desc + 1] ) + && ((desc != _CTYPE_iswblank) || (d & 1)); + } + + if (desc == _CTYPE_iswxdigit) { + return __C_isxdigit(((char) wc)); + } + } + return 0; +} + +#endif + #endif /**********************************************************************/ #ifdef L_towctrans @@ -446,10 +549,26 @@ wint_t towctrans(wint_t wc, wctrans_t desc) #endif -#else +#else /* __WCTYPE_WITH_LOCALE */ +/* Minimal support for C/POSIX locale. */ -#endif +wint_t towctrans(wint_t wc, wctrans_t desc) +{ + if (((unsigned int)(desc - _CTYPE_tolower)) + <= (_CTYPE_toupper - _CTYPE_tolower) + ) { + /* Transliteration is either tolower or toupper. */ + if (((__uwchar_t) wc) <= 0x7f) { + return (desc == _CTYPE_tolower) ? _tolower(wc) : _toupper(wc); + } + } else { + __set_errno(EINVAL); /* Invalid transliteration. */ + } + return wc; +} + +#endif /* __WCTYPE_WITH_LOCALE */ #endif /**********************************************************************/ diff --git a/libc/stdio/Makefile b/libc/stdio/Makefile index 0145b9475..011f3a7f8 100644 --- a/libc/stdio/Makefile +++ b/libc/stdio/Makefile @@ -57,7 +57,8 @@ MOBJ = fclose.o fflush.o fopen.o freopen.o perror.o remove.o \ __fsetlocking.o flockfile.o ftrylockfile.o funlockfile.o \ _stdio_fopen.o _stdio_fread.o _stdio_fwrite.o _stdio_adjpos.o \ _stdio_lseek.o _stdio_init.o \ - _stdio_fsfopen.o _stdio_fdout.o _uintmaxtostr.o _stdio_strerror_r.o + _stdio_fsfopen.o _stdio_fdout.o _uintmaxtostr.o _stdio_strerror_r.o \ + getdelim.o getline.o ctermid.o # ifeq ($(DOLFS),true) # MOBJ += fopen64.o freopen64.o ftello64.o fseeko64.o fsetpos64.o fgetpos64.o @@ -83,8 +84,7 @@ endif MSRC3=scanf.c MOBJ3=scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o vfscanf.o -CSRC=popen.c getdelim.c getline.c tmpfile.c tmpnam.c \ - tmpnam_r.c tempnam.c ctermid.c +CSRC=popen.c tmpfile.c tmpnam.c tmpnam_r.c tempnam.c ifeq ($(USE_OLD_VFPRINTF),true) CSRC += old_vfprintf.c endif diff --git a/libc/stdio/old_vfprintf.c b/libc/stdio/old_vfprintf.c index 036c97c94..945f59a48 100644 --- a/libc/stdio/old_vfprintf.c +++ b/libc/stdio/old_vfprintf.c @@ -143,7 +143,9 @@ /* #define __isdigit(c) (((unsigned int)(c - '0')) < 10) */ +#if defined(__UCLIBC_HAS_FLOATS__) extern size_t _dtostr(FILE * fp, long double x, struct printf_info *info); +#endif enum { @@ -179,7 +181,7 @@ int vfprintf(FILE * __restrict op, register const char * __restrict fmt, va_list ap) { int i, cnt, lval, len; - char *p; + register char *p; const char *fmt0; int preci, width; #define upcase i @@ -325,7 +327,7 @@ int vfprintf(FILE * __restrict op, register const char * __restrict fmt, p = _uintmaxtostr((tmp + sizeof(tmp) - 1), ((lval>1) /* TODO -- longlong/long/int/short/char */ ? va_arg(ap, uintmax_t) - : (uintmax_t) ((long long) /* sign-extend! */ + : (uintmax_t) ((intmax_t) /* sign-extend! */ va_arg(ap, long))), -radix, upcase); diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index 2fac4c93f..fc6dd87bd 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -108,7 +108,7 @@ #define __PA_FLAG_INTMASK \ (__PA_FLAG_CHAR|PA_FLAG_SHORT|__PA_FLAG_INT|PA_FLAG_LONG|PA_FLAG_LONG_LONG) -extern printf_function *_custom_printf_handler[MAX_USER_SPEC]; +extern printf_function _custom_printf_handler[MAX_USER_SPEC]; extern printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC]; extern char *_custom_printf_spec; @@ -177,13 +177,13 @@ enum { */ /* TODO -- Fix the table below to take into account stdint.h. */ -#ifndef LLONG_MAX -#error fix QUAL_CHARS for no long long! Affects 'L', 'j', 'q', 'll'. -#else -#if LLONG_MAX != INTMAX_MAX -#error fix QUAL_CHARS intmax_t entry 'j'! -#endif -#endif +/* #ifndef LLONG_MAX */ +/* #error fix QUAL_CHARS for no long long! Affects 'L', 'j', 'q', 'll'. */ +/* #else */ +/* #if LLONG_MAX != INTMAX_MAX */ +/* #error fix QUAL_CHARS intmax_t entry 'j'! */ +/* #endif */ +/* #endif */ #ifdef PDS #error PDS already defined! @@ -191,6 +191,9 @@ enum { #ifdef SS #error SS already defined! #endif +#ifdef IMS +#error IMS already defined! +#endif #if PTRDIFF_MAX == INT_MAX #define PDS 0 @@ -212,11 +215,21 @@ enum { #error fix QUAL_CHARS size_t entries 'z', 'Z'! #endif +#if INTMAX_MAX == INT_MAX +#define IMS 0 +#elif INTMAX_MAX == LONG_MAX +#define IMS 4 +#elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX) +#define IMS 8 +#else +#error fix QUAL_CHARS ptrdiff_t entry 't'! +#endif + #define QUAL_CHARS { \ /* j:(u)intmax_t z:(s)size_t t:ptrdiff_t \0:int */ \ /* q:long_long Z:(s)size_t */ \ 'h', 'l', 'L', 'j', 'z', 't', 'q', 'Z', 0, \ - 2, 4, 8, 8, SS, PDS, 8, SS, 0, /* TODO -- fix!!! */\ + 2, 4, 8, IMS, SS, PDS, 8, SS, 0, /* TODO -- fix!!! */\ 1, 8 \ } @@ -311,7 +324,7 @@ extern int _ppfs_parsespec(ppfs_t *ppfs); /* parses specifier */ */ size_t parse_printf_format(register const char *template, - size_t n, int *argtypes) + size_t n, register int *argtypes) { ppfs_t ppfs; size_t i; @@ -1021,7 +1034,7 @@ int register_printf_function(int spec, printf_function handler, /**********************************************************************/ #ifdef L__do_one_spec -printf_function *_custom_printf_handler[MAX_USER_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); @@ -1263,6 +1276,7 @@ int _do_one_spec(FILE * __restrict stream, register ppfs_t *ppfs, int *count) #endif /**********************************************************************/ #ifdef L_vsnprintf + #ifdef __STDIO_BUFFERS int vsnprintf(char *__restrict buf, size_t size, const char * __restrict format, va_list arg) @@ -1273,7 +1287,7 @@ int vsnprintf(char *__restrict buf, size_t size, #ifdef __STDIO_GETC_MACRO f.bufgetc = #endif - f.bufrpos = f.bufwpos = f.bufstart = buf; + f.bufpos = f.bufread = f.bufstart = buf; if (size > SIZE_MAX - (size_t) buf) { size = SIZE_MAX - (size_t) buf; @@ -1294,16 +1308,20 @@ int vsnprintf(char *__restrict buf, size_t size, f.filedes = -2; /* for debugging */ f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING); +#ifdef __STDIO_MBSTATE + __INIT_MBSTATE(&(f.state)); +#endif /* __STDIO_MBSTATE */ + #ifdef __STDIO_THREADSAFE __stdio_init_mutex(&f.lock); #endif rv = vfprintf(&f, format, arg); if (size) { - if (f.bufwpos == f.bufend) { - --f.bufwpos; + if (f.bufpos == f.bufend) { + --f.bufpos; } - *f.bufwpos = 0; + *f.bufpos = 0; } return rv; } @@ -1319,10 +1337,11 @@ typedef struct { #define COOKIE ((__snpf_cookie *) cookie) -static ssize_t snpf_write(void *cookie, const char *buf, size_t bufsize) +static ssize_t snpf_write(register void *cookie, const char *buf, + size_t bufsize) { size_t count; - char *p; + register char *p; /* Note: bufsize < SSIZE_MAX because of _stdio_WRITE. */ @@ -1368,6 +1387,10 @@ int vsnprintf(char *__restrict buf, size_t size, f.filedes = -1; /* For debugging. */ f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING); +#ifdef __STDIO_MBSTATE + __INIT_MBSTATE(&(f.state)); +#endif /* __STDIO_MBSTATE */ + #ifdef __STDIO_THREADSAFE __stdio_init_mutex(&f.lock); #endif @@ -1384,6 +1407,7 @@ int vsnprintf(char *__restrict buf, size_t size, #endif /**********************************************************************/ #ifdef L_vdprintf + int vdprintf(int filedes, const char * __restrict format, va_list arg) { FILE f; @@ -1394,7 +1418,7 @@ int vdprintf(int filedes, const char * __restrict format, va_list arg) #ifdef __STDIO_GETC_MACRO f.bufgetc = #endif - f.bufrpos = f.bufwpos = f.bufstart = buf; + f.bufpos = f.bufread = f.bufstart = buf; #ifdef __STDIO_PUTC_MACRO f.bufputc = #endif @@ -1410,6 +1434,10 @@ int vdprintf(int filedes, const char * __restrict format, va_list arg) f.filedes = filedes; f.modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING); +#ifdef __STDIO_MBSTATE + __INIT_MBSTATE(&(f.state)); +#endif /* __STDIO_MBSTATE */ + #ifdef __STDIO_THREADSAFE __stdio_init_mutex(&f.lock); #endif @@ -1418,6 +1446,7 @@ int vdprintf(int filedes, const char * __restrict format, va_list arg) return fflush(&f) ? -1 : rv; } + #endif /**********************************************************************/ #ifdef L_vasprintf @@ -1486,6 +1515,7 @@ int vsprintf(char *__restrict buf, const char * __restrict format, #endif /**********************************************************************/ #ifdef L_fprintf + int fprintf(FILE * __restrict stream, const char * __restrict format, ...) { va_list arg; @@ -1497,6 +1527,7 @@ int fprintf(FILE * __restrict stream, const char * __restrict format, ...) return rv; } + #endif /**********************************************************************/ #ifdef L_snprintf @@ -1521,6 +1552,7 @@ int snprintf(char *__restrict buf, size_t size, #endif /**********************************************************************/ #ifdef L_dprintf + int dprintf(int filedes, const char * __restrict format, ...) { va_list arg; @@ -1532,6 +1564,7 @@ int dprintf(int filedes, const char * __restrict format, ...) return rv; } + #endif /**********************************************************************/ #ifdef L_asprintf @@ -2059,7 +2092,8 @@ void _store_inttype(register void *dest, int desttype, uintmax_t val) /**********************************************************************/ #ifdef L__load_inttype -extern uintmax_t _load_inttype(int desttype, const void *src, int uflag) +extern uintmax_t _load_inttype(int desttype, register const void *src, + int uflag) { if (uflag >= 0) { /* unsigned */ #if LONG_MAX != INT_MAX diff --git a/libc/stdio/scanf.c b/libc/stdio/scanf.c index 7506268b3..6d7a84e57 100644 --- a/libc/stdio/scanf.c +++ b/libc/stdio/scanf.c @@ -31,12 +31,8 @@ * implementation doesn't for the "100ergs" case mentioned above. */ +#define _ISOC99_SOURCE /* for LLONG_MAX primarily... */ #define _GNU_SOURCE -#include <features.h> -#if defined(__UCLIBC__) && !defined(__USE_ISOC99) -#define __USE_ISOC99 -#endif - #define _STDIO_UTILITY #include <stdio.h> #include <stdlib.h> @@ -124,9 +120,13 @@ int vsscanf(__const char *sp, __const char *fmt, va_list ap) string->filedes = -2; /* for debugging */ string->modeflags = (__FLAG_NARROW|__FLAG_READONLY); - string->bufstart = string->bufrpos = (unsigned char *) ((void *) sp); + string->bufstart = string->bufpos = (unsigned char *) ((void *) sp); string->bufgetc = (char *) ((unsigned) -1); +#ifdef __STDIO_MBSTATE + __INIT_MBSTATE(&(string->state)); +#endif /* __STDIO_MBSTATE */ + #ifdef __STDIO_THREADSAFE __stdio_init_mutex(&string->lock); #endif @@ -172,9 +172,11 @@ static int valid_digit(char c, char base) extern unsigned long _stdlib_strto_l(register const char * __restrict str, char ** __restrict endptr, int base, int sflag); +#ifdef LLONG_MAX extern unsigned long long _stdlib_strto_ll(register const char * __restrict str, char ** __restrict endptr, int base, int sflag); +#endif struct scan_cookie { FILE *fp; @@ -205,7 +207,8 @@ static const char spec[] = "%n[csoupxXid"; /* radix[i] <-> spec[i+5] o u p x X i d */ static const char radix[] = { 8, 10, 16, 16, 16, 0, 10 }; -static void init_scan_cookie(struct scan_cookie *sc, FILE *fp) +static void init_scan_cookie(register struct scan_cookie *sc, + register FILE *fp) { sc->fp = fp; sc->nread = 0; @@ -216,7 +219,7 @@ static void init_scan_cookie(struct scan_cookie *sc, FILE *fp) /* TODO -- what about literal '\0' chars in a file??? */ -static int scan_getc_nw(struct scan_cookie *sc) +static int scan_getc_nw(register struct scan_cookie *sc) { if (sc->ungot_flag == 0) { sc->ungot_char = getc(sc->fp); @@ -230,7 +233,7 @@ static int scan_getc_nw(struct scan_cookie *sc) return sc->ungot_char; } -static int scan_getc(struct scan_cookie *sc) +static int scan_getc(register struct scan_cookie *sc) { if (sc->ungot_flag == 0) { sc->ungot_char = getc(sc->fp); @@ -247,7 +250,7 @@ static int scan_getc(struct scan_cookie *sc) return sc->ungot_char; } -static void scan_ungetc(struct scan_cookie *sc) +static void scan_ungetc(register struct scan_cookie *sc) { if (sc->ungot_flag != 0) { assert(sc->width < 0); @@ -262,7 +265,7 @@ static void scan_ungetc(struct scan_cookie *sc) } } -static void kill_scan_cookie(struct scan_cookie *sc) +static void kill_scan_cookie(register struct scan_cookie *sc) { if (sc->ungot_flag) { ungetc(sc->ungot_char,sc->fp); @@ -273,10 +276,7 @@ static void kill_scan_cookie(struct scan_cookie *sc) } } -int vfscanf(fp, format, ap) -FILE *fp; -const char *format; -va_list ap; +int vfscanf(FILE *fp, const char *format, va_list ap) { #ifdef __UCLIBC_HAS_LONG_LONG__ #define STRTO_L_(s,e,b,sf) _stdlib_strto_ll(s,e,b,sf) @@ -294,9 +294,9 @@ va_list ap; #endif UV_TYPE uv; struct scan_cookie sc; - unsigned const char *fmt; + register unsigned const char *fmt; const char *p; - unsigned char *b; + register unsigned char *b; void *vp; int cc, i, cnt; signed char lval; @@ -523,7 +523,7 @@ va_list ap; *((unsigned int *)vp) = (unsigned int)uv; break; #endif - case -1: + case (signed char)(-1): if (usflag) { if (uv > USHRT_MAX) { uv = USHRT_MAX; @@ -535,7 +535,7 @@ va_list ap; } *((unsigned short *)vp) = (unsigned short)uv; break; - case -2: + case (signed char)(-2): if (usflag) { if (uv > UCHAR_MAX) { uv = UCHAR_MAX; diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c index c84731675..a56eff777 100644 --- a/libc/stdio/stdio.c +++ b/libc/stdio/stdio.c @@ -25,6 +25,14 @@ * * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */ +/* Before we include anything, convert L_ctermid to L_ctermid_function + * and undef L_ctermid if defined. This is necessary as L_ctermid is + * a SUSv3 standard macro defined in stdio.h. */ +#ifdef L_ctermid +#define L_ctermid_function +#undef L_ctermid +#endif + #define _ISOC99_SOURCE /* for ULLONG primarily... */ #define _GNU_SOURCE #define _STDIO_UTILITY /* for _stdio_fdout and _uintmaxtostr. */ @@ -72,27 +80,30 @@ /**********************************************************************/ -/* TODO -- make this the default except for bcc with it's broken preproc? */ -#ifdef __UCLIBC__ -#define _stdin stdin -#define _stdout stdout -#define _stderr stderr -#endif /* __UCLIBC__ */ - -/**********************************************************************/ - #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 @@ -175,6 +186,14 @@ void NAME##_unlocked PARAMS #define __STDIO_FILE_INIT_CUSTOM_STREAM(stream) #endif +#ifdef __STDIO_MBSTATE +#define __STDIO_FILE_INIT_MBSTATE \ + { 0, 0 }, +#else +#define __STDIO_FILE_INIT_MBSTATE +#endif + + #ifdef __STDIO_THREADSAFE #define __STDIO_FILE_INIT_THREADSAFE \ 0, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, @@ -191,21 +210,10 @@ void NAME##_unlocked PARAMS __STDIO_FILE_INIT_BUFGETC((buf)) \ __STDIO_FILE_INIT_BUFPUTC((buf)) \ __STDIO_FILE_INIT_CUSTOM_STREAM(stream) \ + __STDIO_FILE_INIT_MBSTATE \ __STDIO_FILE_INIT_THREADSAFE \ } /* TODO: mbstate and builtin buf */ -#ifdef __STDIO_MBSTATE_DATA -extern void _init_mbstate(mbstate_t *dest); - -#define __COMMA_CLEAN_MBSTATE , 0 -#define __COPY_MBSTATE(dest,src) memcpy(dest, src, sizeof(mbstate_t)) -#define __INIT_MBSTATE(dest) _init_mbstate(dest) -#else -#define __COMMA_CLEAN_MBSTATE -#define __COPY_MBSTATE(dest,src) -#define __INIT_MBSTATE(dest) -#endif - #ifdef __STDIO_GLIBC_CUSTOM_STREAMS /* TODO -- what does glibc do for undefined funcs? errno set? */ @@ -237,7 +245,7 @@ extern void _init_mbstate(mbstate_t *dest); /* SUSv2 Legacy function -- need not be reentrant. */ -int getw (register FILE *stream) +int getw(FILE *stream) { int aw[1]; @@ -259,7 +267,7 @@ int getw (register FILE *stream) /* SUSv2 Legacy function -- need not be reentrant. */ -int putw (int w, register FILE *stream) +int putw(int w, FILE *stream) { int aw[1]; @@ -322,6 +330,30 @@ FILE *fopen64(const char * __restrict filename, const char * __restrict mode) #endif /**********************************************************************/ +#ifdef L_ctermid_function + +/* Not required to be reentrant. */ + +char *ctermid(register char *s) +{ + static char sbuf[L_ctermid]; + +#ifdef __BCC__ + /* Currently elks doesn't support /dev/tty. */ + if (!s) { + s = sbuf; + } + *s = 0; + + return s; +#else + /* glibc always returns /dev/tty for linux. */ + return strcpy((s ? s : sbuf), "/dev/tty"); +#endif +} + +#endif +/**********************************************************************/ /* BSD functions */ /**********************************************************************/ #ifdef L_setbuffer @@ -413,7 +445,7 @@ typedef struct { #define COOKIE ((__fmo_cookie *) cookie) -static ssize_t fmo_read(void *cookie, register char *buf, size_t bufsize) +static ssize_t fmo_read(register void *cookie, char *buf, size_t bufsize) { size_t count = COOKIE->len - COOKIE->pos; @@ -442,7 +474,7 @@ static ssize_t fmo_read(void *cookie, register char *buf, size_t bufsize) return bufsize; } -static ssize_t fmo_write(void *cookie, register const char *buf, size_t bufsize) +static ssize_t fmo_write(register void *cookie, const char *buf, size_t bufsize) { size_t count; @@ -499,7 +531,7 @@ static ssize_t fmo_write(void *cookie, register const char *buf, size_t bufsize) } /* glibc doesn't allow seeking, but it has in-buffer seeks... we don't. */ -static int fmo_seek(void *cookie, __offmax_t *pos, int whence) +static int fmo_seek(register void *cookie, __offmax_t *pos, int whence) { __offmax_t p = *pos; @@ -522,7 +554,7 @@ static int fmo_seek(void *cookie, __offmax_t *pos, int whence) return 0; } -static int fmo_close(void *cookie) +static int fmo_close(register void *cookie) { if (COOKIE->dynbuf) { free(COOKIE->buf); @@ -545,7 +577,7 @@ static const cookie_io_functions_t _fmo_io_funcs = { FILE *fmemopen(void *s, size_t len, const char *modes) { FILE *fp; - __fmo_cookie *cookie; + register __fmo_cookie *cookie; size_t i; if ((cookie = malloc(sizeof(__fmo_cookie))) != NULL) { @@ -614,9 +646,9 @@ typedef struct { /* { */ /* } */ -static ssize_t oms_write(void *cookie, const char *buf, size_t bufsize) +static ssize_t oms_write(register void *cookie, const char *buf, size_t bufsize) { - char *newbuf; + register char *newbuf; size_t count; /* Note: we already know bufsize < SSIZE_MAX... */ @@ -649,10 +681,10 @@ static ssize_t oms_write(void *cookie, const char *buf, size_t bufsize) return bufsize; } -static int oms_seek(void *cookie, __offmax_t *pos, int whence) +static int oms_seek(register void *cookie, __offmax_t *pos, int whence) { __offmax_t p = *pos; - char *buf; + register char *buf; size_t leastlen; /* Note: fseek already checks that whence is legal, so don't check here @@ -713,8 +745,8 @@ static const cookie_io_functions_t _oms_io_funcs = { FILE *open_memstream(char **__restrict bufloc, size_t *__restrict sizeloc) { - __oms_cookie *cookie; - FILE *fp; + register __oms_cookie *cookie; + register FILE *fp; if ((cookie = malloc(sizeof(__oms_cookie))) != NULL) { if ((cookie->buf = malloc(cookie->len = BUFSIZ)) == NULL) { @@ -767,8 +799,8 @@ FILE *open_memstream(char **__restrict bufloc, size_t *__restrict sizeloc) #ifndef __BCC__ -FILE *fopencookie (void * __restrict cookie, const char * __restrict mode, - cookie_io_functions_t io_functions) +FILE *fopencookie(void * __restrict cookie, const char * __restrict mode, + cookie_io_functions_t io_functions) { FILE *stream; int fd; @@ -804,10 +836,10 @@ FILE *fopencookie (void * __restrict cookie, const char * __restrict mode, * instead. */ -FILE *_fopencookie (void * __restrict cookie, const char * __restrict mode, - cookie_io_functions_t *io_functions) +FILE *_fopencookie(void * __restrict cookie, const char * __restrict mode, + register cookie_io_functions_t *io_functions) { - FILE *stream; + register FILE *stream; if ((stream = _stdio_fopen("/dev/null", mode, NULL, -1)) != NULL) { int fd = stream->filedes; @@ -929,7 +961,7 @@ void __fpurge(register FILE * __restrict stream) #ifdef __STDIO_GETC_MACRO stream->bufgetc = /* Must disable getc. */ #endif - stream->bufwpos = stream->bufrpos = stream->bufstart; /* Reset pointers. */ + stream->bufpos = stream->bufread = stream->bufstart; /* Reset pointers. */ #endif /* __STDIO_BUFFERS */ /* Reset r/w flags and clear ungots. */ stream->modeflags &= ~(__FLAG_READING|__FLAG_WRITING|__MASK_UNGOT); @@ -942,19 +974,22 @@ void __fpurge(register FILE * __restrict stream) /* Not reentrant. */ #ifdef __STDIO_WIDE -#warning TODO -- implement __fpending for wide streams! */ -#else /* __STDIO_WIDE */ +#warning unlike the glibc version, this __fpending returns bytes in buffer for wide streams too! + +link_warning(__fpending, "This version of __fpending returns bytes remaining in buffer for both narrow and wide streams. glibc's version returns wide chars in buffer for the wide stream case.") + +#endif /* __STDIO_WIDE */ + size_t __fpending(register FILE * __restrict stream) { #ifdef __STDIO_BUFFERS /* TODO -- should we check this? should we set errno? just assert? */ return (stream->modeflags & (__FLAG_READING|__FLAG_READONLY)) - ? 0 : (stream->bufwpos - stream->bufstart); + ? 0 : (stream->bufpos - stream->bufstart); #else /* __STDIO_BUFFERS */ return 0; #endif /* __STDIO_BUFFERS */ } -#endif /* __STDIO_WIDE */ #endif /**********************************************************************/ @@ -1039,6 +1074,64 @@ void funlockfile(FILE *stream) #endif /**********************************************************************/ +#ifdef L_getline + +ssize_t getline(char **__restrict lineptr, size_t *__restrict n, + FILE *__restrict stream) +{ + return __getdelim(lineptr, n, '\n', stream); +} + +#endif +/**********************************************************************/ +#ifdef L_getdelim + +weak_alias(__getdelim,getdelim); + +#define GETDELIM_GROWBY 64 + +ssize_t __getdelim(char **__restrict lineptr, size_t *__restrict n, + int delimiter, register FILE *__restrict stream) +{ + register char *buf; + size_t pos; + int c; + + if (!lineptr || !n || !stream) { /* Be compatable with glibc... even */ + __set_errno(EINVAL); /* though I think we should assert here */ + return -1; /* if anything. */ + } + + if (!(buf = *lineptr)) { /* If passed NULL for buffer, */ + *n = 0; /* ignore value passed and treat size as 0. */ + } + pos = 1; /* Make sure we have space for terminating nul. */ + + __STDIO_THREADLOCK(stream); + + do { + if (pos >= *n) { + if (!(buf = realloc(buf, *n + GETDELIM_GROWBY))) { + __set_errno(ENOMEM); /* Emulate old uClibc implementation. */ + break; + } + *n += GETDELIM_GROWBY; + *lineptr = buf; + } + } while (((c = getc(stream)) != EOF) && ((buf[pos++ - 1] = c) != delimiter)); + + __STDIO_THREADUNLOCK(stream); + + if (--pos) { + buf[pos] = 0; + return pos; + } + + return -1; /* Either initial realloc failed or first read was EOF. */ +} + +#endif +/**********************************************************************/ /* my extension functions */ /**********************************************************************/ #ifdef L__stdio_fsfopen @@ -1079,11 +1172,9 @@ FILE *_stdio_fsfopen(const char * __restrict filename, * then the file position is treated as unknown. */ - /* Internal function -- not reentrant. */ -int _stdio_adjpos(register FILE * __restrict stream, - register __offmax_t *pos) +int _stdio_adjpos(register FILE * __restrict stream, register __offmax_t *pos) { __offmax_t r; int cor = stream->modeflags & __MASK_UNGOT; /* handle ungots */ @@ -1092,18 +1183,18 @@ int _stdio_adjpos(register FILE * __restrict stream, /* Assumed narrow stream so correct if wide. */ if (cor && (stream->modeflags & __FLAG_WIDE)) { cor = cor - 1 + stream->ungot_width[0]; - if ((stream->ungot_width[0] == 0) /* don't know byte count or */ - || ((stream->modeflags & __MASK_UNGOT) > 1)) { /* app case */ - return -1; + if (((stream->modeflags & __MASK_UNGOT) > 1) || stream->ungot[1]) { + return -1; /* App did ungetwc, so position is indeterminate. */ } + assert(stream->ungot_width[0] > 0); } #endif /* __STDIO_WIDE */ #ifdef __STDIO_BUFFERS if (stream->modeflags & __FLAG_WRITING) { - cor -= (stream->bufwpos - stream->bufstart); /* pending writes */ + cor -= (stream->bufpos - stream->bufstart); /* pending writes */ } if (stream->modeflags & __FLAG_READING) { - cor += (stream->bufwpos - stream->bufrpos); /* extra's read */ + cor += (stream->bufread - stream->bufpos); /* extra's read */ } #endif /* __STDIO_BUFFERS */ @@ -1122,7 +1213,7 @@ int _stdio_adjpos(register FILE * __restrict stream, /* Internal function -- not reentrant. */ -int _stdio_lseek(FILE *stream, __offmax_t *pos, int whence) +int _stdio_lseek(register FILE *stream, register __offmax_t *pos, int whence) { __offmax_t res; @@ -1152,7 +1243,7 @@ int _stdio_lseek(FILE *stream, __offmax_t *pos, int whence) /* Unlike write, it's ok for read to return fewer than bufsize, since * we may not need all of them. */ -static ssize_t _stdio_READ(FILE *stream, void *buf, size_t bufsize) +static ssize_t _stdio_READ(register FILE *stream, unsigned char *buf, size_t bufsize) { ssize_t rv; @@ -1192,8 +1283,7 @@ static ssize_t _stdio_READ(FILE *stream, void *buf, size_t bufsize) /* Internal function -- not reentrant. */ -size_t _stdio_fread(unsigned char *buffer, size_t bytes, - register FILE *stream) +size_t _stdio_fread(unsigned char *buffer, size_t bytes, register FILE *stream) { __stdio_validate_FILE(stream); /* debugging only */ @@ -1233,12 +1323,15 @@ size_t _stdio_fread(unsigned char *buffer, size_t bytes, if (stream->modeflags & __MASK_BUFMODE) { /* If the stream is readable and not fully buffered, we must first * flush all line buffered output streams. Do this before the - * error check as this may be a read/write line-buffered stream. */ - fflush((FILE *) &_stdio_openlist); /* Uses an implementation hack!!! */ + * error check as this may be a read/write line-buffered stream. + * Note: Uses an implementation-specific hack!!! */ + fflush_unlocked((FILE *) &_stdio_openlist); } #ifdef __STDIO_AUTO_RW_TRANSITION - if ((stream->modeflags & __FLAG_WRITING) && (fflush(stream) == EOF)) { + if ((stream->modeflags & __FLAG_WRITING) + && (fflush_unlocked(stream) == EOF) + ) { return 0; /* Fail if we need to fflush but can't. */ } #endif /* __STDIO_AUTO_RW_TRANSITION */ @@ -1260,23 +1353,23 @@ size_t _stdio_fread(unsigned char *buffer, size_t bytes, /* Now get any other needed chars from the buffer or the file. */ FROM_BUF: - while (bytes && (stream->bufrpos < stream->bufwpos)) { + while (bytes && (stream->bufpos < stream->bufread)) { --bytes; - *p++ = *stream->bufrpos++; + *p++ = *stream->bufpos++; } if (bytes > 0) { ssize_t len; /* The buffer is exhausted, but we still need chars. */ - stream->bufrpos = stream->bufwpos = stream->bufstart; + stream->bufpos = stream->bufread = stream->bufstart; - if (bytes <= stream->bufend - stream->bufwpos) { + if (bytes <= stream->bufend - stream->bufread) { /* We have sufficient space in the buffer. */ - len = _stdio_READ(stream, stream->bufwpos, - stream->bufend - stream->bufwpos); + len = _stdio_READ(stream, stream->bufread, + stream->bufend - stream->bufread); if (len > 0) { - stream->bufwpos += len; + stream->bufread += len; goto FROM_BUF; } } else { @@ -1293,7 +1386,7 @@ size_t _stdio_fread(unsigned char *buffer, size_t bytes, #ifdef __STDIO_GETC_MACRO if (!(stream->modeflags & (__FLAG_WIDE|__MASK_UNGOT|__MASK_BUFMODE))) { - stream->bufgetc = stream->bufwpos; /* Enable getc macro. */ + stream->bufgetc = stream->bufread; /* Enable getc macro. */ } #endif @@ -1377,7 +1470,8 @@ size_t _stdio_fread(unsigned char *buffer, size_t bytes, *deals correctly with bufsize > SSIZE_MAX... not much on an issue on linux * but definitly could be on Elks. Also on Elks, always loops for EINTR.. * Returns number of bytes written, so a short write indicates an error */ -static size_t _stdio_WRITE(FILE *stream, const void *buf, size_t bufsize) +static size_t _stdio_WRITE(register FILE *stream, + register const unsigned char *buf, size_t bufsize) { size_t todo; ssize_t rv, stodo; @@ -1412,7 +1506,7 @@ static size_t _stdio_WRITE(FILE *stream, const void *buf, size_t bufsize) /* Internal function -- not reentrant. */ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes, - register FILE *stream) + register FILE *stream) { #ifdef __STDIO_BUFFERS register const unsigned char *p; @@ -1438,7 +1532,7 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes, #ifdef __STDIO_AUTO_RW_TRANSITION /* If reading, deal with ungots and read-buffered chars. */ if (stream->modeflags & __FLAG_READING) { - if (((stream->bufrpos < stream->bufwpos) + 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? */ @@ -1456,7 +1550,7 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes, #ifdef __STDIO_GETC_MACRO stream->bufgetc = #endif /* __STDIO_GETC_MACRO */ - stream->bufrpos = stream->bufwpos = stream->bufstart; + stream->bufpos = stream->bufread = stream->bufstart; } #endif @@ -1475,7 +1569,7 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes, if (!buffer) { /* fflush the stream */ FFLUSH: { - size_t count = stream->bufwpos - stream->bufstart; + size_t count = stream->bufpos - stream->bufstart; p = stream->bufstart; if (stream->filedes == -2) { /* TODO -- document this hack! */ @@ -1489,22 +1583,22 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes, count -= rv; } - stream->bufwpos = stream->bufstart; + stream->bufpos = stream->bufstart; while (count) { - *stream->bufwpos++ = *p++; + *stream->bufpos++ = *p++; --count; } if (!buffer) { /* fflush case... */ __stdio_validate_FILE(stream); /* debugging only */ - return stream->bufwpos - stream->bufstart; + return stream->bufpos - stream->bufstart; } } } #if 1 /* TODO: If the stream is buffered, we may be able to omit. */ - if ((stream->bufwpos == stream->bufstart) /* buf empty */ + if ((stream->bufpos == stream->bufstart) /* buf empty */ && (stream->bufend - stream->bufstart <= bytes) /* fills */ && (stream->filedes != -2)) { /* not strinf fake file */ /* so want to do a direct write of supplied buffer */ @@ -1517,7 +1611,7 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes, #endif /* otherwise buffer not empty and/or data fits */ { - size_t count = stream->bufend - stream->bufwpos; + size_t count = stream->bufend - stream->bufpos; p = buffer; if (count > bytes) { @@ -1526,7 +1620,7 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes, bytes -= count; while (count) { - *stream->bufwpos++ = *buffer++; + *stream->bufpos++ = *buffer++; --count; } @@ -1615,10 +1709,12 @@ void __stdio_validate_FILE(FILE *stream) __STDIO_THREADLOCK(stream); #ifdef __STDIO_BUFFERS - assert(stream->bufstart <= stream->bufrpos); - assert(stream->bufrpos <= stream->bufwpos); - assert(stream->bufwpos <= stream->bufend); - assert(stream->bufwpos <= stream->bufend); + assert(stream->bufstart <= stream->bufread); + if (stream->modeflags & (__FLAG_READING)) { + assert(stream->bufpos <= stream->bufread); + } + assert(stream->bufread <= stream->bufend); + assert(stream->bufpos <= stream->bufend); if ((stream->modeflags & __MASK_BUFMODE) == __FLAG_NBF) { assert(stream->bufstart == stream->bufend); } @@ -1637,7 +1733,7 @@ void __stdio_validate_FILE(FILE *stream) #endif #ifdef __STDIO_GETC_MACRO assert(stream->bufstart <= stream->bufgetc); - assert(stream->bufgetc <= stream->bufwpos); + assert(stream->bufgetc <= stream->bufread); if (stream->bufstart < stream->bufgetc) { assert(stream->modeflags & (__FLAG_READING)); assert(!(stream->modeflags @@ -1693,9 +1789,9 @@ static FILE _stdio_streams[] = { 2, 0, 0, 0 ) }; -FILE *_stdin = _stdio_streams + 0; -FILE *_stdout = _stdio_streams + 1; -FILE *_stderr = _stdio_streams + 2; +FILE *stdin = _stdio_streams + 0; +FILE *stdout = _stdio_streams + 1; +FILE *stderr = _stdio_streams + 2; #if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) @@ -1725,7 +1821,7 @@ void __stdio_init_mutex(pthread_mutex_t *m) void _stdio_term(void) { #if defined(__STDIO_GLIBC_CUSTOM_STREAMS) || defined(__STDIO_THREADSAFE) - FILE *ptr; + register FILE *ptr; #endif /* TODO: if called via a signal handler for a signal mid _stdio_fwrite, @@ -1746,7 +1842,7 @@ void _stdio_term(void) /* TODO -- set an alarm and flush each file "by hand"? to avoid blocking? */ /* Now flush all streams. */ - fflush(NULL); + fflush_unlocked(NULL); #endif /* __STDIO_BUFFERS */ /* Next close all custom streams in case of any special cleanup, but @@ -1765,7 +1861,7 @@ void _stdio_term(void) /* TODO: "unbuffer" files like glibc does? Inconsistent with * custom stream handling above, but that's necessary to deal * with special user-defined close behavior. */ - stream->bufwpos = stream->bufrpos = stream->bufend + stream->bufpos = stream->bufread = stream->bufend #ifdef __STDIO_GETC_MACRO = stream->bufgetc #endif @@ -1867,8 +1963,8 @@ int fclose(register FILE *stream) #ifdef __STDIO_BUFFERS if (stream->modeflags & __FLAG_WRITING) { - rv = fflush(stream); /* Write any pending buffered chars. */ - } /* Also disables putc macro if used. */ + rv = fflush_unlocked(stream); /* Write any pending buffered chars. */ + } /* Also disables putc macro if used. */ #ifdef __STDIO_GETC_MACRO /* Not necessary after fflush, but always do this to reduce size. */ @@ -2097,8 +2193,8 @@ FILE *fopen(const char * __restrict filename, const char * __restrict mode) /* Internal function -- reentrant (locks open file list) */ FILE *_stdio_fopen(const char * __restrict filename, - register const char * __restrict mode, - register FILE * __restrict stream, int filedes) + register const char * __restrict mode, + register FILE * __restrict stream, int filedes) { __mode_t open_mode; @@ -2230,7 +2326,7 @@ FILE *_stdio_fopen(const char * __restrict filename, #ifdef __STDIO_PUTC_MACRO stream->bufputc = #endif - stream->bufwpos = stream->bufrpos = stream->bufstart; + stream->bufpos = stream->bufread = stream->bufstart; #endif /* __STDIO_BUFFERS */ #ifdef __STDIO_GLIBC_CUSTOM_STREAMS @@ -2241,6 +2337,10 @@ FILE *_stdio_fopen(const char * __restrict filename, stream->gcs.close = _cs_close; #endif /* __STDIO_GLIBC_CUSTOM_STREAMS */ +#ifdef __STDIO_MBSTATE + __INIT_MBSTATE(&(stream->state)); +#endif /* __STDIO_MBSTATE */ + #ifdef __STDIO_THREADSAFE __stdio_init_mutex(&stream->lock); #endif /* __STDIO_THREADSAFE */ @@ -2282,7 +2382,7 @@ FILE *freopen(const char * __restrict filename, const char * __restrict mode, * TODO: Apparently linux allows setting append mode. Implement? */ unsigned short dynmode; - FILE *fp; + register FILE *fp; __STDIO_THREADLOCK(stream); @@ -2290,7 +2390,7 @@ FILE *freopen(const char * __restrict filename, const char * __restrict mode, /* This also removes the stream for the open file list. */ dynmode = #ifdef __STDIO_BUFFERS - // __MASK_BUFMODE | /* TODO: check */ + /* __MASK_BUFMODE | */ /* TODO: check */ #endif /* __STDIO_BUFFERS */ (stream->modeflags & (__FLAG_FREEBUF|__FLAG_FREEFILE)); @@ -2310,12 +2410,12 @@ FILE *freopen(const char * __restrict filename, const char * __restrict mode, /* Reentrant. */ -/* TODO -- is it collecting the common work (40 bytes) into a function? */ +/* TODO -- is it worth collecting the common work (40 bytes) in a function? */ FILE *freopen64(const char * __restrict filename, const char * __restrict mode, register FILE * __restrict stream) { unsigned short dynmode; - FILE *fp; + register FILE *fp; __STDIO_THREADLOCK(stream); @@ -2323,7 +2423,7 @@ FILE *freopen64(const char * __restrict filename, const char * __restrict mode, /* This also removes the stream for the open file list. */ dynmode = #ifdef __STDIO_BUFFERS - // __MASK_BUFMODE | /* TODO: check */ + /* __MASK_BUFMODE | */ /* TODO: check */ #endif /* __STDIO_BUFFERS */ (stream->modeflags & (__FLAG_FREEBUF|__FLAG_FREEFILE)); @@ -2448,7 +2548,7 @@ int setvbuf(register FILE * __restrict stream, register char * __restrict buf, #ifdef __STDIO_PUTC_MACRO stream->bufputc = #endif - stream->bufwpos = stream->bufrpos = stream->bufstart = buf; + stream->bufpos = stream->bufread = stream->bufstart = buf; stream->bufend = buf + size; } @@ -2603,9 +2703,9 @@ UNLOCKED(int,getc,(register FILE *stream),(stream)) /* Reentrancy handled by UNLOCKED() macro. */ -UNLOCKED_STREAM(int,getchar,(void),(),_stdin) +UNLOCKED_STREAM(int,getchar,(void),(),stdin) { - register FILE *stream = _stdin; /* This helps bcc optimize. */ + register FILE *stream = stdin; /* This helps bcc optimize. */ return __GETC(stream); } @@ -2620,7 +2720,7 @@ link_warning(gets, "the 'gets' function is dangerous and should not be used.") char *gets(char *s) /* WARNING!!! UNSAFE FUNCTION!!! */ { - register FILE *stream = _stdin; /* This helps bcc optimize. */ + register FILE *stream = stdin; /* This helps bcc optimize. */ register char *p = s; int c; @@ -2628,7 +2728,7 @@ char *gets(char *s) /* WARNING!!! UNSAFE FUNCTION!!! */ /* Note: don't worry about performance here... this shouldn't be used! * Therefore, force actual function call. */ - while (((c = (*getc)(stream)) != EOF) && ((*p = c) != '\n')) { + while (((c = (getc_unlocked)(stream)) != EOF) && ((*p = c) != '\n')) { ++p; } if ((c == EOF) || (s == p)) { @@ -2661,9 +2761,9 @@ UNLOCKED(int,putc,(int c, register FILE *stream),(c,stream)) /* Reentrancy handled by UNLOCKED() macro. */ -UNLOCKED_STREAM(int,putchar,(int c),(c),_stdout) +UNLOCKED_STREAM(int,putchar,(int c),(c),stdout) { - register FILE *stream = _stdout; /* This helps bcc optimize. */ + register FILE *stream = stdout; /* This helps bcc optimize. */ return __PUTC(c, stream); } @@ -2676,17 +2776,17 @@ UNLOCKED_STREAM(int,putchar,(int c),(c),_stdout) int puts(register const char *s) { - register FILE *stream = _stdout; /* This helps bcc optimize. */ + register FILE *stream = stdout; /* This helps bcc optimize. */ int n; __STDIO_THREADLOCK(stream); - n = fputs(s,stream) + 1; + n = fputs_unlocked(s,stream) + 1; if ( #if 1 - fputc('\n',stream) + fputc_unlocked('\n',stream) #else - fputs("\n",stream) + fputs_unlocked("\n",stream) #endif == EOF) { n = EOF; @@ -2739,7 +2839,7 @@ int ungetc(int c, register FILE *stream) #ifdef __STDIO_BUFFERS /* TODO: shouldn't allow writing??? */ if (stream->modeflags & __FLAG_WRITING) { - fflush(stream); /* Commit any write-buffered chars. */ + fflush_unlocked(stream); /* Commit any write-buffered chars. */ } #endif /* __STDIO_BUFFERS */ @@ -2838,21 +2938,22 @@ UNLOCKED(size_t,fwrite, int fgetpos64(FILE * __restrict stream, register fpos64_t * __restrict pos) { +#ifdef __STDIO_MBSTATE int retval; __STDIO_THREADLOCK(stream); retval = ((pos != NULL) && ((pos->__pos = ftello64(stream)) >= 0)) - ? ( -#ifdef __STDIO_MBSTATE_DATA - __COPY_MBSTATE(&(pos->__mbstate), &(stream->mbstate)), -#endif /* __STDIO_MBSTATE_DATA */ - 0) + ? (__COPY_MBSTATE(&(pos->__mbstate), &(stream->state)), 0) : (__set_errno(EINVAL), -1); __STDIO_THREADUNLOCK(stream); return retval; +#else + return ((pos != NULL) && ((pos->__pos = ftello64(stream)) >= 0)) + ? 0 : (__set_errno(EINVAL), -1); +#endif } #ifndef L_fgetpos64 @@ -2864,7 +2965,7 @@ int fgetpos64(FILE * __restrict stream, register fpos64_t * __restrict pos) #endif /**********************************************************************/ #ifdef L_fseek -strong_alias(fseek, fseeko); +strong_alias(fseek,fseeko); #endif #if defined(L_fseek) && defined(__STDIO_LARGE_FILES) @@ -2907,7 +3008,7 @@ int fseeko64(register FILE *stream, __off64_t offset, int whence) if ( #ifdef __STDIO_BUFFERS /* First commit any pending buffered writes. */ - ((stream->modeflags & __FLAG_WRITING) && fflush(stream)) || + ((stream->modeflags & __FLAG_WRITING) && fflush_unlocked(stream)) || #endif /* __STDIO_BUFFERS */ ((whence == SEEK_CUR) && (_stdio_adjpos(stream, pos) < 0)) || (_stdio_lseek(stream, pos, whence) < 0) @@ -2921,16 +3022,16 @@ int fseeko64(register FILE *stream, __off64_t offset, int whence) #ifdef __STDIO_GETC_MACRO stream->bufgetc = /* Must disable getc. */ #endif - stream->bufwpos = stream->bufrpos = stream->bufstart; + stream->bufpos = stream->bufread = stream->bufstart; #endif /* __STDIO_BUFFERS */ stream->modeflags &= ~(__FLAG_READING|__FLAG_WRITING|__FLAG_EOF|__MASK_UNGOT); -#ifdef __STDIO_MBSTATE_DATA +#ifdef __STDIO_MBSTATE /* TODO: don't clear state if don't move? */ - __INIT_MBSTATE(&(stream->mbstate)); -#endif /* __STDIO_MBSTATE_DATA */ + __INIT_MBSTATE(&(stream->state)); +#endif /* __STDIO_MBSTATE */ __stdio_validate_FILE(stream); /* debugging only */ retval = 0; @@ -2968,18 +3069,23 @@ int fsetpos64(FILE *stream, register const fpos64_t *pos) __set_errno(EINVAL); return EOF; } -#ifdef __STDIO_MBSTATE_DATA -#error unimplemented and non-reentrant besides! +#ifdef __STDIO_MBSTATE { int retval; + + __STDIO_THREADLOCK(stream); + if ((retval = fseeko64(stream, pos->__pos, SEEK_SET)) == 0) { - __COPY_MBSTATE(&(stream->mbstate), &(pos->__mbstate)); + __COPY_MBSTATE(&(stream->state), &(pos->__mbstate)); } + + __STDIO_THREADUNLOCK(stream); + return retval; } -#else /* __STDIO_MBSTATE_DATA */ +#else /* __STDIO_MBSTATE */ return fseeko64(stream, pos->__pos, SEEK_SET); -#endif /* __STDIO_MBSTATE_DATA */ +#endif /* __STDIO_MBSTATE */ } #ifndef L_fsetpos64 @@ -2991,7 +3097,7 @@ int fsetpos64(FILE *stream, register const fpos64_t *pos) #endif /**********************************************************************/ #ifdef L_ftell -strong_alias(ftell, ftello); +strong_alias(ftell,ftello); #endif #if defined(L_ftell) && defined(__STDIO_LARGE_FILES) @@ -3042,6 +3148,10 @@ void rewind(register FILE *stream) __CLEARERR(stream); /* Clear errors first and then seek */ fseek(stream, 0L, SEEK_SET); /* in case there is an error seeking. */ +#ifdef __STDIO_MBSTATE + /* TODO: Is it correct to re-init the stream's state? I think so... */ + __INIT_MBSTATE(&(stream->state)); +#endif /* __STDIO_MBSTATE */ __STDIO_THREADUNLOCK(stream); } @@ -3103,11 +3213,11 @@ void perror(register const char *s) #if 1 #ifdef __STDIO_PRINTF_M_SPEC - fprintf(_stderr, "%s%s%m\n", s, sep); /* Use the gnu %m feature. */ + fprintf(stderr, "%s%s%m\n", s, sep); /* Use the gnu %m feature. */ #else { char buf[64]; - fprintf(_stderr, "%s%s%s\n", s, sep, + fprintf(stderr, "%s%s%s\n", s, sep, _stdio_strerror_r(errno, buf, sizeof(buf))); } #endif @@ -3135,7 +3245,7 @@ void perror(register const char *s) void _stdio_fdout(int fd, ...) { va_list arg; - const char *p; + register const char *p; va_start(arg, fd); while ((p = va_arg(arg, const char *)) != NULL) { @@ -3154,8 +3264,8 @@ void _stdio_fdout(int fd, ...) #define INTERNAL_DIV_MOD #endif -char *_uintmaxtostr(char * __restrict bufend, uintmax_t uval, - int base, __UIM_CASE alphacase) +char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval, + int base, __UIM_CASE alphacase) { int negative; unsigned int digit; @@ -3231,7 +3341,7 @@ char *_uintmaxtostr(char * __restrict bufend, uintmax_t uval, static const char unknown[] = "Unknown error"; -char *_stdio_strerror_r(int err, char *buf, size_t buflen) +char *_stdio_strerror_r(int err, register char *buf, size_t buflen) { int errsave; diff --git a/libc/stdlib/stdlib.c b/libc/stdlib/stdlib.c index 4c9e8f039..689fdeb3b 100644 --- a/libc/stdlib/stdlib.c +++ b/libc/stdlib/stdlib.c @@ -638,7 +638,17 @@ void ssort (void *base, #define UTF_8_MAX_LEN 3 #endif +#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 #endif @@ -647,16 +657,20 @@ void ssort (void *base, size_t _stdlib_mb_cur_max(void) { +#ifdef __CTYPE_HAS_UTF_8_LOCALES return __global_locale.mb_cur_max; +#else +#ifdef __CTYPE_HAS_8_BIT_LOCALES +#warning need to change this when/if transliteration is implemented +#endif + return 1; +#endif } #endif /**********************************************************************/ #ifdef L_mblen -#warning implement __CTYPE_HAS_UTF_8_LOCALES! -#define __CTYPE_HAS_UTF_8_LOCALES - int mblen(register const char *s, size_t n) { static mbstate_t state; @@ -683,9 +697,6 @@ int mblen(register const char *s, size_t n) /**********************************************************************/ #ifdef L_mbtowc -#warning implement __CTYPE_HAS_UTF_8_LOCALES! -#define __CTYPE_HAS_UTF_8_LOCALES - int mbtowc(wchar_t *__restrict pwc, register const char *__restrict s, size_t n) { static mbstate_t state; @@ -712,9 +723,6 @@ int mbtowc(wchar_t *__restrict pwc, register const char *__restrict s, size_t n) /**********************************************************************/ #ifdef L_wctomb -#warning implement __CTYPE_HAS_UTF_8_LOCALES! -#define __CTYPE_HAS_UTF_8_LOCALES - /* Note: We completely ignore state in all currently supported conversions. */ int wctomb(register char *__restrict s, wchar_t swc) diff --git a/libc/string/Makefile b/libc/string/Makefile index 2cd133472..f19782c81 100644 --- a/libc/string/Makefile +++ b/libc/string/Makefile @@ -38,6 +38,8 @@ MOBJW2= wcscasecmp.o wcscat.o wcschrnul.o wcschr.o wcscmp.o wcscpy.o wcscspn.o \ wcsnlen.o wcspbrk.o wcsrchr.o wcsspn.o wcsstr.o wcstok.o wmemchr.o \ wmemcmp.o wmemcpy.o wmemmove.o wmempcpy.o wmemset.o +# wcscoll wcsxfrm wcpcpy wcpncpy + MSRC1=strsignal.c MOBJ1=strsignal.o psignal.o diff --git a/libc/string/wstring.c b/libc/string/wstring.c index 4c619ad36..59300f164 100644 --- a/libc/string/wstring.c +++ b/libc/string/wstring.c @@ -293,7 +293,7 @@ int Wmemcmp(const Wvoid *s1, const Wvoid *s2, size_t n) #ifndef L_wcscmp #warning implement strcoll and remove weak alias (or enable for C locale only) -weak_alias(strcmp, strcoll); +weak_alias(strcmp,strcoll); #endif int Wstrcmp(register const Wchar *s1, register const Wchar *s2) diff --git a/libc/sysdeps/linux/common/bits/uClibc_locale.h b/libc/sysdeps/linux/common/bits/uClibc_locale.h index 2a35d38ec..a9cd39f2f 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_locale.h +++ b/libc/sysdeps/linux/common/bits/uClibc_locale.h @@ -63,11 +63,7 @@ #define __LC_ALL 6 /**********************************************************************/ -#if defined(_LIBC) && !defined(__LOCALE_C_ONLY) - -#include <stddef.h> -#include <stdint.h> -#include <bits/uClibc_locale_data.h> +#ifdef _LIBC /* TODO: This really needs to be somewhere else... */ #include <limits.h> @@ -89,6 +85,14 @@ typedef uintmax_t __uwchar_t; #error Can not determine an appropriate type for __uwchar_t! #endif +#endif + +/**********************************************************************/ +#if defined(_LIBC) && !defined(__LOCALE_C_ONLY) + +#include <stddef.h> +#include <stdint.h> +#include <bits/uClibc_locale_data.h> extern void _locale_set(const unsigned char *p); diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h b/libc/sysdeps/linux/common/bits/uClibc_stdio.h index 1a559bd9c..16a7da876 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h +++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h @@ -40,6 +40,10 @@ #define __STDIO_LARGE_FILES #endif /* __UCLIBC_HAVE_LFS__ */ +#ifdef __UCLIBC_HAS_WCHAR__ +#define __STDIO_WIDE +#endif + /* Make sure defines related to large files are consistent. */ #ifdef _LIBC @@ -67,9 +71,14 @@ /* These are the stdio configuration options. Keep them here until uClibc's configuration process gets reworked. */ -/* #define __STDIO_WIDE */ #ifdef __STDIO_WIDE -typedef int __wchar_t; /* TODO: temporary, as not currently uClibc */ +#define __need_wchar_t +#include <stddef.h> +/* Note: we don't really need mbstate for 8-bit locales. We do for UTF-8. + * For now, always use it. */ +#define __STDIO_MBSTATE +#define __need_mbstate_t +#include <wchar.h> #endif #define __STDIO_BUFFERS @@ -163,13 +172,19 @@ typedef int __wchar_t; /* TODO: temporary, as not currently uClibc */ typedef struct { __off_t __pos; -/* __mbstate_t __state; */ +#ifdef __STDIO_MBSTATE + __mbstate_t __mbstate; +#endif } __stdio_fpos_t; +#ifdef __STDIO_LARGE_FILES typedef struct { __off64_t __pos; -/* __mbstate_t __state; */ +#ifdef __STDIO_MBSTATE + __mbstate_t __mbstate; +#endif } __stdio_fpos64_t; +#endif /**********************************************************************/ @@ -229,8 +244,9 @@ struct __stdio_file_struct { unsigned short modeflags; /* There could be a hole here, but modeflags is used most.*/ #ifdef __STDIO_WIDE + /* TOOD - ungot_width could be combined with ungot. But what about hole? */ unsigned char ungot_width[2]; - __wchar_t ungot[2]; + wchar_t ungot[2]; #else /* __STDIO_WIDE */ unsigned char ungot[2]; #endif /* __STDIO_WIDE */ @@ -241,8 +257,8 @@ struct __stdio_file_struct { #ifdef __STDIO_BUFFERS unsigned char *bufstart; /* pointer to buffer */ unsigned char *bufend; /* pointer to 1 past end of buffer */ - unsigned char *bufwpos; /* pointer to 1 past last buffered */ - unsigned char *bufrpos; /* pointer to next readable buffered */ + unsigned char *bufpos; + unsigned char *bufread; /* pointer to 1 past last buffered read char. */ #ifdef __STDIO_GETC_MACRO unsigned char *bufgetc; /* 1 past last readable by getc */ #endif /* __STDIO_GETC_MACRO */ @@ -254,6 +270,9 @@ struct __stdio_file_struct { void *cookie; _IO_cookie_io_functions_t gcs; #endif /* __STDIO_GLIBC_CUSTOM_STREAMS */ +#ifdef __STDIO_MBSTATE + __mbstate_t state; +#endif #ifdef __STDIO_THREADSAFE int user_locking; pthread_mutex_t lock; @@ -302,6 +321,16 @@ extern int _cs_close(void *cookie); /**********************************************************************/ +#ifdef __STDIO_MBSTATE +#define __COPY_MBSTATE(dest,src) ((dest)->mask = (src)->mask, (dest)->wc = (src)->wc) +#define __INIT_MBSTATE(dest) ((dest)->mask = 0) +#else +#define __COPY_MBSTATE(dest,src) +#define __INIT_MBSTATE(dest) +#endif + +/**********************************************************************/ + /* TODO -- thread safety issues */ #define __CLEARERR(stream) \ ((stream)->modeflags &= ~(__FLAG_EOF|__FLAG_ERROR), (void)0) @@ -323,16 +352,16 @@ extern int _cs_close(void *cookie); */ #ifdef __STDIO_GETC_MACRO -#define __GETC(stream) ( ((stream)->bufrpos < (stream)->bufgetc) \ - ? (*(stream)->bufrpos++) \ +#define __GETC(stream) ( ((stream)->bufpos < (stream)->bufgetc) \ + ? (*(stream)->bufpos++) \ : fgetc_unlocked(stream) ) #else /* __STDIO_GETC_MACRO */ #define __GETC(stream) fgetc_unlocked(stream) #endif /* __STDIO_GETC_MACRO */ #ifdef __STDIO_PUTC_MACRO -#define __PUTC(c, stream) ( ((stream)->bufwpos < (stream)->bufputc) \ - ? (*(stream)->bufwpos++) = (c) \ +#define __PUTC(c, stream) ( ((stream)->bufpos < (stream)->bufputc) \ + ? (*(stream)->bufpos++) = (c) \ : fputc_unlocked((c),(stream)) ) #else /* __STDIO_PUTC_MACRO */ #define __PUTC(c, stream) fputc_unlocked(c, stream); @@ -488,7 +517,9 @@ extern char *_uintmaxtostr(char * __restrict bufend, uintmax_t uval, /* TODO: note done above.. typedef struct __stdio_file_struct _UC_FILE; */ typedef __stdio_fpos_t _UC_fpos_t; +#ifdef __STDIO_LARGE_FILES typedef __stdio_fpos64_t _UC_fpos64_t; +#endif #define _UC_IOFBF _STDIO_IOFBF /* Fully buffered. */ #define _UC_IOLBF _STDIO_IOLBF /* Line buffered. */ |