From 1217289737588e65b088b3535428b27c7287d699 Mon Sep 17 00:00:00 2001 From: Manuel Novoa III Date: Fri, 1 Aug 2003 20:08:59 +0000 Subject: Add a new *scanf implementation, includeing the *wscanf functions. Should be standards compliant and with several optional features, including support for hexadecimal float notation, locale awareness, glibc-like locale-specific digit grouping with the `'' flag, and positional arg support. I tested it pretty well (finding several bugs in glibc's scanf in the process), but it is brand new so be aware. The *wprintf functions now support floating point output. Also, a couple of bugs were squashed. Finally, %a/%A conversions are now implemented. Implement the glibc xlocale interface for thread-specific locale support. Also add the various *_l(args, locale_t loc_arg) funcs. NOTE!!! setlocale() is NOT threadsafe! NOTE!!! The strto{floating point} conversion functions are now locale aware. The also now support hexadecimal floating point notation. Add the wcsto{floating point} conversion functions. Fix a bug in mktime() related to dst. Note that unlike glibc's mktime, uClibc's version always normalizes the struct tm before attempting to determine the correct dst setting if tm_isdst == -1 on entry. Add a stub version of the libintl functions. (untested) Fixed a known memory leak in setlocale() related to the collation data. Add lots of new config options (which Erik agreed to sort out :-), including finally exposing some of the stripped down stdio configs. Be careful with those though, as they haven't been tested in a long time. (temporary) GOTCHAs... The ctype functions are currently incorrect for 8-bit locales. They will be fixed shortly. The ctype functions are now table-based, resulting in larger staticly linked binaries. I'll be adding an option to use the old approach in the stub locale configuration. --- libc/misc/Makefile | 4 +- libc/misc/assert/__assert.c | 16 +- libc/misc/ctype/Makefile | 29 +- libc/misc/ctype/ctype.c | 1041 ++++++++++++++++++++++++++++++++++------ libc/misc/intl/Makefile | 50 ++ libc/misc/intl/intl.c | 149 ++++++ libc/misc/locale/Makefile | 31 +- libc/misc/locale/locale.c | 1121 +++++++++++++++++++++++++++++-------------- libc/misc/time/Makefile | 13 +- libc/misc/time/time.c | 245 +++++++--- libc/misc/wchar/Makefile | 1 - libc/misc/wchar/wchar.c | 111 +++-- libc/misc/wchar/wstdio.c | 37 +- libc/misc/wctype/Makefile | 20 +- libc/misc/wctype/wctype.c | 661 +++++++++++++++++-------- 15 files changed, 2676 insertions(+), 853 deletions(-) create mode 100644 libc/misc/intl/Makefile create mode 100644 libc/misc/intl/intl.c (limited to 'libc/misc') diff --git a/libc/misc/Makefile b/libc/misc/Makefile index 46de813da..037e2154d 100644 --- a/libc/misc/Makefile +++ b/libc/misc/Makefile @@ -26,8 +26,8 @@ include $(TOPDIR)Rules.mak DIRS = assert ctype dirent file fnmatch glob internals \ - mntent syslog time utmp locale sysvipc statfs \ - error ttyent gnu search + mntent syslog time utmp sysvipc statfs \ + error ttyent gnu search intl locale ifeq ($(strip $(UCLIBC_HAS_REGEX)),y) DIRS += regex endif diff --git a/libc/misc/assert/__assert.c b/libc/misc/assert/__assert.c index efffff1de..26bcc6516 100644 --- a/libc/misc/assert/__assert.c +++ b/libc/misc/assert/__assert.c @@ -37,15 +37,21 @@ #include #undef assert + +#define ASSERT_SHOW_PROGNAME 1 + +#ifdef ASSERT_SHOW_PROGNAME +extern const char *__progname; +#endif + #if 1 void __assert(const char *assertion, const char * filename, int linenumber, register const char * function) { fprintf(stderr, -#if 0 - /* TODO: support program_name like glibc? */ - "%s: %s: %d: %s: Assertion `%s' failed.\n", program_name, +#ifdef ASSERT_SHOW_PROGNAME + "%s: %s: %d: %s: Assertion `%s' failed.\n", __progname, #else "%s: %d: %s: Assertion `%s' failed.\n", #endif @@ -66,8 +72,8 @@ void __assert(const char *assertion, const char * filename, char buf[__BUFLEN_INT10TOSTR]; _stdio_fdout(STDERR_FILENO, -#if 0 - program_name, /* TODO: support program_name like glibc? */ +#ifdef ASSERT_SHOW_PROGNAME + __progname, ": ", #endif filename, diff --git a/libc/misc/ctype/Makefile b/libc/misc/ctype/Makefile index 1d7c24535..2f1dd65f0 100644 --- a/libc/misc/ctype/Makefile +++ b/libc/misc/ctype/Makefile @@ -25,17 +25,26 @@ TOPDIR=../../../ include $(TOPDIR)Rules.mak MSRC=ctype.c -MOBJ= isalnum.o isalpha.o isascii.o iscntrl.o isdigit.o isgraph.o \ - islower.o isprint.o ispunct.o isspace.o isupper.o isxdigit.o \ - isxlower.o isxupper.o toascii.o tolower.o toupper.o isblank.o \ - __isctype_loc.o +MOBJ= isalnum.o isalpha.o isascii.o iscntrl.o isdigit.o \ + isgraph.o islower.o isprint.o ispunct.o isspace.o \ + isupper.o isxdigit.o toascii.o tolower.o toupper.o \ + isblank.o isctype.o isxlower.o isxupper.o \ + __C_ctype_b.o __C_ctype_tolower.o __C_ctype_toupper.o \ + __ctype_b_loc.o __ctype_tolower_loc.o __ctype_toupper_loc.o \ + __ctype_assert.o -CSRC=junk.c -COBJS=$(patsubst %.c,%.o, $(CSRC)) +MOBJx= isalnum_l.o isalpha_l.o isascii_l.o iscntrl_l.o isdigit_l.o \ + isgraph_l.o islower_l.o isprint_l.o ispunct_l.o isspace_l.o \ + isupper_l.o isxdigit_l.o toascii_l.o tolower_l.o toupper_l.o \ + isblank_l.o # isxlower_l.o isxupper_l.o +OBJS=$(MOBJ) -OBJS=$(MOBJ) $(COBJS) -all: $(MOBJ) $(LIBC) +ifeq ($(UCLIBC_HAS_XLOCALE),y) + OBJS += $(MOBJx) +endif + +all: $(OBJS) $(LIBC) $(LIBC): ar-target @@ -46,8 +55,8 @@ $(MOBJ): $(MSRC) $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o $(STRIPTOOL) -x -R .note -R .comment $*.o -$(COBJS): %.o : %.c - $(CC) $(CFLAGS) -c $< -o $@ +$(MOBJx): $(MSRC) + $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o $(STRIPTOOL) -x -R .note -R .comment $*.o $(OBJS): Makefile diff --git a/libc/misc/ctype/ctype.c b/libc/misc/ctype/ctype.c index dedd5c00a..0eb97140d 100644 --- a/libc/misc/ctype/ctype.c +++ b/libc/misc/ctype/ctype.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Manuel Novoa III +/* Copyright (C) 2003 Manuel Novoa III * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -31,299 +31,1026 @@ #include #include +#include #include +#include #include #include +#ifdef __UCLIBC_HAS_XLOCALE__ +#include +#endif /* __UCLIBC_HAS_XLOCALE__ */ + /**********************************************************************/ -extern int __isctype_loc(int c, int ct); +#ifdef __UCLIBC_HAS_CTYPE_SIGNED__ -/* Some macros used throughout the file. */ -#define U ((unsigned char)c) -/* #define LCT (__cur_locale->ctype) */ -#define LCT (&__global_locale) +#if EOF >= CHAR_MIN +#define CTYPE_DOMAIN_CHECK(C) \ + (((unsigned int)((C) - CHAR_MIN)) <= (UCHAR_MAX - CHAR_MIN)) +#else +#define CTYPE_DOMAIN_CHECK(C) \ + ((((unsigned int)((C) - CHAR_MIN)) <= (UCHAR_MAX - CHAR_MIN)) || ((C) == EOF)) +#endif -/**********************************************************************/ +#else /* __UCLIBC_HAS_CTYPE_SIGNED__ */ -#ifndef __PASTE -#define __PASTE(X,Y) X ## Y +#if EOF == -1 +#define CTYPE_DOMAIN_CHECK(C) \ + (((unsigned int)((C) - EOF)) <= (UCHAR_MAX - EOF)) +#else +#define CTYPE_DOMAIN_CHECK(C) \ + ((((unsigned int)(C)) <= UCHAR_MAX) || ((C) == EOF)) #endif -#define C_MACRO(X) __PASTE(__C_,X)(c) - -#define CT_MACRO(X) __PASTE(__ctype_,X)(c) +#endif /* __UCLIBC_HAS_CTYPE_SIGNED__ */ /**********************************************************************/ +#ifdef __UCLIBC_MJN3_ONLY__ +#ifdef L_isspace +/* emit only once */ +#warning CONSIDER: Should we assert when debugging and __UCLIBC_HAS_CTYPE_CHECKED? +#warning TODO: Fix asserts in to{upper|lower}{_l}. +#warning TODO: Optimize the isx*() funcs. +#endif +#endif /* __UCLIBC_MJN3_ONLY__ */ + +#undef CTYPE_NAME +#undef ISCTYPE +#undef CTYPE_ALIAS +#ifdef __UCLIBC_DO_XLOCALE +#define CTYPE_NAME(X) __is ## X ## _l +#define ISCTYPE(C,F) __isctype_l( C, F, locale_arg) +#define CTYPE_ALIAS(NAME) weak_alias( __is ## NAME ## _l , is ## NAME ## _l) +#else +#define CTYPE_NAME(X) is ## X +#define ISCTYPE(C,F) __isctype( C, F ) +#define CTYPE_ALIAS(NAME) +#endif +#undef PASTE2 +#define PASTE2(X,Y) X ## Y -#ifndef __CTYPE_HAS_8_BIT_LOCALES -#define IS_FUNC_BODY(NAME) \ -int NAME (int c) \ -{ \ - return C_MACRO(NAME); \ -} +#undef CTYPE_BODY + +#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__) +/* Make sure assert is active for to*() funcs below. */ +#undef NDEBUG +#include + +extern void __isctype_assert(int c, int mask) __attribute__ ((__noreturn__)); + +#define CTYPE_BODY(NAME,C,MASK) \ + if (CTYPE_DOMAIN_CHECK(C)) { \ + return ISCTYPE(C, MASK); \ + } \ + __isctype_assert(C, MASK); + +#elif defined(__UCLIBC_HAS_CTYPE_CHECKED__) + +#define CTYPE_BODY(NAME,C,MASK) \ + return CTYPE_DOMAIN_CHECK(C) \ + ? ISCTYPE(C, MASK) \ + : 0; + +#elif defined(__UCLIBC_HAS_CTYPE_UNSAFE__) + +#define CTYPE_BODY(NAME,C,MASK) \ + return ISCTYPE(C, MASK); + + +#else /* No checking done. */ + +#error Unknown type of ctype checking! + +#endif -#else -/* It may be worth defining __isctype_loc over the whole range of char. */ -/* #define IS_FUNC_BODY(NAME) \ */ -/* int NAME (int c) \ */ -/* { \ */ -/* return __isctype_loc(c, __PASTE(_CTYPE_,NAME)); \ */ -/* } */ #define IS_FUNC_BODY(NAME) \ -int NAME (int c) \ +int CTYPE_NAME(NAME) (int c __LOCALE_PARAM ) \ { \ - if (((unsigned int) c) <= 0x7f) { \ - return C_MACRO(NAME); \ - } \ - return __isctype_loc(c, __PASTE(_CTYPE_,NAME)); \ + CTYPE_BODY(NAME,c,PASTE2(_IS,NAME)) \ +} \ +CTYPE_ALIAS(NAME) + + +/**********************************************************************/ +#ifdef L___ctype_assert +#ifdef __UCLIBC_HAS_CTYPE_ENFORCED__ + +extern const char *__progname; + +void __isctype_assert(int c, int mask) +{ + fprintf(stderr, "%s: __is*{_l}(%d,%#x {locale})\n", __progname, c, mask); + abort(); } -#endif /* __CTYPE_HAS_8_BIT_LOCALES */ +#endif +#endif +/**********************************************************************/ +#if defined(L_isalnum) || defined(L_isalnum_l) + +IS_FUNC_BODY(alnum); + +#endif +/**********************************************************************/ +#if defined(L_isalpha) || defined(L_isalpha_l) +IS_FUNC_BODY(alpha); + +#endif /**********************************************************************/ -#ifdef L_isalnum +#if defined(L_isblank) || defined(L_isblank_l) -IS_FUNC_BODY(isalnum); +IS_FUNC_BODY(blank); #endif /**********************************************************************/ -#ifdef L_isalpha +#if defined(L_iscntrl) || defined(L_iscntrl_l) -IS_FUNC_BODY(isalpha); +IS_FUNC_BODY(cntrl); #endif /**********************************************************************/ -#ifdef L_isblank +#if defined(L_isdigit) || defined(L_isdigit_l) -/* Warning!!! This is correct for all the currently supported 8-bit locales. - * If any are added though, this will need to be verified. */ +/* The standards require EOF < 0. */ +#if EOF >= CHAR_MIN +#define __isdigit_char_or_EOF(C) __isdigit_char((C)) +#else +#define __isdigit_char_or_EOF(C) __isdigit_int((C)) +#endif -int isblank(int c) +int CTYPE_NAME(digit) (int C __LOCALE_PARAM) { - return __isblank(c); +#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__) + if (CTYPE_DOMAIN_CHECK(C)) { + return __isdigit_char_or_EOF(C); /* C is (unsigned) char or EOF. */ + } + __isctype_assert(C, _ISdigit); +#else + return __isdigit_int(C); /* C could be invalid. */ +#endif } +CTYPE_ALIAS(digit) + #endif /**********************************************************************/ -#ifdef L_iscntrl +#if defined(L_isgraph) || defined(L_isgraph_l) -IS_FUNC_BODY(iscntrl); +IS_FUNC_BODY(graph); #endif /**********************************************************************/ -#ifdef L_isdigit +#if defined(L_islower) || defined(L_islower_l) -int isdigit(int c) -{ - return __isdigit(c); -} +IS_FUNC_BODY(lower); #endif /**********************************************************************/ -#ifdef L_isgraph +#if defined(L_isprint) || defined(L_isprint_l) -IS_FUNC_BODY(isgraph); +IS_FUNC_BODY(print); #endif /**********************************************************************/ -#ifdef L_islower +#if defined(L_ispunct) || defined(L_ispunct_l) -IS_FUNC_BODY(islower); +IS_FUNC_BODY(punct); #endif /**********************************************************************/ -#ifdef L_isprint +#if defined(L_isspace) || defined(L_isspace_l) -IS_FUNC_BODY(isprint); +IS_FUNC_BODY(space); #endif /**********************************************************************/ -#ifdef L_ispunct +#if defined(L_isupper) || defined(L_isupper_l) -IS_FUNC_BODY(ispunct); +IS_FUNC_BODY(upper); #endif /**********************************************************************/ -#ifdef L_isspace +#if defined(L_isxdigit) || defined(L_isxdigit_l) -/* Warning!!! This is correct for all the currently supported 8-bit locales. - * If any are added though, this will need to be verified. */ +IS_FUNC_BODY(xdigit); -int isspace(int c) +#endif +/**********************************************************************/ +#ifdef L_tolower + +int tolower(int c) { - return __isspace(c); +#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__) + assert(CTYPE_DOMAIN_CHECK(c)); +#endif + return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? (__UCLIBC_CTYPE_TOLOWER)[c] : c; } #endif /**********************************************************************/ -#ifdef L_isupper +#ifdef L_tolower_l + +#undef tolower_l -IS_FUNC_BODY(isupper); +int tolower_l(int c, __locale_t l) +{ +#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__) + assert(CTYPE_DOMAIN_CHECK(c)); +#endif + return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? l->__ctype_tolower[c] : c; +} #endif /**********************************************************************/ -#ifdef L_isxdigit +#ifdef L_toupper -int isxdigit(int c) +int toupper(int c) { - return __isxdigit(c); +#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__) + assert(CTYPE_DOMAIN_CHECK(c)); +#endif + return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? (__UCLIBC_CTYPE_TOUPPER)[c] : c; } #endif /**********************************************************************/ -#ifdef L_tolower +#ifdef L_toupper_l -#ifdef __CTYPE_HAS_8_BIT_LOCALES +#undef toupper_l -int tolower(int c) +int toupper_l(int c, __locale_t l) { - return ((((unsigned int) c) <= 0x7f) - || (LCT->encoding != __ctype_encoding_8_bit)) - ? __C_tolower(c) - : ( __isctype_loc(c, _CTYPE_isupper) - ? (unsigned char) - ( U - LCT->tbl8uplow[ ((int) - (LCT->idx8uplow[(U & 0x7f) - >> Cuplow_IDX_SHIFT]) - << Cuplow_IDX_SHIFT) - + (U & ((1 << Cuplow_IDX_SHIFT) - 1)) ]) - : c ); +#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__) + assert(CTYPE_DOMAIN_CHECK(c)); +#endif + return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? l->__ctype_toupper[c] : c; } -#else /* __CTYPE_HAS_8_BIT_LOCALES */ +#endif +/**********************************************************************/ +#if defined(L_isascii) || defined(L_isascii_l) -int tolower(int c) +int __XL(isascii)(int c) { - return __C_tolower(c); + return __isascii(c); /* locale-independent */ } -#endif /* __CTYPE_HAS_8_BIT_LOCALES */ - #endif /**********************************************************************/ -#ifdef L_toupper - -#ifdef __CTYPE_HAS_8_BIT_LOCALES +#if defined(L_toascii) || defined(L_toascii_l) -int toupper(int c) +int __XL(toascii)(int c) { - return ((((unsigned int) c) <= 0x7f) - || (LCT->encoding != __ctype_encoding_8_bit)) - ? __C_toupper(c) - : ( __isctype_loc(c, _CTYPE_islower) - ? (unsigned char) - ( U + LCT->tbl8uplow[ ((int) - (LCT->idx8uplow[(U & 0x7f) - >> Cuplow_IDX_SHIFT]) - << Cuplow_IDX_SHIFT) - + (U & ((1 << Cuplow_IDX_SHIFT) - 1)) ]) - : c ); + return __toascii(c); /* locale-independent */ } -#else /* __CTYPE_HAS_8_BIT_LOCALES */ +#endif +/**********************************************************************/ +/* old uClibc extensions */ +/**********************************************************************/ +#ifdef L_isxlower -int toupper(int c) +int isxlower(int C) { - return __C_toupper(c); +#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__) + assert(CTYPE_DOMAIN_CHECK(C)); + return (__isctype(C, (_ISxdigit|_ISupper)) == _ISxdigit); +#elif defined(__UCLIBC_HAS_CTYPE_CHECKED__) + return CTYPE_DOMAIN_CHECK(C) + ? (__isctype(C, (_ISxdigit|_ISupper)) == _ISxdigit) + : 0; +#elif defined(__UCLIBC_HAS_CTYPE_UNSAFE__) + return (__isctype(C, (_ISxdigit|_ISupper)) == _ISxdigit); +#else /* No checking done. */ +#error Unknown type of ctype checking! +#endif } -#endif /* __CTYPE_HAS_8_BIT_LOCALES */ +#endif +/**********************************************************************/ +#ifdef L_isxupper + +int isxupper(int C) +{ +#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__) + assert(CTYPE_DOMAIN_CHECK(C)); + return (__isctype(C, (_ISxdigit|_ISlower)) == _ISxdigit); +#elif defined(__UCLIBC_HAS_CTYPE_CHECKED__) + return CTYPE_DOMAIN_CHECK(C) + ? (__isctype(C, (_ISxdigit|_ISlower)) == _ISxdigit) + : 0; +#elif defined(__UCLIBC_HAS_CTYPE_UNSAFE__) + return (__isctype(C, (_ISxdigit|_ISlower)) == _ISxdigit); +#else /* No checking done. */ +#error Unknown type of ctype checking! +#endif +} #endif /**********************************************************************/ -#ifdef L_isascii +/* glibc extensions */ +/**********************************************************************/ +#ifdef L_isctype -int isascii(int c) +int isctype(int c, int mask) { - return __isascii(c); + CTYPE_BODY(NAME,c,mask) } #endif /**********************************************************************/ -#ifdef L_toascii +#if L___ctype_b_loc + +#ifdef __UCLIBC_HAS_XLOCALE__ -int toascii(int c) +const uint16_t **__ctype_b_loc(void) { - return __toascii(c); + return &(__UCLIBC_CURLOCALE_DATA).__ctype_b; } +#endif + #endif /**********************************************************************/ -#ifdef L_isxlower +#if L___ctype_tolower_loc + +#ifdef __UCLIBC_HAS_XLOCALE__ -int isxlower(int c) +const __ctype_touplow_t **__ctype_tolower_loc(void) { - return __isxlower(c); + return &(__UCLIBC_CURLOCALE_DATA).__ctype_tolower; } +#endif + #endif /**********************************************************************/ -#ifdef L_isxupper +#if L___ctype_toupper_loc + +#ifdef __UCLIBC_HAS_XLOCALE__ -int isxupper(int c) +const __ctype_touplow_t **__ctype_toupper_loc(void) { - return __isxupper(c); + return &(__UCLIBC_CURLOCALE_DATA).__ctype_toupper; } +#endif + #endif /**********************************************************************/ -#ifdef L___isctype_loc -#ifdef __CTYPE_HAS_8_BIT_LOCALES +#ifdef L___C_ctype_b + +const uint16_t __C_ctype_b_data[] = { +#ifdef __UCLIBC_HAS_CTYPE_SIGNED__ + /* -128 M-^@ */ 0, + /* -127 M-^A */ 0, + /* -126 M-^B */ 0, + /* -125 M-^C */ 0, + /* -124 M-^D */ 0, + /* -123 M-^E */ 0, + /* -122 M-^F */ 0, + /* -121 M-^G */ 0, + /* -120 M-^H */ 0, + /* -119 M-^I */ 0, + /* -118 M-^J */ 0, + /* -117 M-^K */ 0, + /* -116 M-^L */ 0, + /* -115 M-^M */ 0, + /* -114 M-^N */ 0, + /* -113 M-^O */ 0, + /* -112 M-^P */ 0, + /* -111 M-^Q */ 0, + /* -110 M-^R */ 0, + /* -109 M-^S */ 0, + /* -108 M-^T */ 0, + /* -107 M-^U */ 0, + /* -106 M-^V */ 0, + /* -105 M-^W */ 0, + /* -104 M-^X */ 0, + /* -103 M-^Y */ 0, + /* -102 M-^Z */ 0, + /* -101 M-^[ */ 0, + /* -100 M-^\ */ 0, + /* -99 M-^] */ 0, + /* -98 M-^^ */ 0, + /* -97 M-^_ */ 0, + /* -96 M- */ 0, + /* -95 M-! */ 0, + /* -94 M-" */ 0, + /* -93 M-# */ 0, + /* -92 M-$ */ 0, + /* -91 M-% */ 0, + /* -90 M-& */ 0, + /* -89 M-' */ 0, + /* -88 M-( */ 0, + /* -87 M-) */ 0, + /* -86 M-* */ 0, + /* -85 M-+ */ 0, + /* -84 M-, */ 0, + /* -83 M-- */ 0, + /* -82 M-. */ 0, + /* -81 M-/ */ 0, + /* -80 M-0 */ 0, + /* -79 M-1 */ 0, + /* -78 M-2 */ 0, + /* -77 M-3 */ 0, + /* -76 M-4 */ 0, + /* -75 M-5 */ 0, + /* -74 M-6 */ 0, + /* -73 M-7 */ 0, + /* -72 M-8 */ 0, + /* -71 M-9 */ 0, + /* -70 M-: */ 0, + /* -69 M-; */ 0, + /* -68 M-< */ 0, + /* -67 M-= */ 0, + /* -66 M-> */ 0, + /* -65 M-? */ 0, + /* -64 M-@ */ 0, + /* -63 M-A */ 0, + /* -62 M-B */ 0, + /* -61 M-C */ 0, + /* -60 M-D */ 0, + /* -59 M-E */ 0, + /* -58 M-F */ 0, + /* -57 M-G */ 0, + /* -56 M-H */ 0, + /* -55 M-I */ 0, + /* -54 M-J */ 0, + /* -53 M-K */ 0, + /* -52 M-L */ 0, + /* -51 M-M */ 0, + /* -50 M-N */ 0, + /* -49 M-O */ 0, + /* -48 M-P */ 0, + /* -47 M-Q */ 0, + /* -46 M-R */ 0, + /* -45 M-S */ 0, + /* -44 M-T */ 0, + /* -43 M-U */ 0, + /* -42 M-V */ 0, + /* -41 M-W */ 0, + /* -40 M-X */ 0, + /* -39 M-Y */ 0, + /* -38 M-Z */ 0, + /* -37 M-[ */ 0, + /* -36 M-\ */ 0, + /* -35 M-] */ 0, + /* -34 M-^ */ 0, + /* -33 M-_ */ 0, + /* -32 M-` */ 0, + /* -31 M-a */ 0, + /* -30 M-b */ 0, + /* -29 M-c */ 0, + /* -28 M-d */ 0, + /* -27 M-e */ 0, + /* -26 M-f */ 0, + /* -25 M-g */ 0, + /* -24 M-h */ 0, + /* -23 M-i */ 0, + /* -22 M-j */ 0, + /* -21 M-k */ 0, + /* -20 M-l */ 0, + /* -19 M-m */ 0, + /* -18 M-n */ 0, + /* -17 M-o */ 0, + /* -16 M-p */ 0, + /* -15 M-q */ 0, + /* -14 M-r */ 0, + /* -13 M-s */ 0, + /* -12 M-t */ 0, + /* -11 M-u */ 0, + /* -10 M-v */ 0, + /* -9 M-w */ 0, + /* -8 M-x */ 0, + /* -7 M-y */ 0, + /* -6 M-z */ 0, + /* -5 M-{ */ 0, + /* -4 M-| */ 0, + /* -3 M-} */ 0, + /* -2 M-~ */ 0, +#endif /* __UCLIBC_HAS_CTYPE_SIGNED__*/ + /* -1 M-^? */ 0, + /* 0 ^@ */ _IScntrl, + /* 1 ^A */ _IScntrl, + /* 2 ^B */ _IScntrl, + /* 3 ^C */ _IScntrl, + /* 4 ^D */ _IScntrl, + /* 5 ^E */ _IScntrl, + /* 6 ^F */ _IScntrl, + /* 7 ^G */ _IScntrl, + /* 8 ^H */ _IScntrl, + /* 9 ^I */ _ISspace|_ISblank|_IScntrl, + /* 10 ^J */ _ISspace|_IScntrl, + /* 11 ^K */ _ISspace|_IScntrl, + /* 12 ^L */ _ISspace|_IScntrl, + /* 13 ^M */ _ISspace|_IScntrl, + /* 14 ^N */ _IScntrl, + /* 15 ^O */ _IScntrl, + /* 16 ^P */ _IScntrl, + /* 17 ^Q */ _IScntrl, + /* 18 ^R */ _IScntrl, + /* 19 ^S */ _IScntrl, + /* 20 ^T */ _IScntrl, + /* 21 ^U */ _IScntrl, + /* 22 ^V */ _IScntrl, + /* 23 ^W */ _IScntrl, + /* 24 ^X */ _IScntrl, + /* 25 ^Y */ _IScntrl, + /* 26 ^Z */ _IScntrl, + /* 27 ^[ */ _IScntrl, + /* 28 ^\ */ _IScntrl, + /* 29 ^] */ _IScntrl, + /* 30 ^^ */ _IScntrl, + /* 31 ^_ */ _IScntrl, + /* 32 */ _ISspace|_ISprint|_ISblank, + /* 33 ! */ _ISprint|_ISgraph|_ISpunct, + /* 34 " */ _ISprint|_ISgraph|_ISpunct, + /* 35 # */ _ISprint|_ISgraph|_ISpunct, + /* 36 $ */ _ISprint|_ISgraph|_ISpunct, + /* 37 % */ _ISprint|_ISgraph|_ISpunct, + /* 38 & */ _ISprint|_ISgraph|_ISpunct, + /* 39 ' */ _ISprint|_ISgraph|_ISpunct, + /* 40 ( */ _ISprint|_ISgraph|_ISpunct, + /* 41 ) */ _ISprint|_ISgraph|_ISpunct, + /* 42 * */ _ISprint|_ISgraph|_ISpunct, + /* 43 + */ _ISprint|_ISgraph|_ISpunct, + /* 44 , */ _ISprint|_ISgraph|_ISpunct, + /* 45 - */ _ISprint|_ISgraph|_ISpunct, + /* 46 . */ _ISprint|_ISgraph|_ISpunct, + /* 47 / */ _ISprint|_ISgraph|_ISpunct, + /* 48 0 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 49 1 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 50 2 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 51 3 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 52 4 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 53 5 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 54 6 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 55 7 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 56 8 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 57 9 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 58 : */ _ISprint|_ISgraph|_ISpunct, + /* 59 ; */ _ISprint|_ISgraph|_ISpunct, + /* 60 < */ _ISprint|_ISgraph|_ISpunct, + /* 61 = */ _ISprint|_ISgraph|_ISpunct, + /* 62 > */ _ISprint|_ISgraph|_ISpunct, + /* 63 ? */ _ISprint|_ISgraph|_ISpunct, + /* 64 @ */ _ISprint|_ISgraph|_ISpunct, + /* 65 A */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 66 B */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 67 C */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 68 D */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 69 E */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 70 F */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 71 G */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 72 H */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 73 I */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 74 J */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 75 K */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 76 L */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 77 M */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 78 N */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 79 O */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 80 P */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 81 Q */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 82 R */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 83 S */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 84 T */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 85 U */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 86 V */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 87 W */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 88 X */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 89 Y */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 90 Z */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 91 [ */ _ISprint|_ISgraph|_ISpunct, + /* 92 \ */ _ISprint|_ISgraph|_ISpunct, + /* 93 ] */ _ISprint|_ISgraph|_ISpunct, + /* 94 ^ */ _ISprint|_ISgraph|_ISpunct, + /* 95 _ */ _ISprint|_ISgraph|_ISpunct, + /* 96 ` */ _ISprint|_ISgraph|_ISpunct, + /* 97 a */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 98 b */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 99 c */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 100 d */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 101 e */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 102 f */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum, + /* 103 g */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 104 h */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 105 i */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 106 j */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 107 k */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 108 l */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 109 m */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 110 n */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 111 o */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 112 p */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 113 q */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 114 r */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 115 s */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 116 t */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 117 u */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 118 v */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 119 w */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 120 x */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 121 y */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 122 z */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum, + /* 123 { */ _ISprint|_ISgraph|_ISpunct, + /* 124 | */ _ISprint|_ISgraph|_ISpunct, + /* 125 } */ _ISprint|_ISgraph|_ISpunct, + /* 126 ~ */ _ISprint|_ISgraph|_ISpunct, + /* 127 ^? */ _IScntrl, + /* 128 M-^@ */ 0, + /* 129 M-^A */ 0, + /* 130 M-^B */ 0, + /* 131 M-^C */ 0, + /* 132 M-^D */ 0, + /* 133 M-^E */ 0, + /* 134 M-^F */ 0, + /* 135 M-^G */ 0, + /* 136 M-^H */ 0, + /* 137 M-^I */ 0, + /* 138 M-^J */ 0, + /* 139 M-^K */ 0, + /* 140 M-^L */ 0, + /* 141 M-^M */ 0, + /* 142 M-^N */ 0, + /* 143 M-^O */ 0, + /* 144 M-^P */ 0, + /* 145 M-^Q */ 0, + /* 146 M-^R */ 0, + /* 147 M-^S */ 0, + /* 148 M-^T */ 0, + /* 149 M-^U */ 0, + /* 150 M-^V */ 0, + /* 151 M-^W */ 0, + /* 152 M-^X */ 0, + /* 153 M-^Y */ 0, + /* 154 M-^Z */ 0, + /* 155 M-^[ */ 0, + /* 156 M-^\ */ 0, + /* 157 M-^] */ 0, + /* 158 M-^^ */ 0, + /* 159 M-^_ */ 0, + /* 160 M- */ 0, + /* 161 M-! */ 0, + /* 162 M-" */ 0, + /* 163 M-# */ 0, + /* 164 M-$ */ 0, + /* 165 M-% */ 0, + /* 166 M-& */ 0, + /* 167 M-' */ 0, + /* 168 M-( */ 0, + /* 169 M-) */ 0, + /* 170 M-* */ 0, + /* 171 M-+ */ 0, + /* 172 M-, */ 0, + /* 173 M-- */ 0, + /* 174 M-. */ 0, + /* 175 M-/ */ 0, + /* 176 M-0 */ 0, + /* 177 M-1 */ 0, + /* 178 M-2 */ 0, + /* 179 M-3 */ 0, + /* 180 M-4 */ 0, + /* 181 M-5 */ 0, + /* 182 M-6 */ 0, + /* 183 M-7 */ 0, + /* 184 M-8 */ 0, + /* 185 M-9 */ 0, + /* 186 M-: */ 0, + /* 187 M-; */ 0, + /* 188 M-< */ 0, + /* 189 M-= */ 0, + /* 190 M-> */ 0, + /* 191 M-? */ 0, + /* 192 M-@ */ 0, + /* 193 M-A */ 0, + /* 194 M-B */ 0, + /* 195 M-C */ 0, + /* 196 M-D */ 0, + /* 197 M-E */ 0, + /* 198 M-F */ 0, + /* 199 M-G */ 0, + /* 200 M-H */ 0, + /* 201 M-I */ 0, + /* 202 M-J */ 0, + /* 203 M-K */ 0, + /* 204 M-L */ 0, + /* 205 M-M */ 0, + /* 206 M-N */ 0, + /* 207 M-O */ 0, + /* 208 M-P */ 0, + /* 209 M-Q */ 0, + /* 210 M-R */ 0, + /* 211 M-S */ 0, + /* 212 M-T */ 0, + /* 213 M-U */ 0, + /* 214 M-V */ 0, + /* 215 M-W */ 0, + /* 216 M-X */ 0, + /* 217 M-Y */ 0, + /* 218 M-Z */ 0, + /* 219 M-[ */ 0, + /* 220 M-\ */ 0, + /* 221 M-] */ 0, + /* 222 M-^ */ 0, + /* 223 M-_ */ 0, + /* 224 M-` */ 0, + /* 225 M-a */ 0, + /* 226 M-b */ 0, + /* 227 M-c */ 0, + /* 228 M-d */ 0, + /* 229 M-e */ 0, + /* 230 M-f */ 0, + /* 231 M-g */ 0, + /* 232 M-h */ 0, + /* 233 M-i */ 0, + /* 234 M-j */ 0, + /* 235 M-k */ 0, + /* 236 M-l */ 0, + /* 237 M-m */ 0, + /* 238 M-n */ 0, + /* 239 M-o */ 0, + /* 240 M-p */ 0, + /* 241 M-q */ 0, + /* 242 M-r */ 0, + /* 243 M-s */ 0, + /* 244 M-t */ 0, + /* 245 M-u */ 0, + /* 246 M-v */ 0, + /* 247 M-w */ 0, + /* 248 M-x */ 0, + /* 249 M-y */ 0, + /* 250 M-z */ 0, + /* 251 M-{ */ 0, + /* 252 M-| */ 0, + /* 253 M-} */ 0, + /* 254 M-~ */ 0, + /* 255 M-^? */ 0 +}; + +const uint16_t *__C_ctype_b = __C_ctype_b_data + 1 +#ifdef __UCLIBC_HAS_CTYPE_SIGNED__ + + 127 +#endif + ; + +#ifndef __UCLIBC_HAS_XLOCALE__ + +const uint16_t *__ctype_b = __C_ctype_b_data + 1 +#ifdef __UCLIBC_HAS_CTYPE_SIGNED__ + + 127 +#endif + ; -/* This internal routine is similar to iswctype(), but it doesn't - * work for any non-standard types, itdoesn't work for "xdigit"s, - * and it doesn't work for chars between 0 and 0x7f (although that - * may change). */ +#endif -static const char ctype_range[] = { - __CTYPE_RANGES +#endif +/**********************************************************************/ +#ifdef L___C_ctype_tolower + +const __ctype_touplow_t __C_ctype_tolower_data[] = { +#ifdef __UCLIBC_HAS_CTYPE_SIGNED__ + -128, -127, -126, -125, + -124, -123, -122, -121, + -120, -119, -118, -117, + -116, -115, -114, -113, + -112, -111, -110, -109, + -108, -107, -106, -105, + -104, -103, -102, -101, + -100, -99, -98, -97, + -96, -95, -94, -93, + -92, -91, -90, -89, + -88, -87, -86, -85, + -84, -83, -82, -81, + -80, -79, -78, -77, + -76, -75, -74, -73, + -72, -71, -70, -69, + -68, -67, -66, -65, + -64, -63, -62, -61, + -60, -59, -58, -57, + -56, -55, -54, -53, + -52, -51, -50, -49, + -48, -47, -46, -45, + -44, -43, -42, -41, + -40, -39, -38, -37, + -36, -35, -34, -33, + -32, -31, -30, -29, + -28, -27, -26, -25, + -24, -23, -22, -21, + -20, -19, -18, -17, + -16, -15, -14, -13, + -12, -11, -10, -9, + -8, -7, -6, -5, + -4, -3, -2, -1, +#endif /* __UCLIBC_HAS_CTYPE_SIGNED__*/ + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15, + 16, 17, 18, 19, + 20, 21, 22, 23, + 24, 25, 26, 27, + 28, 29, 30, 31, + 32, 33, 34, 35, + 36, 37, 38, 39, + 40, 41, 42, 43, + 44, 45, 46, 47, + 48, 49, 50, 51, + 52, 53, 54, 55, + 56, 57, 58, 59, + 60, 61, 62, 63, + 64, 97 /* a */, 98 /* b */, 99 /* c */, + 100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */, + 104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */, + 108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */, + 112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */, + 116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */, + 120 /* x */, 121 /* y */, 122 /* z */, 91, + 92, 93, 94, 95, + 96, 97, 98, 99, + 100, 101, 102, 103, + 104, 105, 106, 107, + 108, 109, 110, 111, + 112, 113, 114, 115, + 116, 117, 118, 119, + 120, 121, 122, 123, + 124, 125, 126, 127, + 128, 129, 130, 131, + 132, 133, 134, 135, + 136, 137, 138, 139, + 140, 141, 142, 143, + 144, 145, 146, 147, + 148, 149, 150, 151, + 152, 153, 154, 155, + 156, 157, 158, 159, + 160, 161, 162, 163, + 164, 165, 166, 167, + 168, 169, 170, 171, + 172, 173, 174, 175, + 176, 177, 178, 179, + 180, 181, 182, 183, + 184, 185, 186, 187, + 188, 189, 190, 191, + 192, 193, 194, 195, + 196, 197, 198, 199, + 200, 201, 202, 203, + 204, 205, 206, 207, + 208, 209, 210, 211, + 212, 213, 214, 215, + 216, 217, 218, 219, + 220, 221, 222, 223, + 224, 225, 226, 227, + 228, 229, 230, 231, + 232, 233, 234, 235, + 236, 237, 238, 239, + 240, 241, 242, 243, + 244, 245, 246, 247, + 248, 249, 250, 251, + 252, 253, 254, 255 }; -int __isctype_loc(int c, int ct) -{ - unsigned char d; +const __ctype_touplow_t *__C_ctype_tolower = __C_ctype_tolower_data +#ifdef __UCLIBC_HAS_CTYPE_SIGNED__ + + 128 +#endif + ; - assert(((unsigned int)ct) < _CTYPE_isxdigit); - assert(((unsigned int)c) > 0x7f); +#ifndef __UCLIBC_HAS_XLOCALE__ -#if (CHAR_MIN == 0) /* We don't have signed chars... */ - if ((LCT->encoding != __ctype_encoding_8_bit) - || (((unsigned int) c) > UCHAR_MAX) - ) { - return 0; - } -#else - /* Allow non-EOF negative char values for glibc compatiblity. */ - if ((LCT->encoding != __ctype_encoding_8_bit) || (c == EOF) - || ( ((unsigned int)(c - CHAR_MIN)) > (UCHAR_MAX - CHAR_MIN)) - ) { - return 0; - } +const __ctype_touplow_t *__ctype_tolower = __C_ctype_tolower_data +#ifdef __UCLIBC_HAS_CTYPE_SIGNED__ + + 128 #endif + ; - /* TODO - test assumptions??? 8-bit chars -- or ensure in generator. */ +#endif -#define Cctype_TBL_MASK ((1 << Cctype_IDX_SHIFT) - 1) -#define Cctype_IDX_OFFSET (128 >> Cctype_IDX_SHIFT) +#endif +/**********************************************************************/ +#ifdef L___C_ctype_toupper + +const __ctype_touplow_t __C_ctype_toupper_data[] = { +#ifdef __UCLIBC_HAS_CTYPE_SIGNED__ + -128, -127, -126, -125, + -124, -123, -122, -121, + -120, -119, -118, -117, + -116, -115, -114, -113, + -112, -111, -110, -109, + -108, -107, -106, -105, + -104, -103, -102, -101, + -100, -99, -98, -97, + -96, -95, -94, -93, + -92, -91, -90, -89, + -88, -87, -86, -85, + -84, -83, -82, -81, + -80, -79, -78, -77, + -76, -75, -74, -73, + -72, -71, -70, -69, + -68, -67, -66, -65, + -64, -63, -62, -61, + -60, -59, -58, -57, + -56, -55, -54, -53, + -52, -51, -50, -49, + -48, -47, -46, -45, + -44, -43, -42, -41, + -40, -39, -38, -37, + -36, -35, -34, -33, + -32, -31, -30, -29, + -28, -27, -26, -25, + -24, -23, -22, -21, + -20, -19, -18, -17, + -16, -15, -14, -13, + -12, -11, -10, -9, + -8, -7, -6, -5, + -4, -3, -2, -1, +#endif /* __UCLIBC_HAS_CTYPE_SIGNED__*/ + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15, + 16, 17, 18, 19, + 20, 21, 22, 23, + 24, 25, 26, 27, + 28, 29, 30, 31, + 32, 33, 34, 35, + 36, 37, 38, 39, + 40, 41, 42, 43, + 44, 45, 46, 47, + 48, 49, 50, 51, + 52, 53, 54, 55, + 56, 57, 58, 59, + 60, 61, 62, 63, + 64, 65, 66, 67, + 68, 69, 70, 71, + 72, 73, 74, 75, + 76, 77, 78, 79, + 80, 81, 82, 83, + 84, 85, 86, 87, + 88, 89, 90, 91, + 92, 93, 94, 95, + 96, 65 /* A */, 66 /* B */, 67 /* C */, + 68 /* D */, 69 /* E */, 70 /* F */, 71 /* G */, + 72 /* H */, 73 /* I */, 74 /* J */, 75 /* K */, + 76 /* L */, 77 /* M */, 78 /* N */, 79 /* O */, + 80 /* P */, 81 /* Q */, 82 /* R */, 83 /* S */, + 84 /* T */, 85 /* U */, 86 /* V */, 87 /* W */, + 88 /* X */, 89 /* Y */, 90 /* Z */, 123, + 124, 125, 126, 127, + 128, 129, 130, 131, + 132, 133, 134, 135, + 136, 137, 138, 139, + 140, 141, 142, 143, + 144, 145, 146, 147, + 148, 149, 150, 151, + 152, 153, 154, 155, + 156, 157, 158, 159, + 160, 161, 162, 163, + 164, 165, 166, 167, + 168, 169, 170, 171, + 172, 173, 174, 175, + 176, 177, 178, 179, + 180, 181, 182, 183, + 184, 185, 186, 187, + 188, 189, 190, 191, + 192, 193, 194, 195, + 196, 197, 198, 199, + 200, 201, 202, 203, + 204, 205, 206, 207, + 208, 209, 210, 211, + 212, 213, 214, 215, + 216, 217, 218, 219, + 220, 221, 222, 223, + 224, 225, 226, 227, + 228, 229, 230, 231, + 232, 233, 234, 235, + 236, 237, 238, 239, + 240, 241, 242, 243, + 244, 245, 246, 247, + 248, 249, 250, 251, + 252, 253, 254, 255 +}; + +const __ctype_touplow_t *__C_ctype_toupper = __C_ctype_toupper_data +#ifdef __UCLIBC_HAS_CTYPE_SIGNED__ + + 128 +#endif + ; + +#ifndef __UCLIBC_HAS_XLOCALE__ + +const __ctype_touplow_t *__ctype_toupper = __C_ctype_toupper_data +#ifdef __UCLIBC_HAS_CTYPE_SIGNED__ + + 128 +#endif + ; - c &= 0x7f; -#ifdef Cctype_PACKED - d = LCT->tbl8ctype[ ((int)(LCT->idx8ctype[(U >> Cctype_IDX_SHIFT) ]) - << (Cctype_IDX_SHIFT - 1)) - + ((U & Cctype_TBL_MASK) >> 1)]; - d = (U & 1) ? (d >> 4) : (d & 0xf); -#else - d = LCT->tbl8ctype[ ((int)(LCT->idx8ctype[(U >> Cctype_IDX_SHIFT) ]) - << Cctype_IDX_SHIFT) - + (U & Cctype_TBL_MASK) ]; #endif - return ( ((unsigned char)(d - ctype_range[2*ct])) <= ctype_range[2*ct+1] ); -} -#endif /* __CTYPE_HAS_8_BIT_LOCALES */ #endif /**********************************************************************/ diff --git a/libc/misc/intl/Makefile b/libc/misc/intl/Makefile new file mode 100644 index 000000000..75fbb321f --- /dev/null +++ b/libc/misc/intl/Makefile @@ -0,0 +1,50 @@ +# Makefile for uClibc +# +# Copyright (C) 2000 by Lineo, inc. +# Copyright (C) 2000,2001 Erik Andersen +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU Library General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more +# details. +# +# You should have received a copy of the GNU Library General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Derived in part from the Linux-8086 C library, the GNU C Library, and several +# other sundry sources. Files within this library are copyright by their +# respective copyright holders. + +TOPDIR=../../../ +include $(TOPDIR)Rules.mak + +MSRC= intl.c +MOBJ= gettext.o ngettext.o dgettext.o dcgettext.o dngettext.o dcngettext.o \ + textdomain.o bindtextdomain.o bind_textdomain_codeset.o + +OBJS=$(MOBJ) + +all: $(OBJS) $(LIBC) + +$(LIBC): ar-target + +ar-target: $(OBJS) + $(AR) $(ARFLAGS) $(LIBC) $(OBJS) + +$(MOBJ): $(MSRC) + $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o + $(STRIPTOOL) -x -R .note -R .comment $*.o + +$(COBJS): %.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + $(STRIPTOOL) -x -R .note -R .comment $*.o + +clean: + rm -f *.[oa] *~ core + diff --git a/libc/misc/intl/intl.c b/libc/misc/intl/intl.c new file mode 100644 index 000000000..183ffcc92 --- /dev/null +++ b/libc/misc/intl/intl.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2003 Manuel Novoa III + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Supply some weaks for gettext and friends. Used by strerror*(). + */ + +#include +#include +#include + +#undef __OPTIMIZE__ +#include + +/**********************************************************************/ +#ifdef L_gettext + +char *weak_function gettext(const char *msgid) +{ + return (char *) msgid; +} + +#endif +/**********************************************************************/ +#ifdef L_dgettext + +char *__uClibc_dgettext(const char *domainname, + const char *msgid) +{ + return (char *) msgid; +} + +weak_alias (__uClibc_dgettext, __dgettext) +weak_alias (__uClibc_dgettext, dgettext) + +#endif +/**********************************************************************/ +#ifdef L_dcgettext + +char * __uClibc_dcgettext(const char *domainname, + const char *msgid, int category) +{ + return (char *) msgid; +} + +weak_alias (__uClibc_dcgettext, __dcgettext) +weak_alias (__uClibc_dcgettext, dcgettext) + +#endif +/**********************************************************************/ +#ifdef L_ngettext + +char *weak_function ngettext(const char *msgid1, const char *msgid2, + unsigned long int n) +{ + return (char *) ((n == 1) ? msgid1 : msgid2); +} + +#endif +/**********************************************************************/ +#ifdef L_dngettext + +char *weak_function dngettext(const char *domainname, const char *msgid1, + const char *msgid2, unsigned long int n) +{ + return (char *) ((n == 1) ? msgid1 : msgid2); +} + +#endif +/**********************************************************************/ +#ifdef L_dcngettext + +char *weak_function dcngettext(const char *domainname, const char *msgid1, + const char *msgid2, unsigned long int n, + int category) +{ + return (char *) ((n == 1) ? msgid1 : msgid2); +} + +#endif +/**********************************************************************/ +#ifdef L_textdomain + +char *weak_function textdomain(const char *domainname) +{ + static const char default_str[] = "messages"; + + if (domainname && *domainname && strcmp(domainname, default_str)) { + __set_errno(EINVAL); + return NULL; + } + return (char *) default_str; +} + +#endif +/**********************************************************************/ +#ifdef L_bindtextdomain + +char *weak_function bindtextdomain(const char *domainname, const char *dirname) +{ + static const char dir[] = "/"; + + if (!domainname || !*domainname + || (dirname +#if 1 + && ((dirname[0] != '/') || dirname[1]) +#else + && strcmp(dirname, dir) +#endif + ) + ) { + __set_errno(EINVAL); + return NULL; + } + + return (char *) dir; +} + +#endif +/**********************************************************************/ +#ifdef L_bind_textdomain_codeset + +/* Specify the character encoding in which the messages from the + DOMAINNAME message catalog will be returned. */ +char *weak_function bind_textdomain_codeset(const char *domainname, + const char *codeset) +{ + if (!domainname || !*domainname || codeset) { + __set_errno(EINVAL); + } + return NULL; +} + +#endif +/**********************************************************************/ diff --git a/libc/misc/locale/Makefile b/libc/misc/locale/Makefile index 29c8cd5a0..8ad041e69 100644 --- a/libc/misc/locale/Makefile +++ b/libc/misc/locale/Makefile @@ -26,14 +26,29 @@ include $(TOPDIR)Rules.mak MSRC= locale.c MOBJ= setlocale.o localeconv.o _locale_init.o nl_langinfo.o +MOBJx= -OBJS= $(MOBJ) +ifeq ($(UCLIBC_HAS_LOCALE),y) + MOBJ += newlocale.o __locale_mbrtowc_l.o +endif + +ifeq ($(UCLIBC_HAS_XLOCALE),y) + MOBJx += nl_langinfo_l.o duplocale.o freelocale.o uselocale.o __curlocale.o +endif + +OBJS= $(MOBJ) $(MOBJx) ifeq ($(UCLIBC_HAS_LOCALE),y) - OBJS += locale_data.o + OBJS += $(COBJS) locale_data.o endif -all: data $(OBJS) $(LIBC) +DATA= +ifeq ($(UCLIBC_HAS_LOCALE),y) + DATA += locale_data.o +endif + +all: $(DATA) $(OBJS) $(LIBC) + $(LIBC): ar-target @@ -44,12 +59,14 @@ $(MOBJ): $(MSRC) $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o $(STRIPTOOL) -x -R .note -R .comment $*.o +$(MOBJx): $(MSRC) + $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o + $(STRIPTOOL) -x -R .note -R .comment $*.o + $(OBJS): Makefile -data: -ifeq ($(UCLIBC_HAS_LOCALE),y) - make -C $(TOPDIR)/extra/locale -endif +# locale_data.o: +# make -C $(TOPDIR)/extra/locale clean: rm -f *.[oa] *~ core diff --git a/libc/misc/locale/locale.c b/libc/misc/locale/locale.c index 9c162a980..071a8df71 100644 --- a/libc/misc/locale/locale.c +++ b/libc/misc/locale/locale.c @@ -36,28 +36,94 @@ */ #define _GNU_SOURCE -#include + +#define __CTYPE_HAS_8_BIT_LOCALES 1 + + #include #include #include #include #include #include +#include +#include + +#undef __LOCALE_C_ONLY +#ifndef __UCLIBC_HAS_LOCALE__ +#define __LOCALE_C_ONLY +#endif /* __UCLIBC_HAS_LOCALE__ */ + + +#ifdef __LOCALE_C_ONLY + +#include + +#else /* __LOCALE_C_ONLY */ + +#ifdef __UCLIBC_MJN3_ONLY__ +#ifdef L_setlocale +#warning TODO: Fix the __CTYPE_HAS_8_BIT_LOCALES define at the top of the file. +#warning TODO: Fix __WCHAR_ENABLED. +#endif +#endif -#ifndef __LOCALE_C_ONLY +/* Need to include this before locale.h and xlocale.h! */ +#include -#define CUR_LOCALE_SPEC (__global_locale.cur_locale) #undef CODESET_LIST #define CODESET_LIST (__locale_mmap->codeset_list) +#ifdef __UCLIBC_HAS_XLOCALE__ +#include +#include +#else /* __UCLIBC_HAS_XLOCALE__ */ +/* We need this internally... */ +#define __UCLIBC_HAS_XLOCALE__ 1 +#include +#include +#undef __UCLIBC_HAS_XLOCALE__ +#endif /* __UCLIBC_HAS_XLOCALE__ */ + +#include + +#define LOCALE_NAMES (__locale_mmap->locale_names5) +#define LOCALES (__locale_mmap->locales) +#define LOCALE_AT_MODIFIERS (__locale_mmap->locale_at_modifiers) +#define CATEGORY_NAMES (__locale_mmap->lc_names) + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: redo the MAX_LOCALE_STR stuff... +#endif +#define MAX_LOCALE_STR 256 /* TODO: Only sufficient for current case. */ +#define MAX_LOCALE_CATEGORY_STR 32 /* TODO: Only sufficient for current case. */ +/* Note: Best if MAX_LOCALE_CATEGORY_STR is a power of 2. */ + +extern int _locale_set_l(const unsigned char *p, __locale_t base); +extern void _locale_init_l(__locale_t base); + #endif /* __LOCALE_C_ONLY */ +#undef LOCALE_STRING_SIZE +#define LOCALE_SELECTOR_SIZE (2 * __LC_ALL + 2) + +#ifdef __UCLIBC_MJN3_ONLY__ +#ifdef L_setlocale +#warning TODO: Create a C locale selector string. +#endif +#endif +#define C_LOCALE_SELECTOR "\x23\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" + + +#include +#include + /**********************************************************************/ #ifdef L_setlocale #ifdef __LOCALE_C_ONLY -link_warning(setlocale,"the 'setlocale' function supports only C|POSIX locales") +link_warning(setlocale,"REMINDER: The 'setlocale' function supports only C|POSIX locales.") static const char C_string[] = "C"; @@ -74,273 +140,125 @@ char *setlocale(int category, register const char *locale) #else /* ---------------------------------------------- __LOCALE_C_ONLY */ -#if !defined(NUM_LOCALES) || (NUM_LOCALES <= 1) -#error locales enabled, but not data other than for C locale! +#ifdef __UCLIBC_HAS_THREADS__ +link_warning(setlocale,"REMINDER: The 'setlocale' function is _not_ threadsafe except for simple queries.") #endif -#define LOCALE_NAMES (__locale_mmap->locale_names5) -#define LOCALES (__locale_mmap->locales) -#define LOCALE_AT_MODIFIERS (__locale_mmap->locale_at_modifiers) -#define CATEGORY_NAMES (__locale_mmap->lc_names) +#if !defined(__LOCALE_DATA_NUM_LOCALES) || (__LOCALE_DATA_NUM_LOCALES <= 1) +#error locales enabled, but not data other than for C locale! +#endif +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: Move posix and utf8 strings. +#endif static const char posix[] = "POSIX"; static const char utf8[] = "UTF-8"; #ifdef __UCLIBC_MJN3_ONLY__ -#warning REMINDER: redo the MAX_LOCALE_STR stuff... +#warning TODO: Fix dimensions of hr_locale. #endif -#define MAX_LOCALE_STR 256 /* TODO: Only sufficient for current case. */ - -static char hr_locale[MAX_LOCALE_STR]; +/* Individual category strings start at hr_locale + category * MAX_LOCALE_CATEGORY. + * This holds for LC_ALL as well. + */ +static char hr_locale[(MAX_LOCALE_CATEGORY_STR * LC_ALL) + MAX_LOCALE_STR]; -static __inline char *human_readable_locale(int category, const unsigned char *s) +static void update_hr_locale(const unsigned char *spec) { const unsigned char *loc; + const unsigned char *s; char *n; - int i; - - ++s; - - if (category == LC_ALL) { - for (i = 0 ; i < LC_ALL-1 ; i += 2) { - if ((s[i] != s[i+2]) || (s[i+1] != s[i+3])) { - goto SKIP; - } - } - /* All categories the same, so simplify string by using a single - * category. */ - category = LC_CTYPE; - } - - SKIP: - i = (category == LC_ALL) ? 0 : category; - s += 2*i; - n = hr_locale; + int i, category, done; + done = category = 0; do { - if ((*s != 0xff) || (s[1] != 0xff)) { - loc = LOCALES + WIDTH_LOCALES * ((((int)(*s & 0x7f)) << 7) + (s[1] & 0x7f)); - if (category == LC_ALL) { - n = stpcpy(n, CATEGORY_NAMES + (int) CATEGORY_NAMES[i]); - *n++ = '='; - } - if (*loc == 0) { - *n++ = 'C'; - *n = 0; - } else { - char at = 0; - memcpy(n, LOCALE_NAMES + 5*((*loc)-1), 5); - if (n[2] != '_') { - at = n[2]; - n[2] = '_'; - } - n += 5; - *n++ = '.'; - if (loc[2] == 2) { - n = stpcpy(n, utf8); - } else if (loc[2] >= 3) { - n = stpcpy(n, CODESET_LIST + (int)(CODESET_LIST[loc[2] - 3])); - } - if (at) { - const char *q; - *n++ = '@'; - q = LOCALE_AT_MODIFIERS; - do { - if (q[1] == at) { - n = stpcpy(n, q+2); - break; - } - q += 2 + *q; - } while (*q); + s = spec + 1; + n = hr_locale + category * MAX_LOCALE_CATEGORY_STR; + + if (category == LC_ALL) { + done = 1; + for (i = 0 ; i < LC_ALL-1 ; i += 2) { + if ((s[i] != s[i+2]) || (s[i+1] != s[i+3])) { + goto SKIP; } } - *n++ = ';'; + /* All categories the same, so simplify string by using a single + * category. */ + category = LC_CTYPE; } - s += 2; - } while (++i < category); - - *--n = 0; /* Remove trailing ';' and nul-terminate. */ - assert(n-hr_locale < MAX_LOCALE_STR); - return hr_locale; -} - -static int find_locale(int category, const char *p, unsigned char *new_locale) -{ - int i; - const unsigned char *s; - uint16_t n; - unsigned char lang_cult, codeset; - -#if defined(LOCALE_AT_MODIFIERS_LENGTH) && 1 - /* Support standard locale handling for @-modifiers. */ -#ifdef __UCLIBC_MJN3_ONLY__ -#warning REMINDER: fix buf size in find_locale -#endif - char buf[18]; /* TODO: 7+{max codeset name length} */ - const char *q; + SKIP: + i = (category == LC_ALL) ? 0 : category; + s += 2*i; - if ((q = strchr(p,'@')) != NULL) { - if ((((size_t)((q-p)-5)) > (sizeof(buf) - 5)) || (p[2] != '_')) { - return 0; - } - /* locale name at least 5 chars long and 3rd char is '_' */ - s = LOCALE_AT_MODIFIERS; do { - if (!strcmp(s+2, q+1)) { - break; - } - s += 2 + *s; /* TODO - fix this throughout */ - } while (*s); - if (!*s) { - return 0; - } - assert(q - p < sizeof(buf)); - memcpy(buf, p, q-p); - buf[q-p] = 0; - buf[2] = s[1]; - p = buf; - } -#endif - - lang_cult = codeset = 0; /* Assume C and default codeset. */ - if (((*p == 'C') && !p[1]) || !strcmp(p, posix)) { - goto FIND_LOCALE; - } - - if ((strlen(p) > 5) && (p[5] == '.')) { /* Codeset in locale name? */ - /* TODO: maybe CODESET_LIST + *s ??? */ - /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */ - codeset = 2; - if (strcmp(utf8,p+6) != 0) {/* TODO - fix! */ - s = CODESET_LIST; - do { - ++codeset; /* Increment codeset first. */ - if (!strcmp(CODESET_LIST+*s, p+6)) { - goto FIND_LANG_CULT; + if ((*s != 0xff) || (s[1] != 0xff)) { + loc = LOCALES + + __LOCALE_DATA_WIDTH_LOCALES * ((((int)(*s & 0x7f)) << 7) + + (s[1] & 0x7f)); + if (category == LC_ALL) { + n = stpcpy(n, CATEGORY_NAMES + (int) CATEGORY_NAMES[i]); + *n++ = '='; } - } while (*++s); - return 0; /* No matching codeset! */ - } - } - - FIND_LANG_CULT: /* Find language_culture number. */ - s = LOCALE_NAMES; - do { /* TODO -- do a binary search? */ - /* TODO -- fix gen_mmap!*/ - ++lang_cult; /* Increment first since C/POSIX is 0. */ - if (!strncmp(s,p,5)) { /* Found a matching locale name; */ - goto FIND_LOCALE; - } - s += 5; - } while (lang_cult < NUM_LOCALE_NAMES); - return 0; /* No matching language_culture! */ - - FIND_LOCALE: /* Find locale row matching name and codeset */ - s = LOCALES; - n = 0; - do { /* TODO -- do a binary search? */ - if ((lang_cult == *s) && ((codeset == s[1]) || (codeset == s[2]))) { - i = ((category == LC_ALL) ? 0 : category); - s = new_locale + 2*i; - do { - /* Encode current locale row number. */ - *((unsigned char *) ++s) = (n >> 7) | 0x80; - *((unsigned char *) ++s) = (n & 0x7f) | 0x80; - } while (++i < category); - - return i; /* Return non-zero */ - } - s += WIDTH_LOCALES; - ++n; - } while (n <= NUM_LOCALES); /* We started at 1!!! */ - - return 0; /* Unsupported locale. */ -} - -static unsigned char *composite_locale(int category, const char *locale, unsigned char *new_locale) -{ - char buf[MAX_LOCALE_STR]; - char *t; - char *e; - int c; - - if (!strchr(locale,'=')) { - if (!find_locale(category, locale, new_locale)) { - return NULL; - } - return new_locale; - } - - if (strlen(locale) >= sizeof(buf)) { - return NULL; - } - stpcpy(buf, locale); - - t = strtok_r(buf, "=", &e); /* This can't fail because of strchr test above. */ - do { - for (c = 0 ; c < LC_ALL ; c++) { /* Find the category... */ - if (!strcmp(CATEGORY_NAMES + (int) CATEGORY_NAMES[c], t)) { - break; - } - } - t = strtok_r(NULL, ";", &e); - if ((category == LC_ALL) || (c == category)) { - if (!t || !find_locale(c, t, new_locale)) { - return NULL; + if (*loc == 0) { + *n++ = 'C'; + *n = 0; + } else { + char at = 0; + memcpy(n, LOCALE_NAMES + 5*((*loc)-1), 5); + if (n[2] != '_') { + at = n[2]; + n[2] = '_'; + } + n += 5; + *n++ = '.'; + if (loc[2] == 2) { + n = stpcpy(n, utf8); + } else if (loc[2] >= 3) { + n = stpcpy(n, CODESET_LIST + (int)(CODESET_LIST[loc[2] - 3])); + } + if (at) { + const char *q; + *n++ = '@'; + q = LOCALE_AT_MODIFIERS; + do { + if (q[1] == at) { + n = stpcpy(n, q+2); + break; + } + q += 2 + *q; + } while (*q); + } + } + *n++ = ';'; } - } - } while ((t = strtok_r(NULL, "=", &e)) != NULL); + s += 2; + } while (++i < category); + *--n = 0; /* Remove trailing ';' and nul-terminate. */ - return new_locale; + ++category; + } while (!done); } char *setlocale(int category, const char *locale) { - const unsigned char *p; - int i; - unsigned char new_locale[LOCALE_STRING_SIZE]; - if (((unsigned int)(category)) > LC_ALL) { - /* TODO - set errno? SUSv3 doesn't say too. */ +#if 0 + __set_errno(EINVAL); /* glibc sets errno -- SUSv3 doesn't say. */ +#endif return NULL; /* Illegal/unsupported category. */ } - if (locale != NULL) { /* Not just a query... */ - stpcpy(new_locale, CUR_LOCALE_SPEC); /* Start with current. */ - - if (!*locale) { /* locale == "", so check environment. */ - i = ((category == LC_ALL) ? 0 : category); - do { - /* Note: SUSv3 doesn't define a fallback mechanism here. So, - * if LC_ALL is invalid, we do _not_ continue trying the other - * environment vars. */ - if (!(p = getenv("LC_ALL"))) { - if (!(p = getenv(CATEGORY_NAMES + CATEGORY_NAMES[i]))) { - if (!(p = getenv("LANG"))) { - p = posix; - } - } - } - - /* The user set something... is it valid? */ - /* Note: Since we don't support user-supplied locales and - * alternate paths, we don't need to worry about special - * handling for suid/sgid apps. */ - if (!find_locale(i, p, new_locale)) { - return NULL; - } - } while (++i < category); - } else if (!composite_locale(category, locale, new_locale)) { + if (locale != NULL) { /* Not just a query... */ + if (!__newlocale((category == LC_ALL) ? LC_ALL_MASK : (1 << category), + locale, __global_locale) + ) { /* Failed! */ return NULL; } - - /* TODO: Ok, everything checks out, so install the new locale. */ - _locale_set(new_locale); + update_hr_locale(__global_locale->cur_locale); } /* Either a query or a successful set, so return current locale string. */ - return human_readable_locale(category, CUR_LOCALE_SPEC); + return hr_locale + (category * MAX_LOCALE_CATEGORY_STR); } #endif /* __LOCALE_C_ONLY */ @@ -355,7 +273,7 @@ char *setlocale(int category, const char *locale) #ifdef __LOCALE_C_ONLY -link_warning(localeconv,"the 'localeconv' function is hardwired for C/POSIX locale only") +link_warning(localeconv,"REMINDER: The 'localeconv' function is hardwired for C/POSIX locale only.") static struct lconv the_lconv; @@ -387,7 +305,7 @@ static struct lconv the_lconv; struct lconv *localeconv(void) { register char *p = (char *) &the_lconv; - register char **q = (char **) &__global_locale.decimal_point; + register char **q = (char **) &(__UCLIBC_CURLOCALE_DATA).decimal_point; do { *((char **)p) = *q; @@ -408,16 +326,22 @@ struct lconv *localeconv(void) #endif /**********************************************************************/ -#ifdef L__locale_init +#if defined(L__locale_init) && !defined(__LOCALE_C_ONLY) -#ifndef __LOCALE_C_ONLY +static __uclibc_locale_t __global_locale_data; -#define C_LOCALE_SELECTOR "\x23\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" -#define LOCALE_INIT_FAILED "locale init failed!\n" +__locale_t __global_locale = &__global_locale_data; -#define CUR_LOCALE_SPEC (__global_locale.cur_locale) +#ifdef __UCLIBC_HAS_XLOCALE__ +__locale_t __curlocale_var = &__global_locale_data; +#endif -__locale_t __global_locale; +/*----------------------------------------------------------------------*/ +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: Move utf8 and ascii strings. +#endif +static const char utf8[] = "UTF-8"; +static const char ascii[] = "ASCII"; typedef struct { uint16_t num_base; @@ -461,9 +385,8 @@ typedef struct { uint16_t multistart_offset; } coldata_der_t; -static int init_cur_collate(int der_num) +static int init_cur_collate(int der_num, __collate_t *cur_collate) { - __collate_t *cur_collate = &__global_locale.collate; const uint16_t *__locale_collate_tbl = __locale_mmap->collate_data; coldata_header_t *cdh; coldata_base_t *cdb; @@ -485,9 +408,16 @@ static int init_cur_collate(int der_num) cdh = (coldata_header_t *) __locale_collate_tbl; +#ifdef __UCLIBC_MJN3_ONLY__ +#warning CONSIDER: Should we assert here? +#endif +#if 0 if (der_num >= cdh->num_der) { return 0; } +#else + assert((der_num < cdh->num_der)); +#endif cdd = (coldata_der_t *)(__locale_collate_tbl + (sizeof(coldata_header_t) @@ -539,14 +469,17 @@ static int init_cur_collate(int der_num) cur_collate->MAX_WEIGHTS = cdh->MAX_WEIGHTS; #ifdef __UCLIBC_MJN3_ONLY__ -#warning if calloc fails, this is WRONG. there is also a memory leak here at the moment -#warning fix the +1 by increasing max_col_index? +#warning CONSIDER: Fix the +1 by increasing max_col_index? +#warning CONSIDER: Since this collate info is dependent only on LC_COLLATE ll_cc and not on codeset, we could just globally allocate this for each in a table #endif - cur_collate->index2weight = calloc(2*cur_collate->max_col_index+2, sizeof(uint16_t)); + + cur_collate->index2weight = calloc(2*cur_collate->max_col_index+2, + sizeof(uint16_t)); if (!cur_collate->index2weight) { return 0; } - cur_collate->index2ruleidx = cur_collate->index2weight + cur_collate->max_col_index + 1; + cur_collate->index2ruleidx = cur_collate->index2weight + + cur_collate->max_col_index + 1; memcpy(cur_collate->index2weight, cur_collate->index2weight_tbl, cur_collate->num_col_base * sizeof(uint16_t)); @@ -602,61 +535,10 @@ static int init_cur_collate(int der_num) return 1; } -void _locale_init(void) -{ - /* TODO: mmap the locale file */ - - /* TODO - ??? */ - memset(CUR_LOCALE_SPEC, 0, LOCALE_STRING_SIZE); - CUR_LOCALE_SPEC[0] = '#'; - - memcpy(__global_locale.category_item_count, - __locale_mmap->lc_common_item_offsets_LEN, - LC_ALL); - - ++__global_locale.category_item_count[0]; /* Increment for codeset entry. */ - __global_locale.category_offsets[0] = offsetof(__locale_t, outdigit0_mb); - __global_locale.category_offsets[1] = offsetof(__locale_t, decimal_point); - __global_locale.category_offsets[2] = offsetof(__locale_t, int_curr_symbol); - __global_locale.category_offsets[3] = offsetof(__locale_t, abday_1); -/* __global_locale.category_offsets[4] = offsetof(__locale_t, collate???); */ - __global_locale.category_offsets[5] = offsetof(__locale_t, yesexpr); - -#ifdef __CTYPE_HAS_8_BIT_LOCALES - __global_locale.tbl8ctype - = (const unsigned char *) &__locale_mmap->tbl8ctype; - __global_locale.tbl8uplow - = (const unsigned char *) &__locale_mmap->tbl8uplow; -#ifdef __WCHAR_ENABLED - __global_locale.tbl8c2wc - = (const uint16_t *) &__locale_mmap->tbl8c2wc; - __global_locale.tbl8wc2c - = (const unsigned char *) &__locale_mmap->tbl8wc2c; - /* translit */ -#endif /* __WCHAR_ENABLED */ -#endif /* __CTYPE_HAS_8_BIT_LOCALES */ -#ifdef __WCHAR_ENABLED - __global_locale.tblwctype - = (const unsigned char *) &__locale_mmap->tblwctype; - __global_locale.tblwuplow - = (const unsigned char *) &__locale_mmap->tblwuplow; - __global_locale.tblwuplow_diff - = (const uint16_t *) &__locale_mmap->tblwuplow_diff; -/* __global_locale.tblwcomb */ -/* = (const unsigned char *) &__locale_mmap->tblwcomb; */ - /* width?? */ -#endif /* __WCHAR_ENABLED */ - - _locale_set(C_LOCALE_SELECTOR); -} - -static const char ascii[] = "ASCII"; -static const char utf8[] = "UTF-8"; - -void _locale_set(const unsigned char *p) +int _locale_set_l(const unsigned char *p, __locale_t base) { const char **x; - unsigned char *s = CUR_LOCALE_SPEC + 1; + unsigned char *s = base->cur_locale + 1; const size_t *stp; const unsigned char *r; const uint16_t *io; @@ -667,12 +549,30 @@ void _locale_set(const unsigned char *p) int len; int c; int i = 0; + __collate_t newcol; ++p; + + newcol.index2weight = NULL; + if ((p[2*LC_COLLATE] != s[2*LC_COLLATE]) + || (p[2*LC_COLLATE + 1] != s[2*LC_COLLATE + 1]) + ) { + row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f); + assert(row < __LOCALE_DATA_NUM_LOCALES); + if (!init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES + * row + 3 + i ], + &newcol) + ) { + return 0; /* calloc failed. */ + } + free(base->collate.index2weight); + memcpy(&base->collate, &newcol, sizeof(__collate_t)); + } + do { if ((*p != *s) || (p[1] != s[1])) { row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f); - assert(row < NUM_LOCALES); + assert(row < __LOCALE_DATA_NUM_LOCALES); *s = *p; s[1] = p[1]; @@ -680,10 +580,13 @@ void _locale_set(const unsigned char *p) if ((i != LC_COLLATE) && ((len = __locale_mmap->lc_common_item_offsets_LEN[i]) != 0) ) { - crow = __locale_mmap->locales[ WIDTH_LOCALES * row + 3 + i ] + crow = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row + + 3 + i ] * len; - x = (const char **)(((char *) &__global_locale) - + __global_locale.category_offsets[i]); + + x = (const char **)(((char *) base) + + base->category_offsets[i]); + stp = __locale_mmap->lc_common_tbl_offsets + 4*i; r = (const unsigned char *)( ((char *)__locale_mmap) + *stp ); io = (const uint16_t *)( ((char *)__locale_mmap) + *++stp ); @@ -694,77 +597,186 @@ void _locale_set(const unsigned char *p) } } if (i == LC_CTYPE) { - c = __locale_mmap->locales[ WIDTH_LOCALES * row + 2 ]; /* codeset */ + c = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row + + 2 ]; /* codeset */ if (c <= 2) { if (c == 2) { - __global_locale.codeset = utf8; - __global_locale.encoding = __ctype_encoding_utf8; + base->codeset = utf8; + base->encoding = __ctype_encoding_utf8; /* TODO - fix for bcc */ - __global_locale.mb_cur_max = 6; + base->mb_cur_max = 6; } else { assert(c==1); - __global_locale.codeset = ascii; - __global_locale.encoding = __ctype_encoding_7_bit; - __global_locale.mb_cur_max = 1; + base->codeset = ascii; + base->encoding = __ctype_encoding_7_bit; + base->mb_cur_max = 1; } } else { - const codeset_8_bit_t *c8b; + const __codeset_8_bit_t *c8b; r = CODESET_LIST; - __global_locale.codeset = r + r[c -= 3]; - __global_locale.encoding = __ctype_encoding_8_bit; + base->codeset = r + r[c -= 3]; + base->encoding = __ctype_encoding_8_bit; #ifdef __UCLIBC_MJN3_ONLY__ -#warning REMINDER: update 8 bit mb_cur_max when trasnlit implemented! +#warning REMINDER: update 8 bit mb_cur_max when translit implemented! #endif /* TODO - update when translit implemented! */ - __global_locale.mb_cur_max = 1; + base->mb_cur_max = 1; c8b = __locale_mmap->codeset_8_bit + c; #ifdef __CTYPE_HAS_8_BIT_LOCALES - __global_locale.idx8ctype = c8b->idx8ctype; - __global_locale.idx8uplow = c8b->idx8uplow; -#ifdef __WCHAR_ENABLED - __global_locale.idx8c2wc = c8b->idx8c2wc; - __global_locale.idx8wc2c = c8b->idx8wc2c; + base->idx8ctype = c8b->idx8ctype; + base->idx8uplow = c8b->idx8uplow; +#ifdef __UCLIBC_HAS_WCHAR__ + base->idx8c2wc = c8b->idx8c2wc; + base->idx8wc2c = c8b->idx8wc2c; /* translit */ -#endif /* __WCHAR_ENABLED */ +#endif /* __UCLIBC_HAS_WCHAR__ */ #endif /* __CTYPE_HAS_8_BIT_LOCALES */ } #ifdef __UCLIBC_MJN3_ONLY__ -#warning might want to just put this in the locale_mmap object +#warning TODO: Put the outdigit string length in the locale_mmap object. #endif - d = __global_locale.outdigit_length; - x = &__global_locale.outdigit0_mb; + d = base->outdigit_length; + x = &base->outdigit0_mb; for (c = 0 ; c < 10 ; c++) { ((unsigned char *)d)[c] = strlen(x[c]); assert(d[c] > 0); } - } else if (i == LC_COLLATE) { - init_cur_collate(__locale_mmap->locales[ WIDTH_LOCALES * row + 3 + i ]); + } else if (i == LC_NUMERIC) { + assert(LC_NUMERIC > LC_CTYPE); /* Need ctype initialized. */ + + base->decimal_point_len + = __locale_mbrtowc_l(&base->decimal_point_wc, + base->decimal_point, base); + assert(base->decimal_point_len > 0); + assert(base->decimal_point[base->decimal_point_len] == 0); + + if (*base->grouping) { + base->thousands_sep_len + = __locale_mbrtowc_l(&base->thousands_sep_wc, + base->thousands_sep, base); + assert(base->thousands_sep_len > 0); + assert(base->thousands_sep[base->thousands_sep_len] == 0); + } + +/* } else if (i == LC_COLLATE) { */ +/* init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES */ +/* * row + 3 + i ], */ +/* &base->collate); */ } } ++i; p += 2; s += 2; } while (i < LC_ALL); + + return 1; } -#endif /* __LOCALE_C_ONLY */ +static const uint16_t __code2flag[16] = { + 0, /* unclassified = 0 */ + _ISprint|_ISgraph|_ISalnum|_ISalpha, /* alpha_nonupper_nonlower */ + _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, /* alpha_lower */ + _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower|_ISupper, /* alpha_upper_lower */ + _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, /* alpha_upper */ + _ISprint|_ISgraph|_ISalnum|_ISdigit, /* digit */ + _ISprint|_ISgraph|_ISpunct, /* punct */ + _ISprint|_ISgraph, /* graph */ + _ISprint|_ISspace, /* print_space_nonblank */ + _ISprint|_ISspace|_ISblank, /* print_space_blank */ + _ISspace, /* space_nonblank_noncntrl */ + _ISspace|_ISblank, /* space_blank_noncntrl */ + _IScntrl|_ISspace, /* cntrl_space_nonblank */ + _IScntrl|_ISspace|_ISblank, /* cntrl_space_blank */ + _IScntrl /* cntrl_nonspace */ +}; -#endif -/**********************************************************************/ -#ifdef L_nl_langinfo +void _locale_init_l(__locale_t base) +{ + memset(base->cur_locale, 0, LOCALE_SELECTOR_SIZE); + base->cur_locale[0] = '#'; -#include -#include + memcpy(base->category_item_count, + __locale_mmap->lc_common_item_offsets_LEN, + LC_ALL); -#ifdef __LOCALE_C_ONLY + ++base->category_item_count[0]; /* Increment for codeset entry. */ + base->category_offsets[0] = offsetof(__uclibc_locale_t, outdigit0_mb); + base->category_offsets[1] = offsetof(__uclibc_locale_t, decimal_point); + base->category_offsets[2] = offsetof(__uclibc_locale_t, int_curr_symbol); + base->category_offsets[3] = offsetof(__uclibc_locale_t, abday_1); +/* base->category_offsets[4] = offsetof(__uclibc_locale_t, collate???); */ + base->category_offsets[5] = offsetof(__uclibc_locale_t, yesexpr); -/* We need to index 320 bytes of data, so you might initially think we - * need to store the offsets in shorts. But since the offset of the - * 64th item is 182, we'll store "offset - 2*64" for all items >= 64 - * and always calculate the data offset as "offset[i] + 2*(i & 64)". - * This allows us to pack the data offsets in an unsigned char while - * also avoiding an "if". - * +#ifdef __CTYPE_HAS_8_BIT_LOCALES + base->tbl8ctype + = (const unsigned char *) &__locale_mmap->tbl8ctype; + base->tbl8uplow + = (const unsigned char *) &__locale_mmap->tbl8uplow; +#ifdef __UCLIBC_HAS_WCHAR__ + base->tbl8c2wc + = (const uint16_t *) &__locale_mmap->tbl8c2wc; + base->tbl8wc2c + = (const unsigned char *) &__locale_mmap->tbl8wc2c; + /* translit */ +#endif /* __UCLIBC_HAS_WCHAR__ */ +#endif /* __CTYPE_HAS_8_BIT_LOCALES */ +#ifdef __UCLIBC_HAS_WCHAR__ + base->tblwctype + = (const unsigned char *) &__locale_mmap->tblwctype; + base->tblwuplow + = (const unsigned char *) &__locale_mmap->tblwuplow; + base->tblwuplow_diff + = (const uint16_t *) &__locale_mmap->tblwuplow_diff; +/* base->tblwcomb */ +/* = (const unsigned char *) &__locale_mmap->tblwcomb; */ + /* width?? */ +#endif /* __UCLIBC_HAS_WCHAR__ */ + + + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning wrong for now, but always set ctype arrays to global C version +#endif +#ifdef __UCLIBC_HAS_XLOCALE__ + base->__ctype_b = __C_ctype_b; + base->__ctype_tolower = __C_ctype_tolower; + base->__ctype_toupper = __C_ctype_toupper; +#else /* __UCLIBC_HAS_XLOCALE__ */ + __ctype_b = __C_ctype_b; + __ctype_tolower = __C_ctype_tolower; + __ctype_toupper = __C_ctype_toupper; +#endif /* __UCLIBC_HAS_XLOCALE__ */ + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: Initialize code2flag correctly based on locale_mmap. +#endif + base->code2flag = __code2flag; + + + _locale_set_l(C_LOCALE_SELECTOR, base); +} + +void _locale_init(void) +{ + /* TODO: mmap the locale file */ + + /* TODO - ??? */ + _locale_init_l(__global_locale); +} + +#endif +/**********************************************************************/ +#if defined(L_nl_langinfo) || defined(L_nl_langinfo_l) + +#ifdef __LOCALE_C_ONLY + +/* We need to index 320 bytes of data, so you might initially think we + * need to store the offsets in shorts. But since the offset of the + * 64th item is 182, we'll store "offset - 2*64" for all items >= 64 + * and always calculate the data offset as "offset[i] + 2*(i & 64)". + * This allows us to pack the data offsets in an unsigned char while + * also avoiding an "if". + * * Note: Category order is assumed to be: * ctype, numeric, monetary, time, collate, messages, all */ @@ -853,22 +865,435 @@ char *nl_langinfo(nl_item item) #else /* __LOCALE_C_ONLY */ -static const char empty[] = ""; +#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) char *nl_langinfo(nl_item item) +{ + return nl_langinfo_l(item, __UCLIBC_CURLOCALE); +} + +#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + +static const char empty[] = ""; + +char *__XL(nl_langinfo)(nl_item item __LOCALE_PARAM ) { unsigned int c = _NL_ITEM_CATEGORY(item); unsigned int i = _NL_ITEM_INDEX(item); - if ((c < LC_ALL) && (i < __global_locale.category_item_count[c])) { - return ((char **)(((char *) &__global_locale) - + __global_locale.category_offsets[c]))[i]; - + if ((c < LC_ALL) && (i < __LOCALE_PTR->category_item_count[c])) { + return ((char **)(((char *) __LOCALE_PTR) + + __LOCALE_PTR->category_offsets[c]))[i]; } + return (char *) empty; } +#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + #endif /* __LOCALE_C_ONLY */ #endif /**********************************************************************/ +#ifdef L_newlocale + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: Move posix and utf8 strings. +#endif +static const char posix[] = "POSIX"; +static const char utf8[] = "UTF-8"; + +static int find_locale(int category_mask, const char *p, + unsigned char *new_locale) +{ + int i; + const unsigned char *s; + uint16_t n; + unsigned char lang_cult, codeset; + +#if defined(__LOCALE_DATA_AT_MODIFIERS_LENGTH) && 1 + /* Support standard locale handling for @-modifiers. */ + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: Fix buf size in find_locale. +#endif + char buf[18]; /* TODO: 7+{max codeset name length} */ + const char *q; + + if ((q = strchr(p,'@')) != NULL) { + if ((((size_t)((q-p)-5)) > (sizeof(buf) - 5)) || (p[2] != '_')) { + return 0; + } + /* locale name at least 5 chars long and 3rd char is '_' */ + s = LOCALE_AT_MODIFIERS; + do { + if (!strcmp(s+2, q+1)) { + break; + } + s += 2 + *s; /* TODO - fix this throughout */ + } while (*s); + if (!*s) { + return 0; + } + assert(q - p < sizeof(buf)); + memcpy(buf, p, q-p); + buf[q-p] = 0; + buf[2] = s[1]; + p = buf; + } +#endif + + lang_cult = codeset = 0; /* Assume C and default codeset. */ + if (((*p == 'C') && !p[1]) || !strcmp(p, posix)) { + goto FIND_LOCALE; + } + + if ((strlen(p) > 5) && (p[5] == '.')) { /* Codeset in locale name? */ + /* TODO: maybe CODESET_LIST + *s ??? */ + /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */ + codeset = 2; + if (strcmp(utf8,p+6) != 0) {/* TODO - fix! */ + s = CODESET_LIST; + do { + ++codeset; /* Increment codeset first. */ + if (!strcmp(CODESET_LIST+*s, p+6)) { + goto FIND_LANG_CULT; + } + } while (*++s); + return 0; /* No matching codeset! */ + } + } + + FIND_LANG_CULT: /* Find language_culture number. */ + s = LOCALE_NAMES; + do { /* TODO -- do a binary search? */ + /* TODO -- fix gen_mmap!*/ + ++lang_cult; /* Increment first since C/POSIX is 0. */ + if (!strncmp(s,p,5)) { /* Found a matching locale name; */ + goto FIND_LOCALE; + } + s += 5; + } while (lang_cult < __LOCALE_DATA_NUM_LOCALE_NAMES); + return 0; /* No matching language_culture! */ + + FIND_LOCALE: /* Find locale row matching name and codeset */ + s = LOCALES; + n = 0; + do { /* TODO -- do a binary search? */ + if ((lang_cult == *s) && ((codeset == s[1]) || (codeset == s[2]))) { + i = 1; + s = new_locale + 1; + do { + if (category_mask & i) { + /* Encode current locale row number. */ + ((unsigned char *) s)[0] = (n >> 7) | 0x80; + ((unsigned char *) s)[1] = (n & 0x7f) | 0x80; + } + s += 2; + i += i; + } while (i < (1 << LC_ALL)); + + return i; /* Return non-zero */ + } + s += __LOCALE_DATA_WIDTH_LOCALES; + ++n; + } while (n <= __LOCALE_DATA_NUM_LOCALES); /* We started at 1!!! */ + + return 0; /* Unsupported locale. */ +} + +static unsigned char *composite_locale(int category_mask, const char *locale, + unsigned char *new_locale) +{ + char buf[MAX_LOCALE_STR]; + char *t; + char *e; + int c; + int component_mask; + + if (!strchr(locale,'=')) { + if (!find_locale(category_mask, locale, new_locale)) { + return NULL; + } + return new_locale; + } + + if (strlen(locale) >= sizeof(buf)) { + return NULL; + } + stpcpy(buf, locale); + + component_mask = 0; + t = strtok_r(buf, "=", &e); /* This can't fail because of strchr test above. */ + do { + c = 0; + while (strcmp(CATEGORY_NAMES + (int) CATEGORY_NAMES[c], t)) { + if (++c == LC_ALL) { /* Unknown category name! */ + return NULL; + } + } + t = strtok_r(NULL, ";", &e); + c = (1 << c); + if (component_mask & c) { /* Multiple components for one category. */ + return NULL; + } + component_mask |= c; + if ((category_mask & c) && (!t || !find_locale(c, t, new_locale))) { + return NULL; + } + } while ((t = strtok_r(NULL, "=", &e)) != NULL); + + if (category_mask & ~component_mask) { /* Category component(s) missing. */ + return NULL; + } + + return new_locale; +} + +__locale_t __newlocale(int category_mask, const char *locale, __locale_t base) +{ + const unsigned char *p; + int i, j, k; + unsigned char new_selector[LOCALE_SELECTOR_SIZE]; + + if (!locale || (((unsigned int)(category_mask)) > LC_ALL_MASK)) { + INVALID: + __set_errno(EINVAL); + return NULL; /* No locale or illegal/unsupported category. */ + } + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: Rename cur_locale to locale_selector. +#endif + strcpy((char *) new_selector, + (base ? (char *) base->cur_locale : C_LOCALE_SELECTOR)); + + if (!*locale) { /* locale == "", so check environment. */ +#ifndef __UCLIBC_HAS_THREADS__ + static /* If no threads, then envstr can be static. */ +#endif /* __UCLIBC_HAS_THREADS__ */ + const char *envstr[4] = { "LC_ALL", NULL, "LANG", posix }; + + i = 1; + k = 0; + do { + if (category_mask & i) { + /* Note: SUSv3 doesn't define a fallback mechanism here. + * So, if LC_ALL is invalid, we do _not_ continue trying + * the other environment vars. */ + envstr[1] = CATEGORY_NAMES + CATEGORY_NAMES[k]; + j = 0; + do { + p = envstr[j]; + } while ((++j < 4) && (!(p = getenv(p)) || !*p)); + + + /* The user set something... is it valid? */ + /* Note: Since we don't support user-supplied locales and + * alternate paths, we don't need to worry about special + * handling for suid/sgid apps. */ + if (!find_locale(i, p, new_selector)) { + goto INVALID; + } + } + i += i; + } while (++k < LC_ALL); + } else if (!composite_locale(category_mask, locale, new_selector)) { + goto INVALID; + } + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: Do a compatible codeset check! +#endif + + /* If we get here, the new selector corresponds to a valid locale. */ + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning CONSIDER: Probably want a _locale_new func to allow for caching of locales. +#endif +#if 0 + if (base) { + _locale_set_l(new_selector, base); + } else { + base = _locale_new(new_selector); + } +#else + if (!base) { + if ((base = malloc(sizeof(__uclibc_locale_t))) == NULL) { + return base; + } + _locale_init_l(base); + } + + _locale_set_l(new_selector, base); +#endif + + return base; +} + +weak_alias(__newlocale, newlocale) + +#endif +/**********************************************************************/ +#ifdef L_duplocale + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: When we allocate ctype tables, remember to dup them. +#endif + +__locale_t duplocale(__locale_t dataset) +{ + __locale_t r; + uint16_t * i2w; + + assert(dataset != LC_GLOBAL_LOCALE); + + if ((r = malloc(sizeof(__uclibc_locale_t))) != NULL) { + if ((i2w = calloc(2*dataset->collate.max_col_index+2, + sizeof(uint16_t))) + != NULL + ) { + memcpy(r, dataset, sizeof(__uclibc_locale_t)); + r->collate.index2weight = i2w; + } else { + free(r); + r = NULL; + } + } + return r; +} + +#endif +/**********************************************************************/ +#ifdef L_freelocale + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: When we allocate ctype tables, remember to free them. +#endif + +void freelocale(__locale_t dataset) +{ + assert(dataset != __global_locale); + assert(dataset != LC_GLOBAL_LOCALE); + + free(dataset->collate.index2weight); /* Free collation data. */ + free(dataset); /* Free locale */ +} + +#endif +/**********************************************************************/ +#ifdef L_uselocale + +__locale_t uselocale(__locale_t dataset) +{ + __locale_t old; + + if (!dataset) { + old = __UCLIBC_CURLOCALE; + } else { + if (dataset == LC_GLOBAL_LOCALE) { + dataset = __global_locale; + } +#ifdef __UCLIBC_HAS_THREADS__ + old = __curlocale_set(dataset); +#else + old = __curlocale_var; + __curlocale_var = dataset; +#endif + } + + if (old == __global_locale) { + return LC_GLOBAL_LOCALE; + } + return old; +} + +#endif +/**********************************************************************/ +#ifdef L___curlocale + +#ifdef __UCLIBC_HAS_THREADS__ + +__locale_t weak_const_function __curlocale(void) +{ + return __curlocale_var; /* This is overriden by the thread version. */ +} + +__locale_t weak_function __curlocale_set(__locale_t newloc) +{ + assert(newloc != LC_GLOBAL_LOCALE); + + __locale_t oldloc = __curlocale_var; + __curlocale_var = newloc; + return oldloc; +} + +#endif + +#endif +/**********************************************************************/ +#ifdef L___locale_mbrtowc_l + +/* NOTE: This returns an int... not size_t. Also, it is not a general + * routine. It is actually a very stripped-down version of mbrtowc + * that takes a __locale_t arg. This is used by strcoll and strxfrm. + * It is also used above to generate wchar_t versions of the decimal point + * and thousands seperator. */ + + +#ifndef __CTYPE_HAS_UTF_8_LOCALES +#warning __CTYPE_HAS_UTF_8_LOCALES not set! +#endif +#ifndef __CTYPE_HAS_8_BIT_LOCALES +#warning __CTYPE_HAS_8_BIT_LOCALES not set! +#endif + +#define Cc2wc_IDX_SHIFT __LOCALE_DATA_Cc2wc_IDX_SHIFT +#define Cc2wc_ROW_LEN __LOCALE_DATA_Cc2wc_ROW_LEN + +extern size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn, + const char **__restrict src, size_t n, + mbstate_t *ps, int allow_continuation); + +int __locale_mbrtowc_l(wchar_t *__restrict dst, + const char *__restrict src, + __locale_t loc ) +{ +#ifdef __CTYPE_HAS_UTF_8_LOCALES + if (loc->encoding == __ctype_encoding_utf8) { + mbstate_t ps; + const char *p = src; + size_t r; + ps.mask = 0; + r = _wchar_utf8sntowcs(dst, 1, &p, SIZE_MAX, &ps, 1); + return (r == 1) ? (p-src) : r; /* Need to return 0 if nul char. */ + } +#endif + +#ifdef __CTYPE_HAS_8_BIT_LOCALES + assert((loc->encoding == __ctype_encoding_7_bit) || (loc->encoding == __ctype_encoding_8_bit)); +#else + assert(loc->encoding == __ctype_encoding_7_bit); +#endif + + if ((*dst = ((unsigned char)(*src))) < 0x80) { /* ASCII... */ + return (*src != 0); + } + +#ifdef __CTYPE_HAS_8_BIT_LOCALES + if (loc->encoding == __ctype_encoding_8_bit) { + wchar_t wc = *dst - 0x80; + *dst = __LOCALE_PTR->tbl8c2wc[ + (__LOCALE_PTR->idx8c2wc[wc >> Cc2wc_IDX_SHIFT] + << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))]; + if (*dst) { + return 1; + } + } +#endif + + return -1; +} + +#endif +/**********************************************************************/ diff --git a/libc/misc/time/Makefile b/libc/misc/time/Makefile index b5714e511..302214baf 100644 --- a/libc/misc/time/Makefile +++ b/libc/misc/time/Makefile @@ -28,15 +28,22 @@ MSRC= time.c MOBJ= asctime.o asctime_r.o clock.o ctime.o ctime_r.o gmtime.o gmtime_r.o \ localtime.o localtime_r.o mktime.o strftime.o strptime.o tzset.o \ _time_t2tm.o __time_tm.o _time_mktime.o dysize.o timegm.o +MOBJx= ifeq ($(UCLIBC_HAS_FLOATS),y) MOBJ += difftime.o endif +ifeq ($(UCLIBC_HAS_XLOCALE),y) + MOBJx += strftime_l.o strptime_l.o +endif + +ifeq ($(UCLIBC_HAS_WCHAR),y) +endif CSRC= adjtime.c ftime.c COBJS=$(patsubst %.c,%.o, $(CSRC)) -OBJS=$(COBJS) $(MOBJ) +OBJS=$(COBJS) $(MOBJ) $(MOBJx) all: $(OBJS) $(LIBC) @@ -49,6 +56,10 @@ $(MOBJ): $(MSRC) $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o $(STRIPTOOL) -x -R .note -R .comment $*.o +$(MOBJx): $(MSRC) + $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o + $(STRIPTOOL) -x -R .note -R .comment $*.o + $(COBJS): %.o : %.c $(CC) $(CFLAGS) -c $< -o $@ $(STRIPTOOL) -x -R .note -R .comment $*.o diff --git a/libc/misc/time/time.c b/libc/misc/time/time.c index 8d3cbc3b4..0ae91f69a 100644 --- a/libc/misc/time/time.c +++ b/libc/misc/time/time.c @@ -95,9 +95,32 @@ * * Nov 26, 2002 Fix bug in setting daylight and timezone when no (valid) TZ. * Bug reported by Arne Bernin in regards to freeswan. + * + * July 27, 2003 Adjust the struct tm extension field support. + * Change __tm_tzone back to a ptr and add the __tm_tzname[] buffer for + * __tm_tzone to point to. This gets around complaints from g++. + * Who knows... it might even fix the PPC timezone init problem. + * + * July 29, 2003 Fix a bug in mktime behavior when tm_isdst was -1. + * Bug reported by "Sid Wade" in regards to busybox. + * + * NOTE: uClibc mktime behavior is different than glibc's when + * the struct tm has tm_isdst == -1 and also had fields outside of + * the normal ranges. + * + * Apparently, glibc examines (at least) tm_sec and guesses the app's + * intention of assuming increasing or decreasing time when entering an + * ambiguous time period at the dst<->st boundaries. + * + * The uClibc behavior is to always normalize the struct tm and then + * try to determing the dst setting. + * + * As long as tm_isdst != -1 or the time specifiec by struct tm is + * unambiguous (not falling in the dst<->st transition region) both + * uClibc and glibc should produce the same result for mktime. + * */ - #define _GNU_SOURCE #define _STDIO_UTILITY #include @@ -112,6 +135,10 @@ #include #include +#ifdef __UCLIBC_HAS_XLOCALE__ +#include +#endif + #ifndef __isleap #define __isleap(y) ( !((y) % 4) && ( ((y) % 100) || !((y) % 400) ) ) #endif @@ -121,27 +148,26 @@ #endif /**********************************************************************/ - /* The era code is currently unfinished. */ /* #define ENABLE_ERA_CODE */ -#define __TIME_TZ_FILE -/* #define __TIME_TZ_FILE_ONCE */ - -#define __TIME_TZ_OPT_SPEED - #define TZ_BUFLEN (2*TZNAME_MAX + 56) -#ifdef __TIME_TZ_FILE +#ifdef __UCLIBC_HAS_TZ_FILE__ + #include #include #include #include "paths.h" /* ":+hh:mm:ss+hh:mm:ss,Mmm.w.d/hh:mm:ss,Mmm.w.d/hh:mm:ss" + nul */ /* 1 + 2*(1+TZNAME_MAX+1 + 9 + 7 + 9) + 1 = 2*TZNAME_MAX + 56 */ -#else /* __TIME_TZ_FILE */ -#undef __TIME_TZ_FILE_ONCE -#endif /* __TIME_TZ_FILE */ + +#else /* __UCLIBC_HAS_TZ_FILE__ */ + +/* Probably no longer needed. */ +#undef __UCLIBC_HAS_TZ_FILE_READ_MANY__ + +#endif /* __UCLIBC_HAS_TZ_FILE__ */ /**********************************************************************/ @@ -592,7 +618,8 @@ struct tm *localtime_r(register const time_t *__restrict timer, result->tm_isdst = dst; #ifdef __UCLIBC_HAS_TM_EXTENSIONS__ result->tm_gmtoff = - _time_tzinfo[dst].gmt_offset; - strcpy( (char *)(result->tm_zone), _time_tzinfo[dst].tzname); + result->tm_zone = result->__tm_tzname; + strcpy(result->__tm_tzname, _time_tzinfo[dst].tzname); #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */ } while ((++dst < 2) && (result->tm_isdst = tm_isdst(result)) != 0); @@ -617,7 +644,18 @@ time_t mktime(struct tm *timeptr) #endif /**********************************************************************/ -#ifdef L_strftime +#if defined(L_strftime) || defined(L_strftime_l) + +#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) + +size_t strftime(char *__restrict s, size_t maxsize, + const char *__restrict format, + const struct tm *__restrict timeptr) +{ + return strftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE); +} + +#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ #define NO_E_MOD 0x80 #define NO_O_MOD 0x40 @@ -811,9 +849,13 @@ static int load_field(int k, const struct tm *__restrict timeptr) #define MAX_PUSH 4 -size_t strftime(char *__restrict s, size_t maxsize, - const char *__restrict format, - const struct tm *__restrict timeptr) +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: Check multibyte format string validity. +#endif + +size_t __XL(strftime)(char *__restrict s, size_t maxsize, + const char *__restrict format, + const struct tm *__restrict timeptr __LOCALE_PARAM ) { long tzo; register const char *p; @@ -882,16 +924,19 @@ size_t strftime(char *__restrict s, size_t maxsize, + (code & 7); #ifdef ENABLE_ERA_CODE if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */ - && (*(o = nl_langinfo(_NL_ITEM(LC_TIME, - (int)(((unsigned char *)p)[4])) + && (*(o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, + (int)(((unsigned char *)p)[4])) + __LOCALE_ARG ))) ) { p = o; goto LOOP; } #endif - p = nl_langinfo(_NL_ITEM(LC_TIME, - (int)(*((unsigned char *)p)))); + p = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, + (int)(*((unsigned char *)p))) + __LOCALE_ARG + ); goto LOOP; } @@ -1037,7 +1082,7 @@ size_t strftime(char *__restrict s, size_t maxsize, if ((code & MASK_SPEC) == STRING_SPEC) { o_count = SIZE_MAX; field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)]; - o = nl_langinfo(_NL_ITEM(LC_TIME, field_val)); + o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, field_val) __LOCALE_ARG ); } else { o_count = ((i >> 1) & 3) + 1; o = buf + o_count; @@ -1061,9 +1106,31 @@ size_t strftime(char *__restrict s, size_t maxsize, goto LOOP; } +#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + #endif /**********************************************************************/ -#ifdef L_strptime +#if defined(L_strptime) || defined(L_strptime_l) + +#if defined(L_strptime) || defined(L_strptime_l) +#define ISDIGIT(C) __isdigit_char((C)) +#endif + +#ifdef __UCLIBC_DO_XLOCALE +#define ISSPACE(C) isspace_l((C), locale_arg) +#else +#define ISSPACE(C) isspace((C)) +#endif + +#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) + +char *strptime(const char *__restrict buf, const char *__restrict format, + struct tm *__restrict tm) +{ + return strptime_l(buf, format, tm, __UCLIBC_CURLOCALE); +} + +#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ /* TODO: * 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds. @@ -1207,8 +1274,8 @@ static const unsigned char spec[] = { #define MAX_PUSH 4 -char *strptime(const char *__restrict buf, const char *__restrict format, - struct tm *__restrict tm) +char *__XL(strptime)(const char *__restrict buf, const char *__restrict format, + struct tm *__restrict tm __LOCALE_PARAM) { register const char *p; char *o; @@ -1273,16 +1340,18 @@ char *strptime(const char *__restrict buf, const char *__restrict format, + (code & 7); #ifdef ENABLE_ERA_CODE if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */ - && (*(o = nl_langinfo(_NL_ITEM(LC_TIME, - (int)(((unsigned char *)p)[4])) - ))) + && (*(o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, + (int)(((unsigned char *)p)[4])) + __LOCALE_ARG + ))) ) { p = o; goto LOOP; } #endif - p = nl_langinfo(_NL_ITEM(LC_TIME, - (int)(*((unsigned char *)p)))); + p = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, + (int)(*((unsigned char *)p))) + __LOCALE_ARG ); goto LOOP; } @@ -1295,9 +1364,9 @@ char *strptime(const char *__restrict buf, const char *__restrict format, /* Go backwards to check full names before abreviations. */ do { --j; - o = nl_langinfo(i+j); - if (!strncasecmp(buf,o,strlen(o)) && *o) { /* Found a match. */ - do { + o = __XL(nl_langinfo)(i+j __LOCALE_ARG); + if (!__XL(strncasecmp)(buf,o,strlen(o) __LOCALE_ARG) && *o) { + do { /* Found a match. */ ++buf; } while (*++o); if (!code) { /* am/pm */ @@ -1322,11 +1391,11 @@ char *strptime(const char *__restrict buf, const char *__restrict format, o = (char *) buf; i = errno; __set_errno(0); - if (!isspace(*buf)) { /* Signal an error if whitespace. */ + if (!ISSPACE(*buf)) { /* Signal an error if whitespace. */ #ifdef TIME_T_IS_UNSIGNED - t = strtoul(buf, &o, 10); + t = __XL(strtoul)(buf, &o, 10 __LOCALE_ARG); #else - t = strtol(buf, &o, 10); + t = __XL(strtol)(buf, &o, 10 __LOCALE_ARG); #endif } if ((o == buf) || errno) { /* Not a number or overflow. */ @@ -1356,7 +1425,7 @@ char *strptime(const char *__restrict buf, const char *__restrict format, j = ((j==1) ? 366 : 9999); } i = -1; - while (isdigit(*buf)) { + while (ISDIGIT(*buf)) { if (i < 0) { i = 0; } @@ -1401,9 +1470,9 @@ char *strptime(const char *__restrict buf, const char *__restrict format, } } goto LOOP; - } else if (isspace(*p)) { + } else if (ISSPACE(*p)) { ++p; - while (isspace(*buf)) { + while (ISSPACE(*buf)) { ++buf; } goto LOOP; @@ -1413,6 +1482,8 @@ char *strptime(const char *__restrict buf, const char *__restrict format, return NULL; } +#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + #endif /**********************************************************************/ #ifdef L_time @@ -1478,10 +1549,10 @@ static const char *getoffset(register const char *e, long *pn) f = -1; do { ++s; - if (isdigit(*e)) { + if (__isdigit_char(*e)) { f = *e++ - '0'; } - if (isdigit(*e)) { + if (__isdigit_char(*e)) { f = 10 * f + (*e++ - '0'); } if (((unsigned int)f) >= *s) { @@ -1507,7 +1578,7 @@ static const char *getnumber(register const char *e, int *pn) int f; f = 0; - while (n && isdigit(*e)) { + while (n && __isdigit_char(*e)) { f = 10 * f + (*e++ - '0'); --n; } @@ -1519,7 +1590,7 @@ static const char *getnumber(register const char *e, int *pn) n = 3; f = 0; - while (n && isdigit(*e)) { + while (n && __isdigit_char(*e)) { f = 10 * f + (*e++ - '0'); --n; } @@ -1529,11 +1600,16 @@ static const char *getnumber(register const char *e, int *pn) #endif /* __BCC__ */ } -#ifdef __TIME_TZ_FILE -#ifdef __TIME_TZ_FILE_ONCE +#ifdef __UCLIBC_MJN3_ONLY__ +#warning CONSIDER: Should we preserve errno from open/read/close errors re TZ file? +#endif + +#ifdef __UCLIBC_HAS_TZ_FILE__ + +#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__ static int TZ_file_read; /* Let BSS initialization set this to 0. */ -#endif /* __TIME_TZ_FILE_ONCE */ +#endif /* __UCLIBC_HAS_TZ_FILE_READ_MANY__ */ static char *read_TZ_file(char *buf) { @@ -1542,7 +1618,7 @@ static char *read_TZ_file(char *buf) size_t todo; char *p = NULL; - if ((fd = open("/etc/TZ", O_RDONLY)) >= 0) { + if ((fd = open(__UCLIBC_TZ_FILE_PATH__, O_RDONLY)) >= 0) { todo = TZ_BUFLEN; p = buf; do { @@ -1559,9 +1635,9 @@ static char *read_TZ_file(char *buf) if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline. */ p[-1] = 0; p = buf; -#ifdef __TIME_TZ_FILE_ONCE +#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__ ++TZ_file_read; -#endif /* __TIME_TZ_FILE_ONCE */ +#endif /* __UCLIBC_HAS_TZ_FILE_READ_MANY__ */ } else { ERROR: p = NULL; @@ -1571,7 +1647,7 @@ static char *read_TZ_file(char *buf) return p; } -#endif /* __TIME_TZ_FILE */ +#endif /* __UCLIBC_HAS_TZ_FILE__ */ void tzset(void) { @@ -1582,18 +1658,18 @@ void tzset(void) rule_struct new_rules[2]; int n, count, f; char c; -#ifdef __TIME_TZ_FILE +#ifdef __UCLIBC_HAS_TZ_FILE__ char buf[TZ_BUFLEN]; -#endif /* __TIME_TZ_FILE */ -#ifdef __TIME_TZ_OPT_SPEED +#endif /* __UCLIBC_HAS_TZ_FILE__ */ +#ifdef __UCLIBC_HAS_TZ_CACHING__ static char oldval[TZ_BUFLEN]; /* BSS-zero'd. */ -#endif /* __TIME_TZ_OPT_SPEED */ +#endif /* __UCLIBC_HAS_TZ_CACHING__ */ TZLOCK; e = getenv(TZ); /* TZ env var always takes precedence. */ -#ifdef __TIME_TZ_FILE_ONCE +#if defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__) /* Put this inside the lock to prevent the possiblity of two different * timezones being used in a threaded app. */ @@ -1602,7 +1678,7 @@ void tzset(void) } else if (TZ_file_read > 0) { goto FAST_DONE; } -#endif /* __TIME_TZ_FILE_ONCE */ +#endif /* defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__) */ /* Warning!!! Since uClibc doesn't do lib locking, the following is * potentially unsafe in a multi-threaded program since it is remotely @@ -1610,14 +1686,14 @@ void tzset(void) * the string being parsed. So, don't do that... */ if ((!e /* TZ env var not set... */ -#ifdef __TIME_TZ_FILE +#ifdef __UCLIBC_HAS_TZ_FILE__ && !(e = read_TZ_file(buf)) /* and no file or invalid file */ -#endif /* __TIME_TZ_FILE */ +#endif /* __UCLIBC_HAS_TZ_FILE__ */ ) || !*e) { /* or set to empty string. */ ILLEGAL: /* TODO: Clean up the following... */ -#ifdef __TIME_TZ_OPT_SPEED +#ifdef __UCLIBC_HAS_TZ_CACHING__ *oldval = 0; /* Set oldval to an empty string. */ -#endif /* __TIME_TZ_OPT_SPEED */ +#endif /* __UCLIBC_HAS_TZ_CACHING__ */ s = _time_tzinfo[0].tzname; *s = 'U'; *++s = 'T'; @@ -1632,7 +1708,7 @@ void tzset(void) ++e; } -#ifdef __TIME_TZ_OPT_SPEED +#ifdef __UCLIBC_HAS_TZ_CACHING__ if (strcmp(e, oldval) == 0) { /* Same string as last time... */ goto FAST_DONE; /* So nothing to do. */ } @@ -1640,7 +1716,7 @@ void tzset(void) * it is too long, but it that case it will be illegal and will be reset * to the empty string anyway. */ strncpy(oldval, e, TZ_BUFLEN); -#endif /* __TIME_TZ_OPT_SPEED */ +#endif /* __UCLIBC_HAS_TZ_CACHING__ */ count = 0; new_rules[1].tzname[0] = 0; @@ -1675,7 +1751,7 @@ void tzset(void) /* Get offset */ s = (char *) e; if ((*e != '-') && (*e != '+')) { - if (count && !isdigit(*e)) { + if (count && !__isdigit_char(*e)) { off -= 3600; /* Default to 1 hour ahead of std. */ goto SKIP_OFFSET; } @@ -1938,8 +2014,9 @@ struct tm *_time_t2tm(const time_t *__restrict timer, p[4] = 0; /* result[8] .. tm_isdst */ #ifdef __UCLIBC_HAS_TM_EXTENSIONS__ result->tm_gmtoff = 0; + result->tm_zone = result->__tm_tzname; { - register char *s = (char *) result->tm_zone; + register char *s = result->__tm_tzname; *s = 'U'; *++s = 'T'; *++s = 'C'; @@ -1977,12 +2054,16 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success) /* 0:sec 1:min 2:hour 3:mday 4:mon 5:year 6:wday 7:yday 8:isdst */ register int *p = (int *) &x; register const unsigned char *s; - int d; + int d, default_dst; tzset(); memcpy(p, timeptr, sizeof(struct tm)); + if ((default_dst = p[8]) < 0) { + default_dst = 1; /* Assume advancing */ + } + d = 400; p[5] = (p[5] - ((p[6] = p[5]/d) * d)) + (p[7] = p[4]/12); if ((p[4] -= 12 * p[7]) < 0) { @@ -2007,49 +2088,69 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success) --d; } + TZLOCK; + #ifdef __BCC__ d = p[5] - 1; 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; + + _time_tzinfo[default_dst].gmt_offset; + DST_CORRECT: if (secs < 0) { secs += 120009600L; days -= 1389; } if ( ((unsigned long)(days + secs/86400L)) > 49710L) { - return -1; + t = ((time_t)(-1)); + goto DONE; } secs += (days * 86400L); #else - TZLOCK; d = p[5] - 1; d = -719163L + d*365 + (d/4) - (d/100) + (d/400); secs = p[0] - + _time_tzinfo[timeptr->tm_isdst > 0].gmt_offset + + _time_tzinfo[default_dst].gmt_offset + 60*( p[1] + 60*(p[2] + 24*(((146073L * ((long long)(p[6])) + d) + p[3]) + p[7]))); - TZUNLOCK; + + DST_CORRECT: if (((unsigned long long)(secs - LONG_MIN)) > (((unsigned long long)LONG_MAX) - LONG_MIN) ) { - return -1; + t = ((time_t)(-1)); + goto DONE; } #endif + d = ((struct tm *)p)->tm_isdst; t = secs; localtime_r(&t, (struct tm *)p); - if (t < 0) { - return -1; + if (t == ((time_t)(-1))) { /* Remember, time_t can be unsigned. */ + goto DONE; + } + + if ((d < 0) && (((struct tm *)p)->tm_isdst != default_dst)) { +#ifdef __BCC__ + secs -= (days * 86400L); +#endif + secs += (_time_tzinfo[1-default_dst].gmt_offset + - _time_tzinfo[default_dst].gmt_offset); + goto DST_CORRECT; } + if (store_on_success) { memcpy(timeptr, p, sizeof(struct tm)); } + + DONE: + TZUNLOCK; + return t; } diff --git a/libc/misc/wchar/Makefile b/libc/misc/wchar/Makefile index acc852195..4a3e2fc7a 100644 --- a/libc/misc/wchar/Makefile +++ b/libc/misc/wchar/Makefile @@ -42,7 +42,6 @@ MOBJ2= fwide.o \ # getwc (fgetwc alias) getwc_unlocked (fgetwc_unlocked alias) # putwc (fputwc alias) putwc_unlocked (fputwc_unlocked alias) -# fwscanf wscanf swscanf vfwscanf vwscanf vswscanf # wcsftime OBJS=$(MOBJ1) $(MOBJ2) diff --git a/libc/misc/wchar/wchar.c b/libc/misc/wchar/wchar.c index ff3e42a84..aa0c2735a 100644 --- a/libc/misc/wchar/wchar.c +++ b/libc/misc/wchar/wchar.c @@ -86,6 +86,9 @@ * Add a couple of ugly hacks to support *wprintf. * Add a mini iconv() and iconv implementation (requires locale support). * + * Aug 1, 2003 + * Bug fix for mbrtowc. + * * Manuel */ @@ -101,13 +104,39 @@ #include #include #include +#include +/**********************************************************************/ #ifdef __UCLIBC_HAS_LOCALE__ -#define ENCODING (__global_locale.encoding) +#ifdef __UCLIBC_MJN3_ONLY__ +#ifdef L_iswspace +/* generates one warning */ +#warning TODO: Fix Cc2wc* and Cwc2c* defines! +#endif +#endif /* __UCLIBC_MJN3_ONLY__ */ + +#define ENCODING ((__UCLIBC_CURLOCALE_DATA).encoding) + +#define Cc2wc_IDX_SHIFT __LOCALE_DATA_Cc2wc_IDX_SHIFT +#define Cc2wc_ROW_LEN __LOCALE_DATA_Cc2wc_ROW_LEN +#define Cwc2c_DOMAIN_MAX __LOCALE_DATA_Cwc2c_DOMAIN_MAX +#define Cwc2c_TI_SHIFT __LOCALE_DATA_Cwc2c_TI_SHIFT +#define Cwc2c_TT_SHIFT __LOCALE_DATA_Cwc2c_TT_SHIFT +#define Cwc2c_TI_LEN __LOCALE_DATA_Cwc2c_TI_LEN + #ifndef __CTYPE_HAS_UTF_8_LOCALES #warning __CTYPE_HAS_UTF_8_LOCALES not set! #endif -#else + +#else /* __UCLIBC_HAS_LOCALE__ */ + +#ifdef __UCLIBC_MJN3_ONLY__ +#ifdef L_btowc +/* emit only once */ +#warning fix preprocessor logic testing locale settings +#endif +#endif + #define ENCODING (__ctype_encoding_7_bit) #ifdef __CTYPE_HAS_8_BIT_LOCALES #error __CTYPE_HAS_8_BIT_LOCALES is defined! @@ -117,7 +146,9 @@ #endif #undef L__wchar_utf8sntowcs #undef L__wchar_wcsntoutf8s -#endif + +#endif /* __UCLIBC_HAS_LOCALE__ */ +/**********************************************************************/ #if WCHAR_MAX > 0xffffUL #define UTF_8_MAX_LEN 6 @@ -266,11 +297,18 @@ size_t mbrtowc(wchar_t *__restrict pwc, const char *__restrict s, #ifdef __CTYPE_HAS_UTF_8_LOCALES /* Need to do this here since mbsrtowcs doesn't allow incompletes. */ if (ENCODING == __ctype_encoding_utf8) { + if (!pwc) { + pwc = wcbuf; + } r = _wchar_utf8sntowcs(pwc, 1, &p, n, ps, 1); return (r == 1) ? (p-s) : r; /* Need to return 0 if nul char. */ } #endif +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: This adds a trailing nul! +#endif /* __UCLIBC_MJN3_ONLY__ */ + r = __mbsnrtowcs(wcbuf, &p, SIZE_MAX, 1, ps); if (((ssize_t) r) >= 0) { @@ -291,7 +329,10 @@ size_t mbrtowc(wchar_t *__restrict pwc, const char *__restrict s, size_t wcrtomb(register char *__restrict s, wchar_t wc, mbstate_t *__restrict ps) { - wchar_t wcbuf[2]; +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: Should wcsnrtombs nul-terminate unconditionally? Check glibc. +#endif /* __UCLIBC_MJN3_ONLY__ */ + wchar_t wcbuf[1]; const wchar_t *pwc; size_t r; char buf[MB_LEN_MAX]; @@ -303,9 +344,8 @@ size_t wcrtomb(register char *__restrict s, wchar_t wc, pwc = wcbuf; wcbuf[0] = wc; - wcbuf[1] = 0; - r = __wcsnrtombs(s, &pwc, SIZE_MAX, MB_LEN_MAX, ps); + r = __wcsnrtombs(s, &pwc, 1, MB_LEN_MAX, ps); return (r != 0) ? r : 1; } @@ -418,7 +458,7 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn, if ((wc = ((unsigned char) *s++)) >= 0x80) { /* Not ASCII... */ mask = 0x40; #ifdef __UCLIBC_MJN3_ONLY__ -#warning fix range for 16 bit wides +#warning TODO: Fix range for 16 bit wchar_t case. #endif if ( ((unsigned char)(s[-1] - 0xc0)) < (0xfe - 0xc0) ) { goto START; @@ -495,7 +535,6 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn, COMPLETE: *pwc = wc; pwc += incr; - } #ifdef DECODER while (--count); @@ -684,8 +723,8 @@ size_t __mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src, while (count) { if ((wc = ((unsigned char)(*s))) >= 0x80) { /* Non-ASCII... */ wc -= 0x80; - wc = __global_locale.tbl8c2wc[ - (__global_locale.idx8c2wc[wc >> Cc2wc_IDX_SHIFT] + wc = __UCLIBC_CURLOCALE_DATA.tbl8c2wc[ + (__UCLIBC_CURLOCALE_DATA.idx8c2wc[wc >> Cc2wc_IDX_SHIFT] << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))]; if (!wc) { goto BAD; @@ -797,12 +836,12 @@ size_t __wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src, } else { u = 0; if (wc <= Cwc2c_DOMAIN_MAX) { - u = __global_locale.idx8wc2c[wc >> (Cwc2c_TI_SHIFT + u = __UCLIBC_CURLOCALE_DATA.idx8wc2c[wc >> (Cwc2c_TI_SHIFT + Cwc2c_TT_SHIFT)]; - u = __global_locale.tbl8wc2c[(u << Cwc2c_TI_SHIFT) + u = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[(u << Cwc2c_TI_SHIFT) + ((wc >> Cwc2c_TT_SHIFT) & ((1 << Cwc2c_TI_SHIFT)-1))]; - u = __global_locale.tbl8wc2c[Cwc2c_TI_LEN + u = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[Cwc2c_TI_LEN + (u << Cwc2c_TT_SHIFT) + (wc & ((1 << Cwc2c_TT_SHIFT)-1))]; } @@ -859,7 +898,8 @@ size_t __wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src, #ifdef L_wcswidth #ifdef __UCLIBC_MJN3_ONLY__ -#warning if we start doing translit, wcwidth and wcswidth will need updating. +#warning REMINDER: If we start doing translit, wcwidth and wcswidth will need updating. +#warning TODO: Update wcwidth to match latest by Kuhn. #endif #if defined(__UCLIBC_HAS_LOCALE__) && \ @@ -1163,7 +1203,7 @@ enum { * */ -const unsigned char codesets[] = +const unsigned char __iconv_codesets[] = "\x0a\xe0""WCHAR_T\x00" /* superset of UCS-4 but platform-endian */ #if __BYTE_ORDER == __BIG_ENDIAN "\x08\xec""UCS-4\x00" /* always BE */ @@ -1201,7 +1241,7 @@ static int find_codeset(const char *name) const unsigned char *s; int codeset; - for (s = codesets ; *s ; s += *s) { + for (s = __iconv_codesets ; *s ; s += *s) { if (!strcasecmp(s+2, name)) { return s[1]; } @@ -1212,10 +1252,10 @@ static int find_codeset(const char *name) /* TODO: maybe CODESET_LIST + *s ??? */ /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */ codeset = 2; - s = CODESET_LIST; + s = __LOCALE_DATA_CODESET_LIST; do { ++codeset; /* Increment codeset first. */ - if (!strcasecmp(CODESET_LIST+*s, name)) { + if (!strcasecmp(__LOCALE_DATA_CODESET_LIST+*s, name)) { return codeset; } } while (*++s); @@ -1223,7 +1263,7 @@ static int find_codeset(const char *name) return 0; /* No matching codeset! */ } -iconv_t iconv_open(const char *tocode, const char *fromcode) +iconv_t weak_function iconv_open(const char *tocode, const char *fromcode) { register _UC_iconv_t *px; int tocodeset, fromcodeset; @@ -1244,16 +1284,17 @@ iconv_t iconv_open(const char *tocode, const char *fromcode) return (iconv_t)(-1); } -int iconv_close(iconv_t cd) +int weak_function iconv_close(iconv_t cd) { free(cd); return 0; } -size_t iconv(iconv_t cd, char **__restrict inbuf, - size_t *__restrict inbytesleft, - char **__restrict outbuf, size_t *__restrict outbytesleft) +size_t weak_function iconv(iconv_t cd, char **__restrict inbuf, + size_t *__restrict inbytesleft, + char **__restrict outbuf, + size_t *__restrict outbytesleft) { _UC_iconv_t *px = (_UC_iconv_t *) cd; size_t nrcount, r; @@ -1362,9 +1403,9 @@ size_t iconv(iconv_t cd, char **__restrict inbuf, return (size_t)(-1); } #ifdef __UCLIBC_MJN3_ONLY__ -#warning optimize this +#warning TODO: optimize this. #endif - if (p != NULL) { /* incomplet char case */ + if (p != NULL) { /* incomplete char case */ goto INVALID; } p = *inbuf + 1; /* nul */ @@ -1374,10 +1415,10 @@ size_t iconv(iconv_t cd, char **__restrict inbuf, if (px->fromcodeset == IC_ASCII) { /* US-ASCII codeset */ goto ILLEGAL; } else { /* some other 8-bit ascii-extension codeset */ - const codeset_8_bit_t *c8b + const __codeset_8_bit_t *c8b = __locale_mmap->codeset_8_bit + px->fromcodeset - 3; wc -= 0x80; - wc = __global_locale.tbl8c2wc[ + wc = __UCLIBC_CURLOCALE_DATA.tbl8c2wc[ (c8b->idx8c2wc[wc >> Cc2wc_IDX_SHIFT] << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))]; if (!wc) { @@ -1439,7 +1480,7 @@ size_t iconv(iconv_t cd, char **__restrict inbuf, r = _wchar_wcsntoutf8s(*outbuf, *outbytesleft, &pw, 1); if (r != (size_t)(-1)) { #ifdef __UCLIBC_MJN3_ONLY__ -#warning what happens for a nul? +#warning TODO: What happens for a nul? #endif if (r == 0) { if (wc != 0) { @@ -1458,14 +1499,14 @@ size_t iconv(iconv_t cd, char **__restrict inbuf, **outbuf = wc; } else { if ((px->tocodeset != 0x01) && (wc <= Cwc2c_DOMAIN_MAX)) { - const codeset_8_bit_t *c8b + const __codeset_8_bit_t *c8b = __locale_mmap->codeset_8_bit + px->tocodeset - 3; __uwchar_t u; u = c8b->idx8wc2c[wc >> (Cwc2c_TI_SHIFT + Cwc2c_TT_SHIFT)]; - u = __global_locale.tbl8wc2c[(u << Cwc2c_TI_SHIFT) + u = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[(u << Cwc2c_TI_SHIFT) + ((wc >> Cwc2c_TT_SHIFT) & ((1 << Cwc2c_TI_SHIFT)-1))]; - wc = __global_locale.tbl8wc2c[Cwc2c_TI_LEN + wc = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[Cwc2c_TI_LEN + (u << Cwc2c_TT_SHIFT) + (wc & ((1 << Cwc2c_TT_SHIFT)-1))]; if (wc) { @@ -1497,7 +1538,7 @@ size_t iconv(iconv_t cd, char **__restrict inbuf, #include #include -extern const unsigned char codesets[]; +extern const unsigned char __iconv_codesets[]; #define IBUF BUFSIZ #define OBUF BUFSIZ @@ -1572,12 +1613,12 @@ int main(int argc, char **argv) if (opts[5]) { /* -l */ fprintf(stderr, "Recognized codesets:\n"); - for (s = codesets ; *s ; s += *s) { + for (s = __iconv_codesets ; *s ; s += *s) { fprintf(stderr," %s\n", s+2); } - s = CODESET_LIST; + s = __LOCALE_DATA_CODESET_LIST; do { - fprintf(stderr," %s\n", CODESET_LIST+ (unsigned char)(*s)); + fprintf(stderr," %s\n", __LOCALE_DATA_CODESET_LIST+ (unsigned char)(*s)); } while (*++s); return EXIT_SUCCESS; diff --git a/libc/misc/wchar/wstdio.c b/libc/misc/wchar/wstdio.c index dfeb35c30..1069ee938 100644 --- a/libc/misc/wchar/wstdio.c +++ b/libc/misc/wchar/wstdio.c @@ -171,7 +171,6 @@ UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream)) 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. */ @@ -183,8 +182,18 @@ UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream)) stream->modeflags |= __FLAG_WIDE; if (stream->modeflags & __MASK_UNGOT) {/* Any ungetwc()s? */ - assert( (stream->modeflags & (__FLAG_READING|__FLAG_ERROR)) - == __FLAG_READING); + + assert(stream->modeflags & __FLAG_READING); + +/* assert( (stream->modeflags & (__FLAG_READING|__FLAG_ERROR)) */ +/* == __FLAG_READING); */ + + if ((((stream->modeflags & __MASK_UNGOT) > 1) || stream->ungot[1])) { + stream->ungot_width[0] = 0; /* Application ungot... */ + } else { + stream->ungot_width[0] = stream->ungot_width[1]; /* scanf ungot */ + } + wi = stream->ungot[(--stream->modeflags) & __MASK_UNGOT]; stream->ungot[1] = 0; goto DONE; @@ -196,7 +205,9 @@ UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream)) ++stream->bufend; } - ungot_width = 0; + if (stream->state.mask == 0) { /* If last was a complete char */ + stream->ungot_width[0] = 0; /* then reset the width. */ + } LOOP: if ((n = stream->bufread - stream->bufpos) == 0) { @@ -204,12 +215,12 @@ UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream)) } r = mbrtowc(wc, stream->bufpos, n, &stream->state); - if (((ssize_t) r) >= 0) { /* Single byte... */ + if (((ssize_t) r) >= 0) { /* Success... */ 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; + stream->ungot_width[0] += r; wi = *wc; goto DONE; } @@ -217,7 +228,7 @@ UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream)) if (r == ((size_t) -2)) { /* Potentially valid but incomplete and no more buffered. */ stream->bufpos += n; /* Update bufpos for stream. */ - ungot_width += n; + stream->ungot_width[0] += n; FILL_BUFFER: if (_stdio_fread(c, (size_t) 1, stream) > 0) { assert(stream->bufpos == stream->bufstart + 1); @@ -371,7 +382,8 @@ UNLOCKED(int,fputws,(const wchar_t *__restrict ws, #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. + * should also set stream->ungot[1] to 0 if this is the only ungot, as well + * as reset stream->ungot_width[1] for use by _stdio_adjpos(). */ /* Reentrant. */ @@ -389,8 +401,7 @@ wint_t ungetwc(wint_t c, register FILE *stream) } 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 can't read or c == WEOF or ungot slots already filled, then fail. */ if ((stream->modeflags & (__MASK_UNGOT2|__FLAG_WRITEONLY #ifndef __STDIO_AUTO_RW_TRANSITION @@ -406,14 +417,18 @@ wint_t ungetwc(wint_t c, register FILE *stream) /* ungot_width */ #ifdef __STDIO_BUFFERS - /* TODO: shouldn't allow writing??? */ +#ifdef __STDIO_AUTO_RW_TRANSITION if (stream->modeflags & __FLAG_WRITING) { fflush_unlocked(stream); /* Commit any write-buffered chars. */ } +#endif /* __STDIO_AUTO_RW_TRANSITION */ #endif /* __STDIO_BUFFERS */ /* Clear EOF and WRITING flags, and set READING FLAG */ stream->modeflags &= ~(__FLAG_EOF|__FLAG_WRITING); +#ifdef __UCLIBC_MJN3_ONLY__ +#warning CONSIDER: Is setting the reading flag after an ungetwc necessary? +#endif /* __UCLIBC_MJN3_ONLY__ */ stream->modeflags |= __FLAG_READING; stream->ungot[1] = 1; /* Flag as app ungetc call; wscanf fixes up. */ stream->ungot[(stream->modeflags++) & __MASK_UNGOT] = c; diff --git a/libc/misc/wctype/Makefile b/libc/misc/wctype/Makefile index 875ccef56..44734945c 100644 --- a/libc/misc/wctype/Makefile +++ b/libc/misc/wctype/Makefile @@ -25,12 +25,22 @@ TOPDIR=../../../ include $(TOPDIR)Rules.mak MSRC= wctype.c -MOBJ= iswalnum.o iswalpha.o iswcntrl.o iswdigit.o iswgraph.o iswlower.o \ - iswprint.o iswpunct.o iswspace.o iswupper.o iswxdigit.o towlower.o \ - towupper.o iswblank.o wctype.o iswctype.o wctrans.o towctrans.o +MOBJ= iswalnum.o iswalpha.o iswcntrl.o iswdigit.o iswgraph.o \ + iswlower.o iswprint.o iswpunct.o iswspace.o iswupper.o \ + iswxdigit.o iswblank.o wctrans.o towctrans.o \ + wctype.o iswctype.o towlower.o towupper.o + +MOBJx= iswalnum_l.o iswalpha_l.o iswcntrl_l.o iswdigit_l.o iswgraph_l.o \ + iswlower_l.o iswprint_l.o iswpunct_l.o iswspace_l.o iswupper_l.o \ + iswxdigit_l.o iswblank_l.o \ + wctype_l.o iswctype_l.o wctrans_l.o towctrans_l.o towlower_l.o towupper_l.o OBJS=$(MOBJ) +ifeq ($(UCLIBC_HAS_XLOCALE),y) + OBJS += $(MOBJx) +endif + all: $(OBJS) $(LIBC) $(LIBC): ar-target @@ -42,6 +52,10 @@ $(MOBJ): $(MSRC) $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o $(STRIPTOOL) -x -R .note -R .comment $*.o +$(MOBJx): $(MSRC) + $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o + $(STRIPTOOL) -x -R .note -R .comment $*.o + clean: rm -f *.[oa] *~ core diff --git a/libc/misc/wctype/wctype.c b/libc/misc/wctype/wctype.c index 68b9e4579..e0dde3a1f 100644 --- a/libc/misc/wctype/wctype.c +++ b/libc/misc/wctype/wctype.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Manuel Novoa III +/* Copyright (C) 2002, 2003 Manuel Novoa III * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -35,148 +35,308 @@ #include #include #include +#include +#include + +#if defined(__LOCALE_C_ONLY) && defined(__UCLIBC_DO_XLOCALE) +#error xlocale functionality is not supported in stub locale mode. +#endif + +#ifdef __UCLIBC_HAS_XLOCALE__ +#include + +extern int __iswctype_l (wint_t __wc, wctype_t __desc, __locale_t __locale); + __THROW; +extern wint_t __towlower_l (wint_t __wc, __locale_t __locale) __THROW; + +extern wint_t __towupper_l (wint_t __wc, __locale_t __locale) __THROW; +extern wint_t __towctrans_l (wint_t __wc, wctrans_t __desc, + __locale_t __locale) __THROW; + +#endif /* __UCLIBC_HAS_XLOCALE__ */ /* We know wide char support is enabled. We wouldn't be here otherwise. */ /* Define this if you want to unify the towupper and towlower code in the * towctrans function. */ -/* #define SMALL_UPLOW */ +/* #define SMALL_UPLOW */ -#ifndef __LOCALE_C_ONLY -#define __WCTYPE_WITH_LOCALE +/**********************************************************************/ +#ifdef __UCLIBC_MJN3_ONLY__ +#ifdef L_iswspace +/* generates one warning */ +#warning TODO: Fix the __CTYPE_* codes! +#endif +#endif /* __UCLIBC_MJN3_ONLY__ */ + +#if 1 +/* Taking advantage of the C99 mutual-exclusion guarantees for the various + * (w)ctype classes, including the descriptions of printing and control + * (w)chars, we can place each in one of the following mutually-exlusive + * subsets. Since there are less than 16, we can store the data for + * each (w)chars in a nibble. In contrast, glibc uses an unsigned int + * per (w)char, with one bit flag for each is* type. While this allows + * a simple '&' operation to determine the type vs. a range test and a + * little special handling for the "blank" and "xdigit" types in my + * approach, it also uses 8 times the space for the tables on the typical + * 32-bit archs we supported.*/ +enum { + __CTYPE_unclassified = 0, + __CTYPE_alpha_nonupper_nonlower, + __CTYPE_alpha_lower, + __CTYPE_alpha_upper_lower, + __CTYPE_alpha_upper, + __CTYPE_digit, + __CTYPE_punct, + __CTYPE_graph, + __CTYPE_print_space_nonblank, + __CTYPE_print_space_blank, + __CTYPE_space_nonblank_noncntrl, + __CTYPE_space_blank_noncntrl, + __CTYPE_cntrl_space_nonblank, + __CTYPE_cntrl_space_blank, + __CTYPE_cntrl_nonspace +}; #endif -/**********************************************************************/ -#ifndef __PASTE -#define __PASTE(X,Y) X ## Y +/* The following is used to implement wctype(), but it is defined + * here because the ordering must agree with that of the enumeration + * below (ignoring unclassified). */ +#define __CTYPE_TYPESTRING \ + "\6alnum\0\6alpha\0\6blank\0\6cntrl\0\6digit\0\6graph\0\6lower\0" \ + "\6print\0\6punct\0\6space\0\6upper\0\7xdigit\0\0" + + +/* The values for wctype_t. */ +enum { + _CTYPE_unclassified = 0, + _CTYPE_isalnum, + _CTYPE_isalpha, + _CTYPE_isblank, + _CTYPE_iscntrl, + _CTYPE_isdigit, + _CTYPE_isgraph, + _CTYPE_islower, + _CTYPE_isprint, + _CTYPE_ispunct, + _CTYPE_isspace, + _CTYPE_isupper, + _CTYPE_isxdigit /* _MUST_ be last of the standard classes! */ +}; + +/* The following is used to implement wctrans(). */ + +#define __CTYPE_TRANSTRING "\10tolower\0\10toupper\0\10totitle\0\0" + +enum { + _CTYPE_tolower = 1, + _CTYPE_toupper, + _CTYPE_totitle +}; + +/*--------------------------------------------------------------------*/ + +#define _CTYPE_iswxdigit (_CTYPE_isxdigit) + +/*--------------------------------------------------------------------*/ + +#ifdef __UCLIBC_MJN3_ONLY__ +#ifdef L_iswspace +/* generates one warning */ +#warning TODO: Fix WC* defines! #endif +#endif /* __UCLIBC_MJN3_ONLY__ */ -#define C_MACRO(X) __PASTE(__C_,X)(wc) +#define ENCODING ((__UCLIBC_CURLOCALE_DATA).encoding) -#define CT_MACRO(X) __PASTE(__ctype_,X)(wc) +#define WCctype ((__UCLIBC_CURLOCALE_DATA).tblwctype) +#define WCuplow ((__UCLIBC_CURLOCALE_DATA).tblwuplow) +#define WCcmob ((__UCLIBC_CURLOCALE_DATA).tblwcomb) +#define WCuplow_diff ((__UCLIBC_CURLOCALE_DATA).tblwuplow_diff) + + +#define WC_TABLE_DOMAIN_MAX __LOCALE_DATA_WC_TABLE_DOMAIN_MAX + +#define WCctype_II_LEN __LOCALE_DATA_WCctype_II_LEN +#define WCctype_TI_LEN __LOCALE_DATA_WCctype_TI_LEN +#define WCctype_UT_LEN __LOCALE_DATA_WCctype_UT_LEN +#define WCctype_II_SHIFT __LOCALE_DATA_WCctype_II_SHIFT +#define WCctype_TI_SHIFT __LOCALE_DATA_WCctype_TI_SHIFT + +#define WCuplow_II_LEN __LOCALE_DATA_WCuplow_II_LEN +#define WCuplow_TI_LEN __LOCALE_DATA_WCuplow_TI_LEN +#define WCuplow_UT_LEN __LOCALE_DATA_WCuplow_UT_LEN +#define WCuplow_II_SHIFT __LOCALE_DATA_WCuplow_II_SHIFT +#define WCuplow_TI_SHIFT __LOCALE_DATA_WCuplow_TI_SHIFT + + +#define WCctype_TI_MASK ((1 << (WCctype_TI_SHIFT)) - 1) +#define WCctype_II_MASK ((1 << (WCctype_II_SHIFT)) - 1) /**********************************************************************/ -/* TODO: fix this! */ -#ifdef __WCTYPE_WITH_LOCALE +#undef __PASTE2 +#undef __PASTE3 +#define __PASTE2(X,Y) X ## Y +#define __PASTE3(X,Y,Z) X ## Y ## Z -#define WCctype (__global_locale.tblwctype) -#define WCuplow (__global_locale.tblwuplow) -#define WCcmob (__global_locale.tblwcomb) -#define WCuplow_diff (__global_locale.tblwuplow_diff) +#ifdef __UCLIBC_DO_XLOCALE -#define ENCODING (__global_locale.encoding) +extern int __iswctype_l (wint_t __wc, wctype_t __desc, __locale_t __locale) + __THROW; #define ISW_FUNC_BODY(NAME) \ -int NAME (wint_t wc) \ +int __PASTE3(__isw,NAME,_l) (wint_t wc, __locale_t l) \ { \ - return iswctype(wc, __PASTE(_CTYPE_,NAME)); \ -} + return __iswctype_l(wc, __PASTE2(_CTYPE_is,NAME), l); \ +} \ +weak_alias(__PASTE3(__isw,NAME,_l), __PASTE3(isw,NAME,_l)) + +#else /* __UCLIBC_DO_XLOCALE */ -#else /* __WCTYPE_WITH_LOCALE */ +extern int __iswctype (wint_t __wc, wctype_t __desc) __THROW; #define ISW_FUNC_BODY(NAME) \ -int NAME (wint_t wc) \ +int __PASTE2(isw,NAME) (wint_t wc) \ { \ - return C_MACRO(NAME); \ + return __iswctype(wc, __PASTE2(_CTYPE_is,NAME)); \ } -#endif /* __WCTYPE_WITH_LOCALE */ - +#endif /* __UCLIBC_DO_XLOCALE */ /**********************************************************************/ -#ifdef L_iswalnum +#if defined(L_iswalnum) || defined(L_iswalnum_l) -ISW_FUNC_BODY(iswalnum); +ISW_FUNC_BODY(alnum); #endif /**********************************************************************/ -#ifdef L_iswalpha +#if defined(L_iswalpha) || defined(L_iswalpha_l) -ISW_FUNC_BODY(iswalpha); +ISW_FUNC_BODY(alpha); #endif /**********************************************************************/ -#ifdef L_iswblank +#if defined(L_iswblank) || defined(L_iswblank_l) -ISW_FUNC_BODY(iswblank); +ISW_FUNC_BODY(blank); #endif /**********************************************************************/ -#ifdef L_iswcntrl +#if defined(L_iswcntrl) || defined(L_iswcntrl_l) -ISW_FUNC_BODY(iswcntrl); +ISW_FUNC_BODY(cntrl); #endif /**********************************************************************/ -#ifdef L_iswdigit +#if defined(L_iswdigit) || defined(L_iswdigit_l) -int iswdigit(wint_t wc) -{ - return __C_iswdigit(wc); -} +ISW_FUNC_BODY(digit); #endif /**********************************************************************/ -#ifdef L_iswgraph +#if defined(L_iswgraph) || defined(L_iswgraph_l) -ISW_FUNC_BODY(iswgraph); +ISW_FUNC_BODY(graph); #endif /**********************************************************************/ -#ifdef L_iswlower +#if defined(L_iswlower) || defined(L_iswlower_l) -ISW_FUNC_BODY(iswlower); +ISW_FUNC_BODY(lower); #endif /**********************************************************************/ -#ifdef L_iswprint +#if defined(L_iswprint) || defined(L_iswprint_l) -ISW_FUNC_BODY(iswprint); +ISW_FUNC_BODY(print); #endif /**********************************************************************/ -#ifdef L_iswpunct +#if defined(L_iswpunct) || defined(L_iswpunct_l) -ISW_FUNC_BODY(iswpunct); +ISW_FUNC_BODY(punct); #endif /**********************************************************************/ -#ifdef L_iswspace +#if defined(L_iswspace) || defined(L_iswspace_l) -ISW_FUNC_BODY(iswspace); +ISW_FUNC_BODY(space); #endif /**********************************************************************/ -#ifdef L_iswupper +#if defined(L_iswupper) || defined(L_iswupper_l) -ISW_FUNC_BODY(iswupper); +ISW_FUNC_BODY(upper); #endif /**********************************************************************/ -#ifdef L_iswxdigit +#if defined(L_iswxdigit) || defined(L_iswxdigit_l) -int iswxdigit(wint_t wc) -{ - return __C_iswxdigit(wc); -} +ISW_FUNC_BODY(xdigit); #endif /**********************************************************************/ +#if defined(L_towlower) || defined(L_towlower_l) + #ifdef L_towlower +#define TOWLOWER(w) towlower(w) +#else /* L_towlower */ +#define TOWLOWER(w) __towlower_l(w, __locale_t locale) +#undef __UCLIBC_CURLOCALE_DATA +#undef __UCLIBC_CURLOCALE +#define __UCLIBC_CURLOCALE_DATA (*locale) +#define __UCLIBC_CURLOCALE (locale) +#endif /* L_towlower */ + +#ifdef __UCLIBC_HAS_XLOCALE__ +#define TOWCTRANS(w,d) __towctrans_l(w,d, __UCLIBC_CURLOCALE) +#else /* __UCLIBC_HAS_XLOCALE__ */ +#define TOWCTRANS(w,d) towctrans(w,d) +#endif /* __UCLIBC_HAS_XLOCALE__ */ + +#define __C_towlower(wc) \ + ((((__uwchar_t)(wc)) <= 0x7f) ? (__C_ctype_tolower)[(wc)] : (wc)) + +#ifdef __LOCALE_C_ONLY -#ifdef __WCTYPE_WITH_LOCALE +wint_t towlower(wint_t wc) +{ + return __C_towlower(wc); +} + +#else /* __LOCALE_C_ONLY */ #ifdef SMALL_UPLOW +#if defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) + wint_t towlower(wint_t wc) { - return towctrans(wc, _CTYPE_tolower); + return __towctrans_l(wc, _CTYPE_tolower, __UCLIBC_CURLOCALE); } -#else +#else /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */ + +wint_t TOWLOWER(wint_t wc) +{ + return TOWCTRANS(wc, _CTYPE_tolower); +} + +#endif /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */ + +#else /* SMALL_UPLOW */ + +#if defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) wint_t towlower(wint_t wc) +{ + return __towlower_l(wc, __UCLIBC_CURLOCALE); +} + +#else /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */ + +wint_t TOWLOWER(wint_t wc) { unsigned int sc, n, i; __uwchar_t u = wc; @@ -202,33 +362,78 @@ wint_t towlower(wint_t wc) return wc; } -#endif +#endif /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */ -#else /* __WCTYPE_WITH_LOCALE */ +#endif /* SMALL_UPLOW */ -wint_t towlower(wint_t wc) -{ - return __C_towlower(wc); -} +#ifdef L_towlower_l +weak_alias(__towlower_l, towlower_l) +#endif /* L_towlower_l */ -#endif /* __WCTYPE_WITH_LOCALE */ +#endif /* __LOCALE_C_ONLY */ #endif /**********************************************************************/ +#if defined(L_towupper) || defined(L_towupper_l) + #ifdef L_towupper +#define TOWUPPER(w) towupper(w) +#else /* L_towupper */ +#define TOWUPPER(w) __towupper_l(w, __locale_t locale) +#undef __UCLIBC_CURLOCALE_DATA +#undef __UCLIBC_CURLOCALE +#define __UCLIBC_CURLOCALE_DATA (*locale) +#define __UCLIBC_CURLOCALE (locale) +#endif /* L_towupper */ + +#ifdef __UCLIBC_HAS_XLOCALE__ +#define TOWCTRANS(w,d) __towctrans_l(w,d, __UCLIBC_CURLOCALE) +#else /* __UCLIBC_HAS_XLOCALE__ */ +#define TOWCTRANS(w,d) towctrans(w,d) +#endif /* __UCLIBC_HAS_XLOCALE__ */ + +#define __C_towupper(wc) \ + ((((__uwchar_t)(wc)) <= 0x7f) ? (__C_ctype_toupper)[(wc)] : (wc)) + +#ifdef __LOCALE_C_ONLY -#ifdef __WCTYPE_WITH_LOCALE +wint_t towupper(wint_t wc) +{ + return __C_towupper(wc); +} + +#else /* __LOCALE_C_ONLY */ #ifdef SMALL_UPLOW +#if defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) + wint_t towupper(wint_t wc) { - return towctrans(wc, _CTYPE_toupper); + return __towctrans_l(wc, _CTYPE_toupper, __UCLIBC_CURLOCALE); } -#else +#else /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */ + +wint_t TOWUPPER(wint_t wc) +{ + return TOWCTRANS(wc, _CTYPE_toupper); +} + +#endif /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */ + +#else /* SMALL_UPLOW */ + +#if defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) wint_t towupper(wint_t wc) +{ + return __towupper_l(wc, __UCLIBC_CURLOCALE); +} + +#else /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */ + +wint_t TOWUPPER(wint_t wc) { unsigned int sc, n, i; __uwchar_t u = wc; @@ -254,16 +459,15 @@ wint_t towupper(wint_t wc) return wc; } -#endif +#endif /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */ -#else /* __WCTYPE_WITH_LOCALE */ +#endif /* SMALL_UPLOW */ -wint_t towupper(wint_t wc) -{ - return __C_towupper(wc); -} +#ifdef L_towupper_l +weak_alias(__towupper_l, towupper_l) +#endif /* L_towupper_l */ -#endif /* __WCTYPE_WITH_LOCALE */ +#endif /* __LOCALE_C_ONLY */ #endif /**********************************************************************/ @@ -293,33 +497,102 @@ wctype_t wctype(const char *property) #endif /**********************************************************************/ -#ifdef L_iswctype +#ifdef L_wctype_l #ifdef __UCLIBC_MJN3_ONLY__ -#warning duh... replace the range-based classification with table lookup! -#endif +#warning REMINDER: Currently wctype_l simply calls wctype. +#endif /* __UCLIBC_MJN3_ONLY__ */ -#ifdef __WCTYPE_WITH_LOCALE +wctype_t __wctype_l (const char *property, __locale_t locale) +{ + return wctype(property); +} + +weak_alias(__wctype_l, wctype_l) + +#endif +/**********************************************************************/ +#if defined(L_iswctype) || defined(L_iswctype_l) + +#define __C_iswdigit(c) \ + ((sizeof(c) == sizeof(char)) \ + ? (((unsigned char)((c) - '0')) < 10) \ + : (((__uwchar_t)((c) - '0')) < 10)) +#define __C_iswxdigit(c) \ + (__C_iswdigit(c) \ + || ((sizeof(c) == sizeof(char)) \ + ? (((unsigned char)((((c)) | 0x20) - 'a')) < 6) \ + : (((__uwchar_t)((((c)) | 0x20) - 'a')) < 6))) #ifdef __UCLIBC_MJN3_ONLY__ -#warning TODO: need to fix locale ctype table lookup stuff +#ifdef L_iswctype +#warning CONSIDER: Change to bit shift? would need to sync with wctype.h #endif -#if 0 -extern const char ctype_range[]; -#else -static const char ctype_range[] = { - __CTYPE_RANGES +#endif /* __UCLIBC_MJN3_ONLY__ */ + + +#if !defined(__UCLIBC_HAS_XLOCALE__) || defined(L_iswctype_l) + +static const unsigned short int desc2flag[] = { + [_CTYPE_unclassified] = 0, + [_CTYPE_isalnum] = (unsigned short int) _ISwalnum, + [_CTYPE_isalpha] = (unsigned short int) _ISwalpha, + [_CTYPE_isblank] = (unsigned short int) _ISwblank, + [_CTYPE_iscntrl] = (unsigned short int) _ISwcntrl, + [_CTYPE_isdigit] = (unsigned short int) _ISwdigit, + [_CTYPE_isgraph] = (unsigned short int) _ISwgraph, + [_CTYPE_islower] = (unsigned short int) _ISwlower, + [_CTYPE_isprint] = (unsigned short int) _ISwprint, + [_CTYPE_ispunct] = (unsigned short int) _ISwpunct, + [_CTYPE_isspace] = (unsigned short int) _ISwspace, + [_CTYPE_isupper] = (unsigned short int) _ISwupper, + [_CTYPE_isxdigit] = (unsigned short int) _ISwxdigit, }; -#endif + +#endif /* defined(L_iswctype_L) || defined(__LOCALE_C_ONLY) */ + +#ifdef __LOCALE_C_ONLY + +int __iswctype(wint_t wc, wctype_t desc) +{ + /* Note... wctype_t is unsigned. */ + + if ((((__uwchar_t) wc) <= 0x7f) + && (desc < (sizeof(desc2flag)/sizeof(desc2flag[0]))) + ) { + return __isctype(wc, desc2flag[desc]); + } + return 0; +} + +#else /* __LOCALE_C_ONLY */ #ifdef __UCLIBC_MJN3_ONLY__ -#warning TODO: need to handle combining class! +#ifdef L_iswctype +#warning CONSIDER: Handle combining class? #endif +#endif /* __UCLIBC_MJN3_ONLY__ */ -#define WCctype_TI_MASK ((1 << WCctype_TI_SHIFT) - 1) -#define WCctype_II_MASK ((1 << WCctype_II_SHIFT) - 1) +#ifdef L_iswctype +#define ISWCTYPE(w,d) __iswctype(w,d) +#else /* L_iswctype */ +#define ISWCTYPE(w,d) __iswctype_l(w,d, __locale_t locale) +#undef __UCLIBC_CURLOCALE_DATA +#undef __UCLIBC_CURLOCALE +#define __UCLIBC_CURLOCALE_DATA (*locale) +#define __UCLIBC_CURLOCALE (locale) +#endif /* L_iswctype */ + +#if defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__) + +int __iswctype(wint_t wc, wctype_t desc) +{ + return __iswctype_l(wc, desc, __UCLIBC_CURLOCALE); +} -int iswctype(wint_t wc, wctype_t desc) +#else /* defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__) */ + +int ISWCTYPE(wint_t wc, wctype_t desc) { unsigned int sc, n, i0, i1; unsigned char d = __CTYPE_unclassified; @@ -348,122 +621,100 @@ int iswctype(wint_t wc, wctype_t desc) d = __CTYPE_punct; } +#if 0 return ( ((unsigned char)(d - ctype_range[2*desc])) <= ctype_range[2*desc + 1] ) && ((desc != _CTYPE_iswblank) || (d & 1)); +#else + return (__UCLIBC_CURLOCALE_DATA).code2flag[d] & desc2flag[desc]; +#endif } +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: xdigit really needs to be handled better. Remember only for ascii! +#endif /* __UCLIBC_MJN3_ONLY__ */ /* TODO - Add locale-specific classifications. */ return (desc == _CTYPE_iswxdigit) ? __C_iswxdigit(wc) : 0; } return 0; } -#else +#endif /* defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__) */ -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), -}; +#ifdef L_iswctype_l +weak_alias(__iswctype_l, iswctype_l) +#endif /* L_iswctype_l */ -static const char ctype_range[] = { - __CTYPE_RANGES -}; +#endif /* __LOCALE_C_ONLY */ -int iswctype(wint_t wc, wctype_t desc) -{ - unsigned char d = __CTYPE_unclassified; +#ifdef L_iswctype +weak_alias(__iswctype, iswctype) +#endif /* L_iswctype */ - if (((__uwchar_t) wc) <= 0x7f) { - if (desc < _CTYPE_iswxdigit) { - d = WCctype[wc >> 1]; - d = (wc & 1) ? (d >> 4) : (d & 0xf); +#endif +/**********************************************************************/ +#if defined(L_towctrans) || defined(L_towctrans_l) - return ( ((unsigned char)(d - ctype_range[2*desc])) - <= ctype_range[2*desc + 1] ) - && ((desc != _CTYPE_iswblank) || (d & 1)); - } +#ifdef __LOCALE_C_ONLY + +/* Minimal support for C/POSIX locale. */ + +#ifndef _tolower +#warning _tolower is undefined! +#define _tolower(c) tolower(c) +#endif +#ifndef _toupper +#warning _toupper is undefined! +#define _toupper(c) toupper(c) +#endif - if (desc == _CTYPE_iswxdigit) { - return __C_isxdigit(((char) wc)); +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 0; + return wc; } -#endif +#else /* __LOCALE_C_ONLY */ -#endif -/**********************************************************************/ #ifdef L_towctrans +#define TOWCTRANS(w,d) towctrans(w,d) +#else /* L_towctrans */ +#define TOWCTRANS(w,d) __towctrans_l(w,d, __locale_t locale) +#undef __UCLIBC_CURLOCALE_DATA +#undef __UCLIBC_CURLOCALE +#define __UCLIBC_CURLOCALE_DATA (*locale) +#define __UCLIBC_CURLOCALE (locale) +#endif /* L_towctrans */ + +#ifdef __UCLIBC_HAS_XLOCALE__ +#define TOWLOWER(w,l) __towlower_l(w,l) +#define TOWUPPER(w,l) __towupper_l(w,l) +#else /* __UCLIBC_HAS_XLOCALE__ */ +#define TOWLOWER(w,l) towlower(w) +#define TOWUPPER(w,l) towupper(w) +#endif /* __UCLIBC_HAS_XLOCALE__ */ + +#if defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__) -#ifdef __WCTYPE_WITH_LOCALE +wint_t towctrans(wint_t wc, wctrans_t desc) +{ + return __towctrans_l(wc, desc, __UCLIBC_CURLOCALE); +} + +#else /* defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__) */ #ifdef SMALL_UPLOW -wint_t towctrans(wint_t wc, wctrans_t desc) +wint_t TOWCTRANS(wint_t wc, wctrans_t desc) { unsigned int sc, n, i; __uwchar_t u = wc; @@ -499,6 +750,9 @@ wint_t towctrans(wint_t wc, wctrans_t desc) } wc += WCuplow_diff[i]; if (desc == _CTYPE_totitle) { +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: Verify totitle special cases! +#endif /* __UCLIBC_MJN3_ONLY__ */ /* WARNING! These special cases work for glibc 2.2.4. Changes * may be needed if the glibc locale tables are updated. */ if ( (((__uwchar_t)(wc - 0x1c4)) <= (0x1cc - 0x1c4)) @@ -516,9 +770,9 @@ wint_t towctrans(wint_t wc, wctrans_t desc) return wc; } -#else +#else /* SMALL_UPLOW */ -wint_t towctrans(wint_t wc, wctrans_t desc) +wint_t TOWCTRANS(wint_t wc, wctrans_t desc) { if (ENCODING == __ctype_encoding_7_bit) { if ((((__uwchar_t) wc) > 0x7f) @@ -532,12 +786,15 @@ wint_t towctrans(wint_t wc, wctrans_t desc) } if (desc == _CTYPE_tolower) { - return towlower(wc); + return TOWLOWER(wc, __UCLIBC_CURLOCALE); } else if (((unsigned int)(desc - _CTYPE_toupper)) <= (_CTYPE_totitle - _CTYPE_toupper) ) { - wc = towupper(wc); + wc = TOWUPPER(wc, __UCLIBC_CURLOCALE); if (desc == _CTYPE_totitle) { +#ifdef __UCLIBC_MJN3_ONLY__ +#warning TODO: Verify totitle special cases! +#endif /* __UCLIBC_MJN3_ONLY__ */ /* WARNING! These special cases work for glibc 2.2.4. Changes * may be needed if the glibc locale tables are updated. */ if ( (((__uwchar_t)(wc - 0x1c4)) <= (0x1cc - 0x1c4)) @@ -553,28 +810,15 @@ wint_t towctrans(wint_t wc, wctrans_t desc) return wc; } -#endif +#endif /* SMALL_UPLOW */ -#else /* __WCTYPE_WITH_LOCALE */ +#endif /* defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__) */ -/* Minimal support for C/POSIX locale. */ +#ifdef L_towctrans_l +weak_alias(__towctrans_l, towctrans_l) +#endif /* L_towctrans_l */ -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 /* __LOCALE_C_ONLY */ #endif /**********************************************************************/ @@ -603,3 +847,18 @@ wctrans_t wctrans(const char *property) #endif /**********************************************************************/ +#ifdef L_wctrans_l + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: Currently wctrans_l simply calls wctrans. +#endif /* __UCLIBC_MJN3_ONLY__ */ + +wctrans_t __wctrans_l(const char *property, __locale_t locale) +{ + return wctrans(property); +} + +weak_alias(__wctrans_l, wctrans_l) + +#endif +/**********************************************************************/ -- cgit v1.2.3