diff options
Diffstat (limited to 'libc')
-rw-r--r-- | libc/misc/Makefile | 3 | ||||
-rw-r--r-- | libc/misc/ctype/Makefile | 5 | ||||
-rw-r--r-- | libc/misc/ctype/ctype.c | 486 | ||||
-rw-r--r-- | libc/misc/ctype/ctype_C.c | 517 | ||||
-rw-r--r-- | libc/misc/internals/__uClibc_main.c | 12 | ||||
-rw-r--r-- | libc/misc/locale/Makefile | 15 | ||||
-rw-r--r-- | libc/misc/locale/_locale.h | 22 | ||||
-rw-r--r-- | libc/misc/locale/locale.c | 719 | ||||
-rw-r--r-- | libc/misc/locale/localeconv.c | 52 | ||||
-rw-r--r-- | libc/misc/wctype/Makefile | 47 | ||||
-rw-r--r-- | libc/misc/wctype/wctype.c | 480 | ||||
-rw-r--r-- | libc/stdlib/Makefile | 5 | ||||
-rw-r--r-- | libc/stdlib/stdlib.c | 181 | ||||
-rw-r--r-- | libc/string/Makefile | 55 | ||||
-rw-r--r-- | libc/string/wstring.c | 1273 | ||||
-rw-r--r-- | libc/sysdeps/linux/common/bits/.cvsignore | 1 | ||||
-rw-r--r-- | libc/sysdeps/linux/common/bits/uClibc_ctype.h | 250 | ||||
-rw-r--r-- | libc/sysdeps/linux/common/bits/uClibc_locale.h | 261 |
18 files changed, 3236 insertions, 1148 deletions
diff --git a/libc/misc/Makefile b/libc/misc/Makefile index 9040e7e0b..8dcf5486a 100644 --- a/libc/misc/Makefile +++ b/libc/misc/Makefile @@ -34,6 +34,9 @@ endif ifeq ($(strip $(INCLUDE_THREADS)),true) DIRS += pthread endif +ifeq ($(strip $(HAS_WCHAR)),true) +DIRS += wctype # wchar +endif all: libc.a diff --git a/libc/misc/ctype/Makefile b/libc/misc/ctype/Makefile index fb099012a..1d7c24535 100644 --- a/libc/misc/ctype/Makefile +++ b/libc/misc/ctype/Makefile @@ -28,10 +28,7 @@ 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 \ - -ifeq ($(HAS_LOCALE),true) - MOBJ += ctype_C.o -endif + __isctype_loc.o CSRC=junk.c COBJS=$(patsubst %.c,%.o, $(CSRC)) diff --git a/libc/misc/ctype/ctype.c b/libc/misc/ctype/ctype.c index a3d3d4354..dedd5c00a 100644 --- a/libc/misc/ctype/ctype.c +++ b/libc/misc/ctype/ctype.c @@ -1,341 +1,329 @@ -/* ctype.c - * Character classification and conversion - * Copyright (C) 2000 Lineo, Inc. - * Written by Erik Andersen - * This file is part of the uClibc C library and is distributed - * under the GNU Library General Public License. +/* Copyright (C) 2002 Manuel Novoa III * - * not C-locale only code - * written by Vladimir Oleynik (c) vodz@usa.net - * and Manuel Novoa III <mnovoa3@bellsouth.net> - * used ideas is part of the GNU C Library. + * 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. */ -#define __USE_CTYPE_MACROS +/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! + * + * Besides uClibc, I'm using this code in my libc for elks, which is + * a 16-bit environment with a fairly limited compiler. It would make + * things much easier for me if this file isn't modified unnecessarily. + * In particular, please put any new or replacement functions somewhere + * else, and modify the makefile to use your version instead. + * Thanks. Manuel + * + * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */ + +#define _GNU_SOURCE +#define __NO_CTYPE + #include <ctype.h> +#include <stdio.h> +#include <limits.h> +#include <assert.h> +#include <locale.h> -#ifdef L_isascii -#undef isascii -int -isascii( int c ) -{ - return (c > 0 && c <= 0x7f); -} -#endif +/**********************************************************************/ -#ifdef L_isdigit -#undef isdigit -int -isdigit( int c ) -{ - return (c >= '0' && c <= '9'); -} -#endif +extern int __isctype_loc(int c, int ct); -#ifdef L_toascii -#undef toascii -int -toascii( int c ) -{ - return (c & 0x7f); -} -#endif +/* Some macros used throughout the file. */ +#define U ((unsigned char)c) +/* #define LCT (__cur_locale->ctype) */ +#define LCT (&__global_locale) -#ifdef L_isblank -#undef isblank -int -isblank( int c ) -{ - return ((c == ' ') || (c == '\t')); -} +/**********************************************************************/ + +#ifndef __PASTE +#define __PASTE(X,Y) X ## Y #endif -/* locale depended */ -#ifndef __UCLIBC_HAS_LOCALE__ +#define C_MACRO(X) __PASTE(__C_,X)(c) -#ifdef L_isalpha -#undef isalpha -int -isalpha( int c ) -{ - return (isupper(c) || islower(c)); -} -#endif +#define CT_MACRO(X) __PASTE(__ctype_,X)(c) -#ifdef L_isalnum -#undef isalnum -int -isalnum( int c ) -{ - return (isalpha(c) || isdigit(c)); -} -#endif +/**********************************************************************/ -#ifdef L_iscntrl -#undef iscntrl -int -iscntrl( int c ) -{ - return ((c >= 0) && ((c <= 0x1f) || (c == 0x7f))); -} -#endif +#ifndef __CTYPE_HAS_8_BIT_LOCALES -#ifdef L_isgraph -#undef isgraph -int -isgraph( int c ) -{ - return (c > ' ' && isprint(c)); +#define IS_FUNC_BODY(NAME) \ +int NAME (int c) \ +{ \ + return C_MACRO(NAME); \ } -#endif -#ifdef L_islower -#undef islower -int -islower( int c ) -{ - return (c >= 'a' && c <= 'z'); -} -#endif +#else -#ifdef L_isprint -#undef isprint -int -isprint( int c ) -{ - return (c >= ' ' && c <= '~'); -} -#endif +/* 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)); \ */ +/* } */ -#ifdef L_ispunct -#undef ispunct -int -ispunct( int c ) -{ - return ((c > ' ' && c <= '~') && !isalnum(c)); +#define IS_FUNC_BODY(NAME) \ +int NAME (int c) \ +{ \ + if (((unsigned int) c) <= 0x7f) { \ + return C_MACRO(NAME); \ + } \ + return __isctype_loc(c, __PASTE(_CTYPE_,NAME)); \ } -#endif -#ifdef L_isspace -#undef isspace -int -isspace( int c ) -{ - return (c == ' ' || c == '\f' || c == '\n' || c == '\r' || - c == '\t' || c == '\v'); -} -#endif +#endif /* __CTYPE_HAS_8_BIT_LOCALES */ -#ifdef L_isupper -#undef isupper -int -isupper( int c ) -{ - return (c >= 'A' && c <= 'Z'); -} -#endif +/**********************************************************************/ +#ifdef L_isalnum + +IS_FUNC_BODY(isalnum); -#ifdef L_isxdigit -#undef isxdigit -int -isxdigit( int c ) -{ - return (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); -} #endif +/**********************************************************************/ +#ifdef L_isalpha + +IS_FUNC_BODY(isalpha); -#ifdef L_isxlower -#undef isxlower -int -isxlower( int c ) -{ - return (isdigit(c) || (c >= 'a' && c <= 'f')); -} #endif +/**********************************************************************/ +#ifdef L_isblank -#ifdef L_isxupper -#undef isxupper -int -isxupper( int c ) +/* Warning!!! This is correct for all the currently supported 8-bit locales. + * If any are added though, this will need to be verified. */ + +int isblank(int c) { - return (isdigit(c) || (c >= 'A' && c <= 'F')); + return __isblank(c); } + #endif +/**********************************************************************/ +#ifdef L_iscntrl + +IS_FUNC_BODY(iscntrl); -#ifdef L_tolower -#undef tolower -int -tolower( int c ) -{ - return (isupper(c) ? (c - 'A' + 'a') : (c)); -} #endif +/**********************************************************************/ +#ifdef L_isdigit -#ifdef L_toupper -#undef toupper -int -toupper( int c ) +int isdigit(int c) { - return (islower(c) ? (c - 'a' + 'A') : (c)); + return __isdigit(c); } + #endif +/**********************************************************************/ +#ifdef L_isgraph -#else /* __UCLIBC_HAS_LOCALE__ */ +IS_FUNC_BODY(isgraph); -#include <limits.h> -#include "../locale/_locale.h" +#endif +/**********************************************************************/ +#ifdef L_islower -#define _UC_ISCTYPE(c, type) \ -((c != -1) && ((_uc_ctype_b[(int)((unsigned char)c)] & type) != 0)) +IS_FUNC_BODY(islower); -#define _UC_ISCTYPE2(c, type, type2) \ -((c != -1) && ((_uc_ctype_b[(int)((unsigned char)c)] & type) == type2)) +#endif +/**********************************************************************/ +#ifdef L_isprint +IS_FUNC_BODY(isprint); -#ifdef L_ctype_C +#endif +/**********************************************************************/ +#ifdef L_ispunct -/* startup setlocale(LC_TYPE, "C"); */ -#include "ctype_C.c" +IS_FUNC_BODY(ispunct); -const unsigned char *_uc_ctype_b = _uc_ctype_b_C; -const unsigned char *_uc_ctype_trans = _uc_ctype_b_C+LOCALE_BUF_SIZE/2; +#endif +/**********************************************************************/ +#ifdef L_isspace -#endif /* L_ctype_C */ +/* Warning!!! This is correct for all the currently supported 8-bit locales. + * If any are added though, this will need to be verified. */ -#ifdef L_isalpha -#undef isalpha -int -isalpha( int c ) +int isspace(int c) { - return _UC_ISCTYPE(c, ISalpha); + return __isspace(c); } -#endif -#ifdef L_isalnum -#undef isalnum -int -isalnum( int c ) -{ - return _UC_ISCTYPE(c, (ISalpha|ISxdigit)); -} #endif +/**********************************************************************/ +#ifdef L_isupper + +IS_FUNC_BODY(isupper); -#ifdef L_iscntrl -#undef iscntrl -int -iscntrl( int c ) -{ - return _UC_ISCTYPE(c, IScntrl); -} #endif +/**********************************************************************/ +#ifdef L_isxdigit -#ifdef L_isgraph -#undef isgraph -int -isgraph( int c ) +int isxdigit(int c) { - return _UC_ISCTYPE2(c, (ISprint|ISspace), ISprint); + return __isxdigit(c); } + #endif +/**********************************************************************/ +#ifdef L_tolower -#ifdef L_islower -#undef islower -int -islower( int c ) +#ifdef __CTYPE_HAS_8_BIT_LOCALES + +int tolower(int c) { - return _UC_ISCTYPE(c, ISlower); + 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 ); } -#endif -#ifdef L_isprint -#undef isprint -int -isprint( int c ) +#else /* __CTYPE_HAS_8_BIT_LOCALES */ + +int tolower(int c) { - return _UC_ISCTYPE(c, ISprint); + return __C_tolower(c); } + +#endif /* __CTYPE_HAS_8_BIT_LOCALES */ + #endif +/**********************************************************************/ +#ifdef L_toupper -#ifdef L_ispunct -#undef ispunct -int -ispunct( int c ) +#ifdef __CTYPE_HAS_8_BIT_LOCALES + +int toupper(int c) { - return _UC_ISCTYPE(c, ISpunct); + 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 ); } -#endif -#ifdef L_isspace -#undef isspace -int -isspace( int c ) +#else /* __CTYPE_HAS_8_BIT_LOCALES */ + +int toupper(int c) { - return _UC_ISCTYPE(c, ISspace); + return __C_toupper(c); } + +#endif /* __CTYPE_HAS_8_BIT_LOCALES */ + #endif +/**********************************************************************/ +#ifdef L_isascii -#ifdef L_isupper -#undef isupper -int -isupper( int c ) +int isascii(int c) { - return _UC_ISCTYPE(c, ISupper); + return __isascii(c); } + #endif +/**********************************************************************/ +#ifdef L_toascii -#ifdef L_isxdigit -#undef isxdigit -int -isxdigit( int c ) +int toascii(int c) { - return _UC_ISCTYPE(c, ISxdigit); + return __toascii(c); } -#endif +#endif +/**********************************************************************/ #ifdef L_isxlower -#undef isxlower -int -isxlower( int c ) + +int isxlower(int c) { - return _UC_ISCTYPE2(c, (ISxdigit|ISupper), ISxdigit); + return __isxlower(c); } -#endif +#endif +/**********************************************************************/ #ifdef L_isxupper -#undef isxupper -int -isxupper( int c ) + +int isxupper(int c) { - return _UC_ISCTYPE2(c, (ISxdigit|ISlower), ISxdigit); + return __isxupper(c); } + #endif +/**********************************************************************/ +#ifdef L___isctype_loc +#ifdef __CTYPE_HAS_8_BIT_LOCALES -#ifdef L_tolower -#undef tolower -int -tolower( int c ) +/* 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). */ + +static const char ctype_range[] = { + __CTYPE_RANGES +}; + +int __isctype_loc(int c, int ct) { - if((c < CHAR_MIN) || (c > UCHAR_MAX)) - return c; - if(isupper(c)) - return _uc_ctype_trans[(int)((unsigned char)c)]; - else - return c; -} + unsigned char d; + + assert(((unsigned int)ct) < _CTYPE_isxdigit); + assert(((unsigned int)c) > 0x7f); + +#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; + } #endif -#ifdef L_toupper -#undef toupper -int -toupper( int c ) -{ - if((c < CHAR_MIN) || (c > UCHAR_MAX)) - return c; - if(islower(c)) - return _uc_ctype_trans[(int)((unsigned char)c)]; - else - return c; -} + /* TODO - test assumptions??? 8-bit chars -- or ensure in generator. */ + +#define Cctype_TBL_MASK ((1 << Cctype_IDX_SHIFT) - 1) +#define Cctype_IDX_OFFSET (128 >> Cctype_IDX_SHIFT) + + 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/ctype/ctype_C.c b/libc/misc/ctype/ctype_C.c deleted file mode 100644 index 2aa2690b6..000000000 --- a/libc/misc/ctype/ctype_C.c +++ /dev/null @@ -1,517 +0,0 @@ -const unsigned char _uc_ctype_b_C[LOCALE_BUF_SIZE] = { - /* 0x00, 0, 00 */ IScntrl, - /* 0x01, 1, 01 */ IScntrl, - /* 0x02, 2, 02 */ IScntrl, - /* 0x03, 3, 03 */ IScntrl, - /* 0x04, 4, 04 */ IScntrl, - /* 0x05, 5, 05 */ IScntrl, - /* 0x06, 6, 06 */ IScntrl, - /* 0x07, 7, 07 */ IScntrl, - /* 0x08, 8, 010 */ IScntrl, - /* 0x09, 9, 011 */ IScntrl|ISspace, - /* 0x0a, 10, 012 */ IScntrl|ISspace, - /* 0x0b, 11, 013 */ IScntrl|ISspace, - /* 0x0c, 12, 014 */ IScntrl|ISspace, - /* 0x0d, 13, 015 */ IScntrl|ISspace, - /* 0x0e, 14, 016 */ IScntrl, - /* 0x0f, 15, 017 */ IScntrl, - /* 0x10, 16, 020 */ IScntrl, - /* 0x11, 17, 021 */ IScntrl, - /* 0x12, 18, 022 */ IScntrl, - /* 0x13, 19, 023 */ IScntrl, - /* 0x14, 20, 024 */ IScntrl, - /* 0x15, 21, 025 */ IScntrl, - /* 0x16, 22, 026 */ IScntrl, - /* 0x17, 23, 027 */ IScntrl, - /* 0x18, 24, 030 */ IScntrl, - /* 0x19, 25, 031 */ IScntrl, - /* 0x1a, 26, 032 */ IScntrl, - /* 0x1b, 27, 033 */ IScntrl, - /* 0x1c, 28, 034 */ IScntrl, - /* 0x1d, 29, 035 */ IScntrl, - /* 0x1e, 30, 036 */ IScntrl, - /* 0x1f, 31, 037 */ IScntrl, - /* 0x20, 32, 040 */ ISprint|ISspace, - /* 0x21, 33, 041 */ ISprint|ISpunct, - /* 0x22, 34, 042 */ ISprint|ISpunct, - /* 0x23, 35, 043 */ ISprint|ISpunct, - /* 0x24, 36, 044 */ ISprint|ISpunct, - /* 0x25, 37, 045 */ ISprint|ISpunct, - /* 0x26, 38, 046 */ ISprint|ISpunct, - /* 0x27, 39, 047 */ ISprint|ISpunct, - /* 0x28, 40, 050 */ ISprint|ISpunct, - /* 0x29, 41, 051 */ ISprint|ISpunct, - /* 0x2a, 42, 052 */ ISprint|ISpunct, - /* 0x2b, 43, 053 */ ISprint|ISpunct, - /* 0x2c, 44, 054 */ ISprint|ISpunct, - /* 0x2d, 45, 055 */ ISprint|ISpunct, - /* 0x2e, 46, 056 */ ISprint|ISpunct, - /* 0x2f, 47, 057 */ ISprint|ISpunct, - /* 0x30, 48, 060 */ ISprint|ISxdigit, - /* 0x31, 49, 061 */ ISprint|ISxdigit, - /* 0x32, 50, 062 */ ISprint|ISxdigit, - /* 0x33, 51, 063 */ ISprint|ISxdigit, - /* 0x34, 52, 064 */ ISprint|ISxdigit, - /* 0x35, 53, 065 */ ISprint|ISxdigit, - /* 0x36, 54, 066 */ ISprint|ISxdigit, - /* 0x37, 55, 067 */ ISprint|ISxdigit, - /* 0x38, 56, 070 */ ISprint|ISxdigit, - /* 0x39, 57, 071 */ ISprint|ISxdigit, - /* 0x3a, 58, 072 */ ISprint|ISpunct, - /* 0x3b, 59, 073 */ ISprint|ISpunct, - /* 0x3c, 60, 074 */ ISprint|ISpunct, - /* 0x3d, 61, 075 */ ISprint|ISpunct, - /* 0x3e, 62, 076 */ ISprint|ISpunct, - /* 0x3f, 63, 077 */ ISprint|ISpunct, - /* 0x40, 64, 0100 */ ISprint|ISpunct, - /* 0x41, 65, 0101 */ ISprint|ISupper|ISalpha|ISxdigit, - /* 0x42, 66, 0102 */ ISprint|ISupper|ISalpha|ISxdigit, - /* 0x43, 67, 0103 */ ISprint|ISupper|ISalpha|ISxdigit, - /* 0x44, 68, 0104 */ ISprint|ISupper|ISalpha|ISxdigit, - /* 0x45, 69, 0105 */ ISprint|ISupper|ISalpha|ISxdigit, - /* 0x46, 70, 0106 */ ISprint|ISupper|ISalpha|ISxdigit, - /* 0x47, 71, 0107 */ ISprint|ISupper|ISalpha, - /* 0x48, 72, 0110 */ ISprint|ISupper|ISalpha, - /* 0x49, 73, 0111 */ ISprint|ISupper|ISalpha, - /* 0x4a, 74, 0112 */ ISprint|ISupper|ISalpha, - /* 0x4b, 75, 0113 */ ISprint|ISupper|ISalpha, - /* 0x4c, 76, 0114 */ ISprint|ISupper|ISalpha, - /* 0x4d, 77, 0115 */ ISprint|ISupper|ISalpha, - /* 0x4e, 78, 0116 */ ISprint|ISupper|ISalpha, - /* 0x4f, 79, 0117 */ ISprint|ISupper|ISalpha, - /* 0x50, 80, 0120 */ ISprint|ISupper|ISalpha, - /* 0x51, 81, 0121 */ ISprint|ISupper|ISalpha, - /* 0x52, 82, 0122 */ ISprint|ISupper|ISalpha, - /* 0x53, 83, 0123 */ ISprint|ISupper|ISalpha, - /* 0x54, 84, 0124 */ ISprint|ISupper|ISalpha, - /* 0x55, 85, 0125 */ ISprint|ISupper|ISalpha, - /* 0x56, 86, 0126 */ ISprint|ISupper|ISalpha, - /* 0x57, 87, 0127 */ ISprint|ISupper|ISalpha, - /* 0x58, 88, 0130 */ ISprint|ISupper|ISalpha, - /* 0x59, 89, 0131 */ ISprint|ISupper|ISalpha, - /* 0x5a, 90, 0132 */ ISprint|ISupper|ISalpha, - /* 0x5b, 91, 0133 */ ISprint|ISpunct, - /* 0x5c, 92, 0134 */ ISprint|ISpunct, - /* 0x5d, 93, 0135 */ ISprint|ISpunct, - /* 0x5e, 94, 0136 */ ISprint|ISpunct, - /* 0x5f, 95, 0137 */ ISprint|ISpunct, - /* 0x60, 96, 0140 */ ISprint|ISpunct, - /* 0x61, 97, 0141 */ ISprint|ISlower|ISalpha|ISxdigit, - /* 0x62, 98, 0142 */ ISprint|ISlower|ISalpha|ISxdigit, - /* 0x63, 99, 0143 */ ISprint|ISlower|ISalpha|ISxdigit, - /* 0x64, 100, 0144 */ ISprint|ISlower|ISalpha|ISxdigit, - /* 0x65, 101, 0145 */ ISprint|ISlower|ISalpha|ISxdigit, - /* 0x66, 102, 0146 */ ISprint|ISlower|ISalpha|ISxdigit, - /* 0x67, 103, 0147 */ ISprint|ISlower|ISalpha, - /* 0x68, 104, 0150 */ ISprint|ISlower|ISalpha, - /* 0x69, 105, 0151 */ ISprint|ISlower|ISalpha, - /* 0x6a, 106, 0152 */ ISprint|ISlower|ISalpha, - /* 0x6b, 107, 0153 */ ISprint|ISlower|ISalpha, - /* 0x6c, 108, 0154 */ ISprint|ISlower|ISalpha, - /* 0x6d, 109, 0155 */ ISprint|ISlower|ISalpha, - /* 0x6e, 110, 0156 */ ISprint|ISlower|ISalpha, - /* 0x6f, 111, 0157 */ ISprint|ISlower|ISalpha, - /* 0x70, 112, 0160 */ ISprint|ISlower|ISalpha, - /* 0x71, 113, 0161 */ ISprint|ISlower|ISalpha, - /* 0x72, 114, 0162 */ ISprint|ISlower|ISalpha, - /* 0x73, 115, 0163 */ ISprint|ISlower|ISalpha, - /* 0x74, 116, 0164 */ ISprint|ISlower|ISalpha, - /* 0x75, 117, 0165 */ ISprint|ISlower|ISalpha, - /* 0x76, 118, 0166 */ ISprint|ISlower|ISalpha, - /* 0x77, 119, 0167 */ ISprint|ISlower|ISalpha, - /* 0x78, 120, 0170 */ ISprint|ISlower|ISalpha, - /* 0x79, 121, 0171 */ ISprint|ISlower|ISalpha, - /* 0x7a, 122, 0172 */ ISprint|ISlower|ISalpha, - /* 0x7b, 123, 0173 */ ISprint|ISpunct, - /* 0x7c, 124, 0174 */ ISprint|ISpunct, - /* 0x7d, 125, 0175 */ ISprint|ISpunct, - /* 0x7e, 126, 0176 */ ISprint|ISpunct, - /* 0x7f, 127, 0177 */ IScntrl, - /* 0x80, 128, 0200 */ 0, - /* 0x81, 129, 0201 */ 0, - /* 0x82, 130, 0202 */ 0, - /* 0x83, 131, 0203 */ 0, - /* 0x84, 132, 0204 */ 0, - /* 0x85, 133, 0205 */ 0, - /* 0x86, 134, 0206 */ 0, - /* 0x87, 135, 0207 */ 0, - /* 0x88, 136, 0210 */ 0, - /* 0x89, 137, 0211 */ 0, - /* 0x8a, 138, 0212 */ 0, - /* 0x8b, 139, 0213 */ 0, - /* 0x8c, 140, 0214 */ 0, - /* 0x8d, 141, 0215 */ 0, - /* 0x8e, 142, 0216 */ 0, - /* 0x8f, 143, 0217 */ 0, - /* 0x90, 144, 0220 */ 0, - /* 0x91, 145, 0221 */ 0, - /* 0x92, 146, 0222 */ 0, - /* 0x93, 147, 0223 */ 0, - /* 0x94, 148, 0224 */ 0, - /* 0x95, 149, 0225 */ 0, - /* 0x96, 150, 0226 */ 0, - /* 0x97, 151, 0227 */ 0, - /* 0x98, 152, 0230 */ 0, - /* 0x99, 153, 0231 */ 0, - /* 0x9a, 154, 0232 */ 0, - /* 0x9b, 155, 0233 */ 0, - /* 0x9c, 156, 0234 */ 0, - /* 0x9d, 157, 0235 */ 0, - /* 0x9e, 158, 0236 */ 0, - /* 0x9f, 159, 0237 */ 0, - /* 0xa0, 160, 0240 */ 0, - /* 0xa1, 161, 0241 */ 0, - /* 0xa2, 162, 0242 */ 0, - /* 0xa3, 163, 0243 */ 0, - /* 0xa4, 164, 0244 */ 0, - /* 0xa5, 165, 0245 */ 0, - /* 0xa6, 166, 0246 */ 0, - /* 0xa7, 167, 0247 */ 0, - /* 0xa8, 168, 0250 */ 0, - /* 0xa9, 169, 0251 */ 0, - /* 0xaa, 170, 0252 */ 0, - /* 0xab, 171, 0253 */ 0, - /* 0xac, 172, 0254 */ 0, - /* 0xad, 173, 0255 */ 0, - /* 0xae, 174, 0256 */ 0, - /* 0xaf, 175, 0257 */ 0, - /* 0xb0, 176, 0260 */ 0, - /* 0xb1, 177, 0261 */ 0, - /* 0xb2, 178, 0262 */ 0, - /* 0xb3, 179, 0263 */ 0, - /* 0xb4, 180, 0264 */ 0, - /* 0xb5, 181, 0265 */ 0, - /* 0xb6, 182, 0266 */ 0, - /* 0xb7, 183, 0267 */ 0, - /* 0xb8, 184, 0270 */ 0, - /* 0xb9, 185, 0271 */ 0, - /* 0xba, 186, 0272 */ 0, - /* 0xbb, 187, 0273 */ 0, - /* 0xbc, 188, 0274 */ 0, - /* 0xbd, 189, 0275 */ 0, - /* 0xbe, 190, 0276 */ 0, - /* 0xbf, 191, 0277 */ 0, - /* 0xc0, 192, 0300 */ 0, - /* 0xc1, 193, 0301 */ 0, - /* 0xc2, 194, 0302 */ 0, - /* 0xc3, 195, 0303 */ 0, - /* 0xc4, 196, 0304 */ 0, - /* 0xc5, 197, 0305 */ 0, - /* 0xc6, 198, 0306 */ 0, - /* 0xc7, 199, 0307 */ 0, - /* 0xc8, 200, 0310 */ 0, - /* 0xc9, 201, 0311 */ 0, - /* 0xca, 202, 0312 */ 0, - /* 0xcb, 203, 0313 */ 0, - /* 0xcc, 204, 0314 */ 0, - /* 0xcd, 205, 0315 */ 0, - /* 0xce, 206, 0316 */ 0, - /* 0xcf, 207, 0317 */ 0, - /* 0xd0, 208, 0320 */ 0, - /* 0xd1, 209, 0321 */ 0, - /* 0xd2, 210, 0322 */ 0, - /* 0xd3, 211, 0323 */ 0, - /* 0xd4, 212, 0324 */ 0, - /* 0xd5, 213, 0325 */ 0, - /* 0xd6, 214, 0326 */ 0, - /* 0xd7, 215, 0327 */ 0, - /* 0xd8, 216, 0330 */ 0, - /* 0xd9, 217, 0331 */ 0, - /* 0xda, 218, 0332 */ 0, - /* 0xdb, 219, 0333 */ 0, - /* 0xdc, 220, 0334 */ 0, - /* 0xdd, 221, 0335 */ 0, - /* 0xde, 222, 0336 */ 0, - /* 0xdf, 223, 0337 */ 0, - /* 0xe0, 224, 0340 */ 0, - /* 0xe1, 225, 0341 */ 0, - /* 0xe2, 226, 0342 */ 0, - /* 0xe3, 227, 0343 */ 0, - /* 0xe4, 228, 0344 */ 0, - /* 0xe5, 229, 0345 */ 0, - /* 0xe6, 230, 0346 */ 0, - /* 0xe7, 231, 0347 */ 0, - /* 0xe8, 232, 0350 */ 0, - /* 0xe9, 233, 0351 */ 0, - /* 0xea, 234, 0352 */ 0, - /* 0xeb, 235, 0353 */ 0, - /* 0xec, 236, 0354 */ 0, - /* 0xed, 237, 0355 */ 0, - /* 0xee, 238, 0356 */ 0, - /* 0xef, 239, 0357 */ 0, - /* 0xf0, 240, 0360 */ 0, - /* 0xf1, 241, 0361 */ 0, - /* 0xf2, 242, 0362 */ 0, - /* 0xf3, 243, 0363 */ 0, - /* 0xf4, 244, 0364 */ 0, - /* 0xf5, 245, 0365 */ 0, - /* 0xf6, 246, 0366 */ 0, - /* 0xf7, 247, 0367 */ 0, - /* 0xf8, 248, 0370 */ 0, - /* 0xf9, 249, 0371 */ 0, - /* 0xfa, 250, 0372 */ 0, - /* 0xfb, 251, 0373 */ 0, - /* 0xfc, 252, 0374 */ 0, - /* 0xfd, 253, 0375 */ 0, - /* 0xfe, 254, 0376 */ 0, - /* 0xff, 255, 0377 */ 0, - -/* _uc_ctype_trans_C */ - - /* 0x00, 0, 00 */ 0x00, - /* 0x01, 1, 01 */ 0x01, - /* 0x02, 2, 02 */ 0x02, - /* 0x03, 3, 03 */ 0x03, - /* 0x04, 4, 04 */ 0x04, - /* 0x05, 5, 05 */ 0x05, - /* 0x06, 6, 06 */ 0x06, - /* 0x07, 7, 07 */ 0x07, - /* 0x08, 8, 010 */ 0x08, - /* 0x09, 9, 011 */ 0x09, - /* 0x0a, 10, 012 */ 0x0a, - /* 0x0b, 11, 013 */ 0x0b, - /* 0x0c, 12, 014 */ 0x0c, - /* 0x0d, 13, 015 */ 0x0d, - /* 0x0e, 14, 016 */ 0x0e, - /* 0x0f, 15, 017 */ 0x0f, - /* 0x10, 16, 020 */ 0x10, - /* 0x11, 17, 021 */ 0x11, - /* 0x12, 18, 022 */ 0x12, - /* 0x13, 19, 023 */ 0x13, - /* 0x14, 20, 024 */ 0x14, - /* 0x15, 21, 025 */ 0x15, - /* 0x16, 22, 026 */ 0x16, - /* 0x17, 23, 027 */ 0x17, - /* 0x18, 24, 030 */ 0x18, - /* 0x19, 25, 031 */ 0x19, - /* 0x1a, 26, 032 */ 0x1a, - /* 0x1b, 27, 033 */ 0x1b, - /* 0x1c, 28, 034 */ 0x1c, - /* 0x1d, 29, 035 */ 0x1d, - /* 0x1e, 30, 036 */ 0x1e, - /* 0x1f, 31, 037 */ 0x1f, - /* 0x20, 32, 040 */ 0x20, - /* 0x21, 33, 041 */ 0x21, - /* 0x22, 34, 042 */ 0x22, - /* 0x23, 35, 043 */ 0x23, - /* 0x24, 36, 044 */ 0x24, - /* 0x25, 37, 045 */ 0x25, - /* 0x26, 38, 046 */ 0x26, - /* 0x27, 39, 047 */ 0x27, - /* 0x28, 40, 050 */ 0x28, - /* 0x29, 41, 051 */ 0x29, - /* 0x2a, 42, 052 */ 0x2a, - /* 0x2b, 43, 053 */ 0x2b, - /* 0x2c, 44, 054 */ 0x2c, - /* 0x2d, 45, 055 */ 0x2d, - /* 0x2e, 46, 056 */ 0x2e, - /* 0x2f, 47, 057 */ 0x2f, - /* 0x30, 48, 060 */ 0x30, - /* 0x31, 49, 061 */ 0x31, - /* 0x32, 50, 062 */ 0x32, - /* 0x33, 51, 063 */ 0x33, - /* 0x34, 52, 064 */ 0x34, - /* 0x35, 53, 065 */ 0x35, - /* 0x36, 54, 066 */ 0x36, - /* 0x37, 55, 067 */ 0x37, - /* 0x38, 56, 070 */ 0x38, - /* 0x39, 57, 071 */ 0x39, - /* 0x3a, 58, 072 */ 0x3a, - /* 0x3b, 59, 073 */ 0x3b, - /* 0x3c, 60, 074 */ 0x3c, - /* 0x3d, 61, 075 */ 0x3d, - /* 0x3e, 62, 076 */ 0x3e, - /* 0x3f, 63, 077 */ 0x3f, - /* 0x40, 64, 0100 */ 0x40, - /* 0x41, 65, 0101 */ 0x61, - /* 0x42, 66, 0102 */ 0x62, - /* 0x43, 67, 0103 */ 0x63, - /* 0x44, 68, 0104 */ 0x64, - /* 0x45, 69, 0105 */ 0x65, - /* 0x46, 70, 0106 */ 0x66, - /* 0x47, 71, 0107 */ 0x67, - /* 0x48, 72, 0110 */ 0x68, - /* 0x49, 73, 0111 */ 0x69, - /* 0x4a, 74, 0112 */ 0x6a, - /* 0x4b, 75, 0113 */ 0x6b, - /* 0x4c, 76, 0114 */ 0x6c, - /* 0x4d, 77, 0115 */ 0x6d, - /* 0x4e, 78, 0116 */ 0x6e, - /* 0x4f, 79, 0117 */ 0x6f, - /* 0x50, 80, 0120 */ 0x70, - /* 0x51, 81, 0121 */ 0x71, - /* 0x52, 82, 0122 */ 0x72, - /* 0x53, 83, 0123 */ 0x73, - /* 0x54, 84, 0124 */ 0x74, - /* 0x55, 85, 0125 */ 0x75, - /* 0x56, 86, 0126 */ 0x76, - /* 0x57, 87, 0127 */ 0x77, - /* 0x58, 88, 0130 */ 0x78, - /* 0x59, 89, 0131 */ 0x79, - /* 0x5a, 90, 0132 */ 0x7a, - /* 0x5b, 91, 0133 */ 0x5b, - /* 0x5c, 92, 0134 */ 0x5c, - /* 0x5d, 93, 0135 */ 0x5d, - /* 0x5e, 94, 0136 */ 0x5e, - /* 0x5f, 95, 0137 */ 0x5f, - /* 0x60, 96, 0140 */ 0x60, - /* 0x61, 97, 0141 */ 0x41, - /* 0x62, 98, 0142 */ 0x42, - /* 0x63, 99, 0143 */ 0x43, - /* 0x64, 100, 0144 */ 0x44, - /* 0x65, 101, 0145 */ 0x45, - /* 0x66, 102, 0146 */ 0x46, - /* 0x67, 103, 0147 */ 0x47, - /* 0x68, 104, 0150 */ 0x48, - /* 0x69, 105, 0151 */ 0x49, - /* 0x6a, 106, 0152 */ 0x4a, - /* 0x6b, 107, 0153 */ 0x4b, - /* 0x6c, 108, 0154 */ 0x4c, - /* 0x6d, 109, 0155 */ 0x4d, - /* 0x6e, 110, 0156 */ 0x4e, - /* 0x6f, 111, 0157 */ 0x4f, - /* 0x70, 112, 0160 */ 0x50, - /* 0x71, 113, 0161 */ 0x51, - /* 0x72, 114, 0162 */ 0x52, - /* 0x73, 115, 0163 */ 0x53, - /* 0x74, 116, 0164 */ 0x54, - /* 0x75, 117, 0165 */ 0x55, - /* 0x76, 118, 0166 */ 0x56, - /* 0x77, 119, 0167 */ 0x57, - /* 0x78, 120, 0170 */ 0x58, - /* 0x79, 121, 0171 */ 0x59, - /* 0x7a, 122, 0172 */ 0x5a, - /* 0x7b, 123, 0173 */ 0x7b, - /* 0x7c, 124, 0174 */ 0x7c, - /* 0x7d, 125, 0175 */ 0x7d, - /* 0x7e, 126, 0176 */ 0x7e, - /* 0x7f, 127, 0177 */ 0x7f, - /* 0x80, 128, 0200 */ 0x80, - /* 0x81, 129, 0201 */ 0x81, - /* 0x82, 130, 0202 */ 0x82, - /* 0x83, 131, 0203 */ 0x83, - /* 0x84, 132, 0204 */ 0x84, - /* 0x85, 133, 0205 */ 0x85, - /* 0x86, 134, 0206 */ 0x86, - /* 0x87, 135, 0207 */ 0x87, - /* 0x88, 136, 0210 */ 0x88, - /* 0x89, 137, 0211 */ 0x89, - /* 0x8a, 138, 0212 */ 0x8a, - /* 0x8b, 139, 0213 */ 0x8b, - /* 0x8c, 140, 0214 */ 0x8c, - /* 0x8d, 141, 0215 */ 0x8d, - /* 0x8e, 142, 0216 */ 0x8e, - /* 0x8f, 143, 0217 */ 0x8f, - /* 0x90, 144, 0220 */ 0x90, - /* 0x91, 145, 0221 */ 0x91, - /* 0x92, 146, 0222 */ 0x92, - /* 0x93, 147, 0223 */ 0x93, - /* 0x94, 148, 0224 */ 0x94, - /* 0x95, 149, 0225 */ 0x95, - /* 0x96, 150, 0226 */ 0x96, - /* 0x97, 151, 0227 */ 0x97, - /* 0x98, 152, 0230 */ 0x98, - /* 0x99, 153, 0231 */ 0x99, - /* 0x9a, 154, 0232 */ 0x9a, - /* 0x9b, 155, 0233 */ 0x9b, - /* 0x9c, 156, 0234 */ 0x9c, - /* 0x9d, 157, 0235 */ 0x9d, - /* 0x9e, 158, 0236 */ 0x9e, - /* 0x9f, 159, 0237 */ 0x9f, - /* 0xa0, 160, 0240 */ 0xa0, - /* 0xa1, 161, 0241 */ 0xa1, - /* 0xa2, 162, 0242 */ 0xa2, - /* 0xa3, 163, 0243 */ 0xa3, - /* 0xa4, 164, 0244 */ 0xa4, - /* 0xa5, 165, 0245 */ 0xa5, - /* 0xa6, 166, 0246 */ 0xa6, - /* 0xa7, 167, 0247 */ 0xa7, - /* 0xa8, 168, 0250 */ 0xa8, - /* 0xa9, 169, 0251 */ 0xa9, - /* 0xaa, 170, 0252 */ 0xaa, - /* 0xab, 171, 0253 */ 0xab, - /* 0xac, 172, 0254 */ 0xac, - /* 0xad, 173, 0255 */ 0xad, - /* 0xae, 174, 0256 */ 0xae, - /* 0xaf, 175, 0257 */ 0xaf, - /* 0xb0, 176, 0260 */ 0xb0, - /* 0xb1, 177, 0261 */ 0xb1, - /* 0xb2, 178, 0262 */ 0xb2, - /* 0xb3, 179, 0263 */ 0xb3, - /* 0xb4, 180, 0264 */ 0xb4, - /* 0xb5, 181, 0265 */ 0xb5, - /* 0xb6, 182, 0266 */ 0xb6, - /* 0xb7, 183, 0267 */ 0xb7, - /* 0xb8, 184, 0270 */ 0xb8, - /* 0xb9, 185, 0271 */ 0xb9, - /* 0xba, 186, 0272 */ 0xba, - /* 0xbb, 187, 0273 */ 0xbb, - /* 0xbc, 188, 0274 */ 0xbc, - /* 0xbd, 189, 0275 */ 0xbd, - /* 0xbe, 190, 0276 */ 0xbe, - /* 0xbf, 191, 0277 */ 0xbf, - /* 0xc0, 192, 0300 */ 0xc0, - /* 0xc1, 193, 0301 */ 0xc1, - /* 0xc2, 194, 0302 */ 0xc2, - /* 0xc3, 195, 0303 */ 0xc3, - /* 0xc4, 196, 0304 */ 0xc4, - /* 0xc5, 197, 0305 */ 0xc5, - /* 0xc6, 198, 0306 */ 0xc6, - /* 0xc7, 199, 0307 */ 0xc7, - /* 0xc8, 200, 0310 */ 0xc8, - /* 0xc9, 201, 0311 */ 0xc9, - /* 0xca, 202, 0312 */ 0xca, - /* 0xcb, 203, 0313 */ 0xcb, - /* 0xcc, 204, 0314 */ 0xcc, - /* 0xcd, 205, 0315 */ 0xcd, - /* 0xce, 206, 0316 */ 0xce, - /* 0xcf, 207, 0317 */ 0xcf, - /* 0xd0, 208, 0320 */ 0xd0, - /* 0xd1, 209, 0321 */ 0xd1, - /* 0xd2, 210, 0322 */ 0xd2, - /* 0xd3, 211, 0323 */ 0xd3, - /* 0xd4, 212, 0324 */ 0xd4, - /* 0xd5, 213, 0325 */ 0xd5, - /* 0xd6, 214, 0326 */ 0xd6, - /* 0xd7, 215, 0327 */ 0xd7, - /* 0xd8, 216, 0330 */ 0xd8, - /* 0xd9, 217, 0331 */ 0xd9, - /* 0xda, 218, 0332 */ 0xda, - /* 0xdb, 219, 0333 */ 0xdb, - /* 0xdc, 220, 0334 */ 0xdc, - /* 0xdd, 221, 0335 */ 0xdd, - /* 0xde, 222, 0336 */ 0xde, - /* 0xdf, 223, 0337 */ 0xdf, - /* 0xe0, 224, 0340 */ 0xe0, - /* 0xe1, 225, 0341 */ 0xe1, - /* 0xe2, 226, 0342 */ 0xe2, - /* 0xe3, 227, 0343 */ 0xe3, - /* 0xe4, 228, 0344 */ 0xe4, - /* 0xe5, 229, 0345 */ 0xe5, - /* 0xe6, 230, 0346 */ 0xe6, - /* 0xe7, 231, 0347 */ 0xe7, - /* 0xe8, 232, 0350 */ 0xe8, - /* 0xe9, 233, 0351 */ 0xe9, - /* 0xea, 234, 0352 */ 0xea, - /* 0xeb, 235, 0353 */ 0xeb, - /* 0xec, 236, 0354 */ 0xec, - /* 0xed, 237, 0355 */ 0xed, - /* 0xee, 238, 0356 */ 0xee, - /* 0xef, 239, 0357 */ 0xef, - /* 0xf0, 240, 0360 */ 0xf0, - /* 0xf1, 241, 0361 */ 0xf1, - /* 0xf2, 242, 0362 */ 0xf2, - /* 0xf3, 243, 0363 */ 0xf3, - /* 0xf4, 244, 0364 */ 0xf4, - /* 0xf5, 245, 0365 */ 0xf5, - /* 0xf6, 246, 0366 */ 0xf6, - /* 0xf7, 247, 0367 */ 0xf7, - /* 0xf8, 248, 0370 */ 0xf8, - /* 0xf9, 249, 0371 */ 0xf9, - /* 0xfa, 250, 0372 */ 0xfa, - /* 0xfb, 251, 0373 */ 0xfb, - /* 0xfc, 252, 0374 */ 0xfc, - /* 0xfd, 253, 0375 */ 0xfd, - /* 0xfe, 254, 0376 */ 0xfe, - /* 0xff, 255, 0377 */ 0xff -}; diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c index 23e024e15..ab3ee2fd7 100644 --- a/libc/misc/internals/__uClibc_main.c +++ b/libc/misc/internals/__uClibc_main.c @@ -34,6 +34,9 @@ extern void weak_function _stdio_init(void); extern void weak_function _stdio_term(void); extern int *weak_const_function __errno_location(void); extern int *weak_const_function __h_errno_location(void); +#ifdef __UCLIBC_HAS_LOCALE__ +extern void weak_function _locale_init(void); +#endif #else /* * Define an empty function and use it as a weak alias for the stdio @@ -62,6 +65,9 @@ extern int atexit(void (*function)(void)); extern int *__errno_location(void); //weak_alias(__uClibc_empty_func, __h_errno_location); extern int *__h_errno_location(void); +#ifdef __UCLIBC_HAS_LOCALE__ +extern void _locale_init(void); +#endif #endif /* @@ -93,6 +99,12 @@ __uClibc_main(int argc, char **argv, char **envp) if (unlikely (__libc_enable_secure)) __libc_check_standard_fds (); #endif + +#ifdef __UCLIBC_HAS_LOCALE__ + /* Initialize the global locale structure. */ + if (likely(_locale_init)) _locale_init(); +#endif + /* * Initialize stdio here. In the static library case, this will * be bypassed if not needed because of the weak alias above. diff --git a/libc/misc/locale/Makefile b/libc/misc/locale/Makefile index 77a54bdc4..393336c50 100644 --- a/libc/misc/locale/Makefile +++ b/libc/misc/locale/Makefile @@ -24,9 +24,14 @@ TOPDIR=../../../ include $(TOPDIR)Rules.mak -CSRC=locale.c localeconv.c -COBJS=$(patsubst %.c,%.o, $(CSRC)) -OBJS=$(COBJS) +MSRC= locale.c +MOBJ= setlocale.o localeconv.o _locale_init.o nl_langinfo.o + +OBJS= $(MOBJ) + +ifeq ($(HAS_LOCALE),true) + OBJS += locale_data.o +endif all: $(OBJS) $(LIBC) @@ -35,8 +40,8 @@ $(LIBC): ar-target ar-target: $(OBJS) $(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): %.o : %.c - $(CC) $(CFLAGS) -c $< -o $@ +$(MOBJ): $(MSRC) + $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o $(STRIPTOOL) -x -R .note -R .comment $*.o $(OBJS): Makefile diff --git a/libc/misc/locale/_locale.h b/libc/misc/locale/_locale.h deleted file mode 100644 index 139a862f9..000000000 --- a/libc/misc/locale/_locale.h +++ /dev/null @@ -1,22 +0,0 @@ -extern const unsigned char *_uc_ctype_b; -extern const unsigned char *_uc_ctype_trans; - -extern const unsigned char _uc_ctype_b_C[256+256]; - -#define LOCALE_BUF_SIZE (sizeof(_uc_ctype_b_C)) - -#define ISbit(bit) (1 << bit) - -enum -{ - ISprint = ISbit (0), /* 1 Printable. */ - ISupper = ISbit (1), /* 2 UPPERCASE. */ - ISlower = ISbit (2), /* 4 lowercase. */ - IScntrl = ISbit (3), /* 8 Control character. */ - ISspace = ISbit (4), /* 16 Whitespace. */ - ISpunct = ISbit (5), /* 32 Punctuation. */ - ISalpha = ISbit (6), /* 64 Alphabetic. */ - ISxdigit = ISbit (7), /* 128 Hexnumeric. */ -}; - -extern const unsigned char *_uc_collate_b; diff --git a/libc/misc/locale/locale.c b/libc/misc/locale/locale.c index d978ae37c..fd587429b 100644 --- a/libc/misc/locale/locale.c +++ b/libc/misc/locale/locale.c @@ -1,332 +1,507 @@ -/* setlocale.c - * Load LC_CTYPE and LC_COLLATE locale only special for uclibc +/* Copyright (C) 2002 Manuel Novoa III * - * Written by Vladimir Oleynik (c) vodz@usa.net + * 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 file is part of the uClibc C library and is distributed - * under the GNU Library General Public License. - * used ideas is part of the GNU C Library. + * 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. + */ + +/* TODO: + * Implement the shared mmap code so non-mmu platforms can use this. + * Implement nl_langinfo() for the stub locale support. + * Add some basic collate functionality similar to what the previous + * locale support had (8-bit codesets only). */ +#define _GNU_SOURCE #include <locale.h> -#include <stdio.h> /* NULL, fopen */ -#include <stdlib.h> /* malloc */ #include <string.h> -#include <limits.h> /* PATH_MAX */ -#include <errno.h> /* EINVAL */ -#include <unistd.h> /* get(e)[u|g]id */ +#include <stdlib.h> +#include <stddef.h> +#include <limits.h> +#include <stdint.h> +#include <assert.h> -#include "_locale.h" +#ifdef __LOCALE_C_ONLY -static char C_LOCALE_NAME []="C"; -static char POSIX_LOCALE_NAME[]="POSIX"; -static char composite_name_C []= -"LC_CTYPE=C;LC_NUMERIC=C;LC_TIME=C;LC_COLLATE=C;LC_MONETARY=C;LC_MESSAGES=C"; +#ifdef __WCHAR_ENABLED +#error wide char support requires full locale support +#endif -#ifdef __UCLIBC_HAS_LOCALE__ +#else /* __LOCALE_C_ONLY */ -#ifdef TEST_LOCALE -static const char PATH_LOCALE[]="./"; -#else -static const char PATH_LOCALE[]=__UCLIBC_LOCALE_DIR; -#endif +#define CUR_LOCALE_SPEC (__global_locale.cur_locale) +#undef CODESET_LIST +#define CODESET_LIST (__locale_mmap->codeset_list) -struct SAV_LOADED_LOCALE { - int category; - char *locale; - const unsigned char *buf; - struct SAV_LOADED_LOCALE *next; -}; +/* TODO: Optional... See below. */ +#define __LOCALE_STRICTER_SETLOCALE -static struct SAV_LOADED_LOCALE sll_C_LC_MESSAGES = { - LC_MESSAGES, C_LOCALE_NAME, 0, 0 -}; +#endif /* __LOCALE_C_ONLY */ -static struct SAV_LOADED_LOCALE sll_C_LC_MONETARY = { - LC_MONETARY, C_LOCALE_NAME, 0, &sll_C_LC_MESSAGES -}; +/**********************************************************************/ +#ifdef L_setlocale -static struct SAV_LOADED_LOCALE sll_C_LC_COLLATE = { - LC_COLLATE, C_LOCALE_NAME, 0, &sll_C_LC_MONETARY -}; +#ifdef __LOCALE_C_ONLY -static struct SAV_LOADED_LOCALE sll_C_LC_TIME = { - LC_TIME, C_LOCALE_NAME, 0, &sll_C_LC_COLLATE -}; +link_warning(setlocale,"the 'setlocale' function supports only C|POSIX locales"); -static struct SAV_LOADED_LOCALE sll_C_LC_NUMERIC = { - LC_NUMERIC, C_LOCALE_NAME, 0, &sll_C_LC_TIME -}; +static const char C_string[] = "C"; -static struct SAV_LOADED_LOCALE sll_C_LC_CTYPE = { - LC_CTYPE, C_LOCALE_NAME, _uc_ctype_b_C, &sll_C_LC_NUMERIC -}; +char *setlocale(int category, register const char *locale) +{ + return ( (((unsigned int)(category)) <= LC_ALL) + && ( (!locale) /* Request for locale category string. */ + || (!*locale) /* Implementation-defined default is C. */ + || ((*locale == 'C') && !locale[1]) + || (!strcmp(locale, "POSIX"))) ) + ? (char *) C_string /* Always in C/POSIX locale. */ + : NULL; +} -static struct SAV_LOADED_LOCALE *sll = &sll_C_LC_CTYPE; +#else /* ---------------------------------------------- __LOCALE_C_ONLY */ +#if !defined(NUM_LOCALES) || (NUM_LOCALES <= 1) +#error locales enabled, but not data other than for C locale! +#endif -#endif /* __UCLIBC_HAS_LOCALE__ */ +static unsigned char setlocale_buf[LOCALE_STRING_SIZE]; -static char *nl_current[LC_ALL+1] = { - C_LOCALE_NAME, C_LOCALE_NAME, C_LOCALE_NAME, - C_LOCALE_NAME, C_LOCALE_NAME, C_LOCALE_NAME, - composite_name_C -}; +#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) -static const char * const LC_strs[LC_ALL+1] = { - "/LC_CTYPE", - "/LC_NUMERIC", - "/LC_TIME", - "/LC_COLLATE", - "/LC_MONETARY", - "/LC_MESSAGES", - "/LC_ALL" -}; +static const char posix[] = "POSIX"; -static char *find_locale(int c, const char **plocale) +static int find_locale(int category, const char *p, unsigned char *new_locale) { -#ifdef __UCLIBC_HAS_LOCALE__ - struct SAV_LOADED_LOCALE *cur; + 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. */ + 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; + } + memcpy(buf, p, q-p); + buf[q-p] = 0; + buf[2] = s[1]; + p = buf; + } #endif - const char *name = *plocale; - - if (name[0] == '\0') { - /* The user decides which locale to use by setting environment - variables. */ - name = getenv (&LC_strs[LC_ALL][1]); - if (name == NULL || name[0] == '\0') - name = getenv (&LC_strs[c][1]); - if (name == NULL || name[0] == '\0') - name = getenv ("LANG"); - if (name == NULL || name[0] == '\0') - name = C_LOCALE_NAME; + + lang_cult = codeset = 0; /* Assume C and default codeset. */ + if (((*p == 'C') && !p[1]) || !strcmp(p, posix)) { + goto FIND_LOCALE; } - if (strcmp (name, C_LOCALE_NAME) == 0 || - strcmp (name, POSIX_LOCALE_NAME) == 0 || - /* TODO! */ (c!=LC_CTYPE && c!=LC_COLLATE)) - name = C_LOCALE_NAME; + if (p[5] == '.') { /* Codeset specified in locale name? */ + /* TODO: maybe CODESET_LIST + *s ??? */ + /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */ + codeset = 2; + if (strcmp("UTF-8",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! */ + } + } - *plocale = name; + 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 = 1; + 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 >> 8) | 0x80; + *((unsigned char *) ++s) = n & 0xff; + } while (++i < category); + + return i; /* Return non-zero */ + } + s += WIDTH_LOCALES; + ++n; + } while (n <= NUM_LOCALES); /* We started at 1!!! */ -#ifdef __UCLIBC_HAS_LOCALE__ - for(cur = sll; cur; cur = cur->next) - if(cur->category == c && strcmp(cur->locale, name)==0) - return cur->locale; -#else - if(name == C_LOCALE_NAME) - return C_LOCALE_NAME; -#endif - return NULL; + return 0; /* Unsupported locale. */ } - -#ifdef __UCLIBC_HAS_LOCALE__ -static char *load_locale(int category, const char *locale) +char *setlocale(int category, const char *locale) { - FILE * fl; - char full_path[PATH_MAX]; - char * buf = 0; - struct SAV_LOADED_LOCALE *cur; - struct SAV_LOADED_LOCALE *bottom; - int bufsize; - int l = strlen(locale); - - if((l+sizeof(PATH_LOCALE)+strlen(LC_strs[category]))>=PATH_MAX) - return NULL; - - /* Not allow acces suid/sgid binaries to outside PATH_LOCALE */ - if((geteuid()!=getuid() || getegid()!=getgid()) && - strchr(locale, '/')!=NULL) - return NULL; - - strcpy(full_path, PATH_LOCALE); - strcat(full_path, locale); - strcat(full_path, LC_strs[category]); - fl = fopen(full_path, "r"); - if(fl==0) - return NULL; + const unsigned char *p; + unsigned char *s; + int i; + unsigned lc_mask; + unsigned char new_locale[LOCALE_STRING_SIZE]; + + if (((unsigned int)(category)) > LC_ALL) { + /* TODO - set errno? SUSv3 doesn't say too. */ + return NULL; /* Illegal/unsupported category. */ + } - switch(category) { - case LC_CTYPE: - bufsize = LOCALE_BUF_SIZE; - break; - case LC_COLLATE: - bufsize = 256; - break; - default: /* TODO */ - bufsize = 0; - break; + lc_mask = 1 << category; + if (category == LC_ALL) { + --lc_mask; } - cur = malloc(sizeof(struct SAV_LOADED_LOCALE)+bufsize+l+2); - if(cur) { - buf = (char *)(cur+1); - if(bufsize!=0 && fread(buf, 1, bufsize+1, fl)!=(bufsize)) { - /* broken locale file */ - free(cur); - buf = 0; -#ifdef TEST_LOCALE - fprintf(stderr, "\nbroken locale file\n"); -#endif - } + if (!locale) { /* Request for locale category string... */ + DONE: + strcpy(setlocale_buf, CUR_LOCALE_SPEC); +#ifdef __LOCALE_STRICTER_SETLOCALE + /* The standard says you can only use the string returned to restore + * the category (categories) requested. This could be optional. + * See below as well. */ + s = setlocale_buf + 1; + lc_mask |= (1 << LC_ALL); + do { + if (!(lc_mask & 1)) { + /* Encode non-selected locale flag. */ + s[1] = *s = 0xff; + } + s += 2; + } while ((lc_mask >>= 1) > 1); +#endif /* __LOCALE_STRICTER_SETLOCALE */ + return (char *) setlocale_buf; } - fclose(fl); - if(cur==0) /* not enough memory */ + strcpy(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 (*locale == '#') { /* Previsouly returned value. */ + assert(strlen(locale) == LOCALE_STRING_SIZE - 1); + + i = ((category == LC_ALL) ? 0 : category); + p = locale + 2*i; + s = new_locale + 2*i; + do { +#ifdef __LOCALE_STRICTER_SETLOCALE + /* Only set categories that were selected in the previous + * return value. Could be optional. See above as well. + * NOTE: This still isn't quite right for non-LC_ALL + * as it only checks the category selected to set. */ + if ((*p == 0xff) && (p[1] == 0xff)) { + return NULL; + } +#endif /* __LOCALE_STRICTER_SETLOCALE */ + /* Note: Validate settings below. */ + *++s = *++p; + *++s = *++p; + } while (++i < category); + } else if (!find_locale(category, locale, new_locale)) { return NULL; - if(buf==0) { /* broken locale file, set to "C" */ - return C_LOCALE_NAME; } - cur->next = 0; - cur->buf = buf; - cur->category = category; - cur->locale = buf+bufsize; - strcpy(cur->locale, locale); - bottom = sll; - while(bottom->next!=0) - bottom = bottom->next; - bottom->next = cur; + /* TODO: Ok, everything checks out, so install the new locale. */ + _locale_set(new_locale); - return cur->locale; + /* Everything ok, so make a copy in setlocale_buf and return. */ + goto DONE; } -static char *set_composite(int category, char *locale) +#endif /* __LOCALE_C_ONLY */ + +#endif +/**********************************************************************/ +#ifdef L_localeconv + +/* Note: We assume here that the compiler does the sane thing regarding + * placement of the fields in the struct. If necessary, we could ensure + * this usings an array of offsets but at some size cost. */ + +#ifdef __LOCALE_C_ONLY + +#warning localeconv is hardwired for C/POSIX locale only +link_warning(localeconv,"the 'localeconv' function is hardwired for C/POSIX locale only"); + +static struct lconv the_lconv; + +static const char decpt[] = "."; + +struct lconv *localeconv(void) { - int i, l; - char *old_composite_name = nl_current[LC_ALL]; - char *new_composite_name; - struct SAV_LOADED_LOCALE *cur; - - for(l=i=0; i<LC_ALL; i++) { - new_composite_name = i == category ? locale : nl_current[i]; - /* '=' + ';' or '\0' */ - l += strlen(&LC_strs[i][1])+strlen(new_composite_name)+2; - } + register char *p = (char *)(&the_lconv); - new_composite_name = malloc(l); - if(new_composite_name==NULL) - return NULL; - if(old_composite_name!=composite_name_C) - free(old_composite_name); - nl_current[category] = locale; /* change after malloc */ - - *new_composite_name = 0; - for(i=0; i<LC_ALL; i++) { - if(i) - strcat(new_composite_name, ";"); - strcat(new_composite_name, &LC_strs[i][1]); - strcat(new_composite_name, "="); - strcat(new_composite_name, nl_current[i]); - } - nl_current[LC_ALL] = new_composite_name; - - /* set locale data for ctype and strcollate functions */ - for(cur = sll; ; cur = cur->next) - if(cur->category == category && cur->locale == locale) - break; - - switch(category) { - case LC_CTYPE: - _uc_ctype_b = cur->buf; - _uc_ctype_trans = cur->buf+LOCALE_BUF_SIZE/2; - break; - case LC_COLLATE: - _uc_collate_b = cur->buf; - break; - default: /* TODO */ - break; - } - return locale; + *((char **)p) = (char *) decpt; + do { + p += sizeof(char **); + *((char **)p) = (char *) (decpt+1); + } while (p < (char *) &the_lconv.negative_sign); + + p = (&the_lconv.int_frac_digits); + do { + *p = CHAR_MAX; + ++p; + } while (p <= &the_lconv.int_n_sign_posn); + + return &the_lconv; } -#endif /* __UCLIBC_HAS_LOCALE__ */ +#else /* __LOCALE_C_ONLY */ -char *setlocale(int category, const char *locale) +static struct lconv the_lconv; + +struct lconv *localeconv(void) { - char * tl; -#ifdef __UCLIBC_HAS_LOCALE__ - int i; + register char *p = (char *) &the_lconv; + register char **q = (char **) &__global_locale.decimal_point; + + do { + *((char **)p) = *q; + p += sizeof(char **); + ++q; + } while (p < &the_lconv.int_frac_digits); + + do { + *p = **q; + ++p; + ++q; + } while (p <= &the_lconv.int_n_sign_posn); + + return &the_lconv; +} + +#endif /* __LOCALE_C_ONLY */ + #endif +/**********************************************************************/ +#ifdef L__locale_init - if (category < 0 || category > LC_ALL) { -#ifdef __UCLIBC_HAS_LOCALE__ -einval: +#ifndef __LOCALE_C_ONLY + +#define C_LOCALE_SELECTOR "\x23\x80\x01\x80\x01\x80\x01\x80\x01\x80\x01\x80\x01" +#define LOCALE_INIT_FAILED "locale init failed!\n" + +#define CUR_LOCALE_SPEC (__global_locale.cur_locale) + +__locale_t __global_locale; + +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_offsets[0] = offsetof(__locale_t, codeset); + __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) +{ + const char **x; + unsigned char *s = CUR_LOCALE_SPEC + 1; + const size_t *stp; + const unsigned char *r; + const uint16_t *io; + const uint16_t *ii; + const unsigned char *d; + int row; /* locale row */ + int crow; /* category row */ + int len; + int c; + int i = 0; + + ++p; + do { + if ((*p != *s) || (p[1] != s[1])) { + row = (((int)(*p & 0x7f)) << 8) + p[1] - 1; +#ifndef NDEBUG + assert(row < NUM_LOCALES); #endif - errno = EINVAL; - return NULL; - } + *s = *p; + s[1] = p[1]; + + if (i == LC_CTYPE) { + c = __locale_mmap->locales[ WIDTH_LOCALES * row + 2 ]; /* codeset */ + if (c <= 2) { + if (c == 2) { + __global_locale.codeset = utf8; + __global_locale.encoding = __ctype_encoding_utf8; + /* TODO - fix for bcc */ + __global_locale.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; + } + } else { + const codeset_8_bit_t *c8b; + r = CODESET_LIST; + __global_locale.codeset = r + r[c -= 3]; + __global_locale.encoding = __ctype_encoding_8_bit; +#warning REMINDER: update 8 bit mb_cur_max when trasnlit implemented! + /* TODO - update when translit implemented! */ + __global_locale.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; + /* translit */ +#endif /* __WCHAR_ENABLED */ +#endif /* __CTYPE_HAS_8_BIT_LOCALES */ + } + + } else if ((len = __locale_mmap->lc_common_item_offsets_LEN[i]) != 0) { + crow = __locale_mmap->locales[ WIDTH_LOCALES * row + 3 + i ] + * len; + x = (const char **)(((char *) &__global_locale) + + __global_locale.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 ); + ii = (const uint16_t *)( ((char *)__locale_mmap) + *++stp ); + d = (const unsigned char *)( ((char *)__locale_mmap) + *++stp ); + for (c=0 ; c < len ; c++) { + *(x + c) = d + ii[ r[crow + c] + io[c] ]; + } + } - if(locale==NULL) - return nl_current[category]; - - if(category!=LC_ALL) { - tl = find_locale(category, &locale); -#ifdef __UCLIBC_HAS_LOCALE__ - if(tl==NULL) - tl = load_locale(category, locale); - if(tl) { - if(nl_current[category] != tl) - tl = set_composite(category, tl); } + ++i; + p += 2; + s += 2; + } while (i < LC_ALL); +} + +#endif /* __LOCALE_C_ONLY */ + #endif - return tl; - } - /* LC_ALL */ -#ifdef __UCLIBC_HAS_LOCALE__ - /* The user wants to set all categories. The desired locales - for the individual categories can be selected by using a - composite locale name. This is a semi-colon separated list - of entries of the form `CATEGORY=VALUE'. */ - tl = strchr(locale, ';'); - if(tl==NULL) { - /* This is not a composite name. Load the data for each category. */ - for(i=0; i<LC_ALL; i++) - setlocale(i, locale); /* recursive */ - } else { - /* This is a composite name. Make a copy and split it up. */ - const char *newnames[LC_ALL]; - char *np; - char *cp; - - i = strlen(locale); - np = alloca (i); - if(np) - strcpy(np, locale); - else - return NULL; - for (i = 0; i < LC_ALL; ++i) - newnames[i] = 0; - - while ((cp = strchr (np, '=')) != NULL) { - for (i = 0; i < LC_ALL; ++i) - if ((size_t) (cp - np) == strlen(&LC_strs[i][1]) - && memcmp (np, &LC_strs[i][1], (cp - np)) == 0) - break; - - if (i == LC_ALL) - /* Bogus category name. */ - goto einval; - - /* Found the category this clause sets. */ - newnames[i] = ++cp; - cp = strchr (cp, ';'); - if (cp != NULL) { - /* Examine the next clause. */ - *cp = '\0'; - np = cp + 1; - } else - /* This was the last clause. We are done. */ - break; - } - - for (i = 0; i < LC_ALL; ++i) - setlocale(i, newnames[i]); /* recursive */ +/**********************************************************************/ +#ifdef L_nl_langinfo + +#ifndef __LOCALE_C_ONLY + +#include <langinfo.h> +#include <nl_types.h> + +static const char empty[] = ""; + +char *nl_langinfo(nl_item item) +{ + 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]; + } + return (char *) empty; +} + +#endif /* __LOCALE_C_ONLY */ #endif - return nl_current[LC_ALL]; -} +/**********************************************************************/ diff --git a/libc/misc/locale/localeconv.c b/libc/misc/locale/localeconv.c deleted file mode 100644 index ab447924a..000000000 --- a/libc/misc/locale/localeconv.c +++ /dev/null @@ -1,52 +0,0 @@ -/* localeconv.c - * - * Written by Erik Andersen <andersee@debian.org> - * - * 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; see the file COPYING.LIB. If not, - * write to the Free Software Foundation, Inc., 675 Mass Ave, - * Cambridge, MA 02139, USA. */ - -#include <string.h> -#include <locale.h> - -/* Return monetary and numeric information about the current locale. */ -struct lconv * localeconv __P ((void)) -{ - static struct lconv result; - static char *blank = ""; - static char *decimal = "."; - char junk = '\177'; - - result.decimal_point = decimal; - result.thousands_sep = blank; - result.grouping = "\177"; - result.int_curr_symbol = blank; - result.currency_symbol = blank; - result.mon_decimal_point = blank; - result.mon_thousands_sep = blank; - result.mon_grouping = blank; - result.positive_sign = blank; - result.negative_sign = blank; - result.int_frac_digits = junk; - result.frac_digits = junk; - result.p_cs_precedes = junk; - result.p_sep_by_space = junk; - result.n_cs_precedes = junk; - result.n_sep_by_space = junk; - result.p_sign_posn = junk; - result.n_sign_posn = junk; - - return &result; -} - diff --git a/libc/misc/wctype/Makefile b/libc/misc/wctype/Makefile new file mode 100644 index 000000000..875ccef56 --- /dev/null +++ b/libc/misc/wctype/Makefile @@ -0,0 +1,47 @@ +# Makefile for uClibc +# +# Copyright (C) 2000 by Lineo, inc. +# Copyright (C) 2000,2001 Erik Andersen <andersen@uclibc.org> +# +# 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= 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 + +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 + +clean: + rm -f *.[oa] *~ core + diff --git a/libc/misc/wctype/wctype.c b/libc/misc/wctype/wctype.c new file mode 100644 index 000000000..39ed2cfd5 --- /dev/null +++ b/libc/misc/wctype/wctype.c @@ -0,0 +1,480 @@ +/* Copyright (C) 2002 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. + */ + +/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! + * + * Besides uClibc, I'm using this code in my libc for elks, which is + * a 16-bit environment with a fairly limited compiler. It would make + * things much easier for me if this file isn't modified unnecessarily. + * In particular, please put any new or replacement functions somewhere + * else, and modify the makefile to use your version instead. + * Thanks. Manuel + * + * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */ + +#define _GNU_SOURCE +#define __NO_CTYPE + +#include <wctype.h> +#include <assert.h> +#include <string.h> +#include <errno.h> +#include <locale.h> + +/* 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 __WCTYPE_WITH_LOCALE + +/**********************************************************************/ + +#ifndef __PASTE +#define __PASTE(X,Y) X ## Y +#endif + +#define C_MACRO(X) __PASTE(__C_,X)(wc) + +#define CT_MACRO(X) __PASTE(__ctype_,X)(wc) + +/**********************************************************************/ + +/* TODO: fix this! */ +#ifdef __WCTYPE_WITH_LOCALE + +#define WCctype (__global_locale.tblwctype) +#define WCuplow (__global_locale.tblwuplow) +#define WCcmob (__global_locale.tblwcomb) +#define WCuplow_diff (__global_locale.tblwuplow_diff) + +#define ENCODING (__global_locale.encoding) + +#define ISW_FUNC_BODY(NAME) \ +int NAME (wint_t wc) \ +{ \ + return iswctype(wc, __PASTE(_CTYPE_,NAME)); \ +} + +#else /* __WCTYPE_WITH_LOCALE */ + +#define ISW_FUNC_BODY(NAME) \ +int NAME (wint_t wc) \ +{ \ + return C_MACRO(NAME); \ +} + +#endif /* __WCTYPE_WITH_LOCALE */ + +/**********************************************************************/ +#ifdef L_iswalnum + +ISW_FUNC_BODY(iswalnum); + +#endif +/**********************************************************************/ +#ifdef L_iswalpha + +ISW_FUNC_BODY(iswalpha); + +#endif +/**********************************************************************/ +#ifdef L_iswblank + +ISW_FUNC_BODY(iswblank); + +#endif +/**********************************************************************/ +#ifdef L_iswcntrl + +ISW_FUNC_BODY(iswcntrl); + +#endif +/**********************************************************************/ +#ifdef L_iswdigit + +int iswdigit(wint_t wc) +{ + return __C_iswdigit(wc); +} + +#endif +/**********************************************************************/ +#ifdef L_iswgraph + +ISW_FUNC_BODY(iswgraph); + +#endif +/**********************************************************************/ +#ifdef L_iswlower + +ISW_FUNC_BODY(iswlower); + +#endif +/**********************************************************************/ +#ifdef L_iswprint + +ISW_FUNC_BODY(iswprint); + +#endif +/**********************************************************************/ +#ifdef L_iswpunct + +ISW_FUNC_BODY(iswpunct); + +#endif +/**********************************************************************/ +#ifdef L_iswspace + +ISW_FUNC_BODY(iswspace); + +#endif +/**********************************************************************/ +#ifdef L_iswupper + +ISW_FUNC_BODY(iswupper); + +#endif +/**********************************************************************/ +#ifdef L_iswxdigit + +int iswxdigit(wint_t wc) +{ + return __C_iswxdigit(wc); +} + +#endif +/**********************************************************************/ +#ifdef L_towlower + +#ifdef __WCTYPE_WITH_LOCALE + +#ifdef SMALL_UPLOW + +wint_t towlower(wint_t wc) +{ + return towctrans(wc, _CTYPE_tolower); +} + +#else + +wint_t towlower(wint_t wc) +{ + unsigned int sc, n, i; + __uwchar_t u = wc; + + if (ENCODING == __ctype_encoding_7_bit) { + /* We're in the C/POSIX locale, so ignore the tables. */ + return __C_towlower(wc); + } + + if (u <= WC_TABLE_DOMAIN_MAX) { + sc = u & ((1 << WCuplow_TI_SHIFT) - 1); + u >>= WCuplow_TI_SHIFT; + n = u & ((1 << WCuplow_II_SHIFT) - 1); + u >>= WCuplow_II_SHIFT; + + i = ((unsigned int) WCuplow[u]) << WCuplow_II_SHIFT; + i = ((unsigned int) WCuplow[WCuplow_II_LEN + i + n]) + << WCuplow_TI_SHIFT; + i = ((unsigned int) WCuplow[WCuplow_II_LEN + WCuplow_TI_LEN + + i + sc]) << 1; + wc += WCuplow_diff[i + 1]; + } + return wc; +} + +#endif + +#else /* __WCTYPE_WITH_LOCALE */ + +wint_t towlower(wint_t wc) +{ + return __C_towlower(wc); +} + +#endif /* __WCTYPE_WITH_LOCALE */ + +#endif +/**********************************************************************/ +#ifdef L_towupper + +#ifdef __WCTYPE_WITH_LOCALE + +#ifdef SMALL_UPLOW + +wint_t towupper(wint_t wc) +{ + return towctrans(wc, _CTYPE_toupper); +} + +#else + +wint_t towupper(wint_t wc) +{ + unsigned int sc, n, i; + __uwchar_t u = wc; + + if (ENCODING == __ctype_encoding_7_bit) { + /* We're in the C/POSIX locale, so ignore the tables. */ + return __C_towupper(wc); + } + + if (u <= WC_TABLE_DOMAIN_MAX) { + sc = u & ((1 << WCuplow_TI_SHIFT) - 1); + u >>= WCuplow_TI_SHIFT; + n = u & ((1 << WCuplow_II_SHIFT) - 1); + u >>= WCuplow_II_SHIFT; + + i = ((unsigned int) WCuplow[u]) << WCuplow_II_SHIFT; + i = ((unsigned int) WCuplow[WCuplow_II_LEN + i + n]) + << WCuplow_TI_SHIFT; + i = ((unsigned int) WCuplow[WCuplow_II_LEN + WCuplow_TI_LEN + + i + sc]) << 1; + wc += WCuplow_diff[i]; + } + return wc; +} + +#endif + +#else /* __WCTYPE_WITH_LOCALE */ + +wint_t towupper(wint_t wc) +{ + return __C_towupper(wc); +} + +#endif /* __WCTYPE_WITH_LOCALE */ + +#endif +/**********************************************************************/ +#ifdef L_wctype + +static const unsigned char typestring[] = __CTYPE_TYPESTRING; +/* extern const unsigned char typestring[]; */ + +wctype_t wctype(const char *property) +{ + const unsigned char *p; + int i; + + p = typestring; + i = 1; + do { + if (!strcmp(property, ++p)) { + return i; + } + ++i; + p += p[-1]; + } while (*p); + + /* TODO - Add locale-specific classifications. */ + return 0; +} + +#endif +/**********************************************************************/ +#ifdef L_iswctype + +#warning TODO: need to fix locale ctype table lookup stuff +#if 0 +extern const char ctype_range[]; +#else +static const char ctype_range[] = { + __CTYPE_RANGES +}; +#endif + +#warning TODO: need to handle combining class! + +#define WCctype_TI_MASK ((1 << WCctype_TI_SHIFT) - 1) +#define WCctype_II_MASK ((1 << WCctype_II_SHIFT) - 1) + +int iswctype(wint_t wc, wctype_t desc) +{ + unsigned int sc, n, i0, i1; + unsigned char d = __CTYPE_unclassified; + + if ((ENCODING != __ctype_encoding_7_bit) || (((__uwchar_t) wc) <= 0x7f)){ + if (desc < _CTYPE_iswxdigit) { + if (((__uwchar_t) wc) <= WC_TABLE_DOMAIN_MAX) { + /* From here on, we know wc > 0. */ + sc = wc & WCctype_TI_MASK; + wc >>= WCctype_TI_SHIFT; + n = wc & WCctype_II_MASK; + wc >>= WCctype_II_SHIFT; + + i0 = WCctype[wc]; + i0 <<= WCctype_II_SHIFT; + i1 = WCctype[WCctype_II_LEN + i0 + n]; + i1 <<= (WCctype_TI_SHIFT-1); + d = WCctype[WCctype_II_LEN + WCctype_TI_LEN + i1 + (sc >> 1)]; + + d = (sc & 1) ? (d >> 4) : (d & 0xf); + } else if ( ((((__uwchar_t)(wc - 0xe0020UL)) <= 0x5f) + || (wc == 0xe0001UL)) + || ( (((__uwchar_t)(wc - 0xf0000UL)) < 0x20000UL) + && ((wc & 0xffffU) <= 0xfffdU)) + ) { + d = __CTYPE_punct; + } + + return ( ((unsigned char)(d - ctype_range[2*desc])) + <= ctype_range[2*desc + 1] ) + && ((desc != _CTYPE_iswblank) || (d & 1)); + } + + /* TODO - Add locale-specific classifications. */ + return (desc == _CTYPE_iswxdigit) ? __C_iswxdigit(wc) : 0; + } + return 0; +} + +#endif +/**********************************************************************/ +#ifdef L_towctrans + +#ifdef __WCTYPE_WITH_LOCALE + +#ifdef SMALL_UPLOW + +wint_t towctrans(wint_t wc, wctrans_t desc) +{ + unsigned int sc, n, i; + __uwchar_t u = wc; + + /* TODO - clean up */ + if (ENCODING == __ctype_encoding_7_bit) { + if ((((__uwchar_t) wc) > 0x7f) + || (((unsigned int)(desc - _CTYPE_tolower)) + > (_CTYPE_toupper - _CTYPE_tolower)) + ){ + /* We're in the C/POSIX locale, so ignore non-ASCII values + * as well an any mappings other than toupper or tolower. */ + return wc; + } + } + + if (((unsigned int)(desc - _CTYPE_tolower)) + <= (_CTYPE_totitle - _CTYPE_tolower) + ) { + if (u <= WC_TABLE_DOMAIN_MAX) { + sc = u & ((1 << WCuplow_TI_SHIFT) - 1); + u >>= WCuplow_TI_SHIFT; + n = u & ((1 << WCuplow_II_SHIFT) - 1); + u >>= WCuplow_II_SHIFT; + + i = ((unsigned int) WCuplow[u]) << WCuplow_II_SHIFT; + i = ((unsigned int) WCuplow[WCuplow_II_LEN + i + n]) + << WCuplow_TI_SHIFT; + i = ((unsigned int) WCuplow[WCuplow_II_LEN + WCuplow_TI_LEN + + i + sc]) << 1; + if (desc == _CTYPE_tolower) { + ++i; + } + wc += WCuplow_diff[i]; + if (desc == _CTYPE_totitle) { + /* 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)) + || (wc == 0x1f1) + ) { + ++wc; + } + } + } + } else { + /* TODO - Deal with other transliterations. */ + __set_errno(EINVAL); + } + + return wc; +} + +#else + +wint_t towctrans(wint_t wc, wctrans_t desc) +{ + if (ENCODING == __ctype_encoding_7_bit) { + if ((((__uwchar_t) wc) > 0x7f) + || (((unsigned int)(desc - _CTYPE_tolower)) + > (_CTYPE_toupper - _CTYPE_tolower)) + ){ + /* We're in the C/POSIX locale, so ignore non-ASCII values + * as well an any mappings other than toupper or tolower. */ + return wc; + } + } + + if (desc == _CTYPE_tolower) { + return towlower(wc); + } else if (((unsigned int)(desc - _CTYPE_toupper)) + <= (_CTYPE_totitle - _CTYPE_toupper) + ) { + wc = towupper(wc); + if (desc == _CTYPE_totitle) { + /* 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)) + || (wc == 0x1f1) + ) { + ++wc; + } + } + } else { + /* TODO - Deal with other transliterations. */ + __set_errno(EINVAL); + } + return wc; +} + +#endif + +#else + + +#endif + +#endif +/**********************************************************************/ +#ifdef L_wctrans + +static const char transstring[] = __CTYPE_TRANSTRING; + +wctrans_t wctrans(const char *property) +{ + const unsigned char *p; + int i; + + p = transstring; + i = 1; + do { + if (!strcmp(property, ++p)) { + return i; + } + ++i; + p += p[-1]; + } while (*p); + + /* TODO - Add locale-specific translations. */ + return 0; +} + +#endif +/**********************************************************************/ diff --git a/libc/stdlib/Makefile b/libc/stdlib/Makefile index 44a359434..64ae75d18 100644 --- a/libc/stdlib/Makefile +++ b/libc/stdlib/Makefile @@ -28,7 +28,8 @@ DIRS = $(MALLOC) ALL_SUBDIRS = malloc malloc-930716 malloc-simple MSRC = stdlib.c -MOBJ = abs.o labs.o atoi.o atol.o strtol.o strtoul.o _stdlib_strto_l.o +MOBJ = abs.o labs.o atoi.o atol.o strtol.o strtoul.o _stdlib_strto_l.o \ + qsort.o bsearch.o ifeq ($(HAS_LONG_LONG),true) MOBJ += llabs.o atoll.o strtoll.o strtoull.o _stdlib_strto_ll.o @@ -37,7 +38,7 @@ endif MSRC2=atexit.c MOBJ2=atexit.o on_exit.o __exit_handler.o exit.o -CSRC = abort.c getenv.c mktemp.c qsort.c realpath.c bsearch.c \ +CSRC = abort.c getenv.c mktemp.c realpath.c \ mkstemp.c mkstemp64.c putenv.c rand.c random.c random_r.c setenv.c \ system.c div.c ldiv.c getpt.c ptsname.c grantpt.c unlockpt.c gcvt.c CSRC+= drand48.c drand48-iter.c drand48_r.c erand48.c erand48_r.c \ diff --git a/libc/stdlib/stdlib.c b/libc/stdlib/stdlib.c index 40286f0e5..101debb40 100644 --- a/libc/stdlib/stdlib.c +++ b/libc/stdlib/stdlib.c @@ -27,30 +27,44 @@ #define _ISOC99_SOURCE /* for ULLONG primarily... */ #define _GNU_SOURCE -#include <stdlib.h> #include <limits.h> #include <stdint.h> #include <inttypes.h> #include <ctype.h> #include <errno.h> #include <assert.h> +#include <unistd.h> + +/* Work around gcc's refusal to create aliases. */ +#define atoi __ignore_atoi +#define abs __ignore_abs +#include <stdlib.h> +#undef atoi +#undef abs extern unsigned long _stdlib_strto_l(register const char * __restrict str, char ** __restrict endptr, int base, int sflag); + +#if defined(ULLONG_MAX) extern unsigned long long _stdlib_strto_ll(register const char * __restrict str, char ** __restrict endptr, int base, int sflag); +#endif -/* TODO: gcc reports an error due to prototype conflicts. Don't include - * the header for the problem cases? */ -#define HEADER_ALIAS_PROBLEM +/**********************************************************************/ +#ifdef L_atof +double atof(const char *nptr) +{ + return strtod(nptr, (char **) NULL); +} + +#endif /**********************************************************************/ #ifdef L_abs -#ifdef HEADER_ALIAS_PROBLEM -/* #if UINT_MAX < ULONG_MAX */ +#if UINT_MAX < ULONG_MAX int abs(int j) { @@ -63,8 +77,7 @@ int abs(int j) /**********************************************************************/ #ifdef L_labs -#ifndef HEADER_ALIAS_PROBLEM -/* #if UINT_MAX == ULONG_MAX */ +#if UINT_MAX == ULONG_MAX strong_alias(labs,abs) #endif @@ -102,8 +115,7 @@ long long int llabs(long long int j) /**********************************************************************/ #ifdef L_atoi -#ifdef HEADER_ALIAS_PROBLEM -/* #if UINT_MAX < ULONG_MAX */ +#if UINT_MAX < ULONG_MAX int atoi(const char *nptr) { @@ -116,8 +128,7 @@ int atoi(const char *nptr) /**********************************************************************/ #ifdef L_atol -#ifndef HEADER_ALIAS_PROBLEM -/* #if UINT_MAX == ULONG_MAX */ +#if UINT_MAX == ULONG_MAX strong_alias(atol,atoi) #endif @@ -446,3 +457,149 @@ unsigned long long _stdlib_strto_ll(register const char * __restrict str, #endif /**********************************************************************/ +/* Made _Exit() an alias for _exit(), as per C99. */ +/* #ifdef L__Exit */ + +/* void _Exit(int status) */ +/* { */ +/* _exit(status); */ +/* } */ + +/* #endif */ +/**********************************************************************/ +#ifdef L_bsearch + +void *bsearch(const void *key, const void *base, size_t /* nmemb */ high, + size_t size, int (*compar)(const void *, const void *)) +{ + register char *p; + size_t low; + size_t mid; + int r; + + if (size > 0) { /* TODO: change this to an assert?? */ + low = 0; + while (low < high) { + mid = low + ((high - low) >> 1); /* Avoid possible overflow here. */ + p = ((char *)base) + mid * size; /* Could overflow here... */ + r = (*compar)(key, p); /* but that's an application problem! */ + if (r > 0) { + low = mid + 1; + } else if (r < 0) { + high = mid; + } else { + return p; + } + } + } + return NULL; +} + +#endif +/**********************************************************************/ +#ifdef L_qsort + +/* This code is derived from a public domain shell sort routine by + * Ray Gardner and found in Bob Stout's snippets collection. The + * original code is included below in an #if 0/#endif block. + * + * I modified it to avoid the possibility of overflow in the wgap + * calculation, as well as to reduce the generated code size with + * bcc and gcc. */ + +void qsort (void *base, + size_t nel, + size_t width, + int (*comp)(const void *, const void *)) +{ + size_t wgap, i, j, k; + char tmp; + + if ((nel > 1) && (width > 0)) { + assert( nel <= ((size_t)(-1)) / width ); /* check for overflow */ + wgap = 0; + do { + wgap = 3 * wgap + 1; + } while (wgap < (nel-1)/3); + /* From the above, we know that either wgap == 1 < nel or */ + /* ((wgap-1)/3 < (int) ((nel-1)/3) <= (nel-1)/3 ==> wgap < nel. */ + wgap *= width; /* So this can not overflow if wnel doesn't. */ + nel *= width; /* Convert nel to 'wnel' */ + do { + i = wgap; + do { + j = i; + do { + register char *a; + register char *b; + + j -= wgap; + a = j + ((char *)base); + b = a + wgap; + if ( (*comp)(a, b) <= 0 ) { + break; + } + k = width; + do { + tmp = *a; + *a++ = *b; + *b++ = tmp; + } while ( --k ); + } while (j >= wgap); + i += width; + } while (i < nel); + wgap = (wgap - width)/3; + } while (wgap); + } +} + +/* ---------- original snippets version below ---------- */ + +#if 0 +/* +** ssort() -- Fast, small, qsort()-compatible Shell sort +** +** by Ray Gardner, public domain 5/90 +*/ + +#include <stddef.h> + +void ssort (void *base, + size_t nel, + size_t width, + int (*comp)(const void *, const void *)) +{ + size_t wnel, gap, wgap, i, j, k; + char *a, *b, tmp; + + wnel = width * nel; + for (gap = 0; ++gap < nel;) + gap *= 3; + while ( gap /= 3 ) + { + wgap = width * gap; + for (i = wgap; i < wnel; i += width) + { + for (j = i - wgap; ;j -= wgap) + { + a = j + (char *)base; + b = a + wgap; + if ( (*comp)(a, b) <= 0 ) + break; + k = width; + do + { + tmp = *a; + *a++ = *b; + *b++ = tmp; + } while ( --k ); + if (j < wgap) + break; + } + } + } +} +#endif + +#endif +/**********************************************************************/ diff --git a/libc/string/Makefile b/libc/string/Makefile index c7a4c128a..0d034d1d6 100644 --- a/libc/string/Makefile +++ b/libc/string/Makefile @@ -24,27 +24,48 @@ TOPDIR=../../ include $(TOPDIR)Rules.mak +MSRCW= wstring.c +MOBJW= basename.o bcopy.o bzero.o dirname.o ffs.o memccpy.o memchr.o memcmp.o \ + memcpy.o memmove.o mempcpy.o memrchr.o memset.o rawmemchr.o stpcpy.o \ + stpncpy.o strcasecmp.o strcasestr.o strcat.o strchrnul.o strchr.o \ + strcmp.o strcpy.o strcspn.o strdup.o strlen.o strncasecmp.o strncat.o \ + strncmp.o strncpy.o strndup.o strnlen.o strpbrk.o strrchr.o strsep.o \ + strspn.o strstr.o strtok.o strtok_r.o \ + __xpg_basename.o # strcoll.o strerror.o strxfrm.o + +MOBJW2= wcscasecmp.o wcscat.o wcschrnul.o wcschr.o wcscmp.o wcscpy.o wcscspn.o \ + wcsdup.o wcslen.o wcsncasecmp.o wcsncat.o wcsncmp.o wcsncpy.o \ + wcsnlen.o wcspbrk.o wcsrchr.o wcsspn.o wcsstr.o wcstok.o wmemchr.o \ + wmemcmp.o wmemcpy.o wmemmove.o wmempcpy.o wmemset.o + MSRC=string.c -MOBJ=strlen.o strcat.o strcpy.o strchr.o strcmp.o strncat.o strncpy.o \ - strncmp.o strrchr.o strdup.o strndup.o memcpy.o memccpy.o memset.o \ - memmove.o memcmp.o memchr.o ffs.o strnlen.o strxfrm.o stpcpy.o \ - stpncpy.o memrchr.o mempcpy.o +# MOBJ=strlen.o strcat.o strcpy.o strchr.o strcmp.o strncat.o strncpy.o \ +# strncmp.o strrchr.o strdup.o strndup.o memcpy.o memccpy.o memset.o \ +# memmove.o memcmp.o memchr.o ffs.o strnlen.o strxfrm.o stpcpy.o \ +# stpncpy.o memrchr.o mempcpy.o +MOBJ=strxfrm.o -ifeq ($(HAS_LOCALE),true) - MOBJ += strcoll.o -endif +# ifeq ($(HAS_LOCALE),true) +# MOBJ += strcoll.o +# endif MSRC1=strsignal.c MOBJ1=strsignal.o psignal.o -MSRC2=strstr.c -MOBJ2=strstr.o strcasestr.o +MOBJ2= +#MSRC2=strstr.c +#MOBJ2=strstr.o strcasestr.o -CSRC=strpbrk.c strsep.c strtok.c strtok_r.c strcspn.c \ - strspn.c strcasecmp.c strncasecmp.c strerror.c bcopy.c bzero.c \ - bcmp.c sys_errlist.c dirname.c basename.c +# CSRC=strpbrk.c strsep.c strtok.c strtok_r.c strcspn.c \ +# strspn.c strcasecmp.c strncasecmp.c strerror.c bcopy.c bzero.c \ +# bcmp.c sys_errlist.c dirname.c basename.c +CSRC=strerror.c sys_errlist.c COBJS=$(patsubst %.c,%.o, $(CSRC)) -OBJS=$(MOBJ) $(MOBJ1) $(MOBJ2) $(COBJS) +OBJS=$(MOBJ) $(MOBJ1) $(MOBJ2) $(COBJS) $(MOBJW) + +ifeq ($(HAS_WCHAR),true) + OBJS += $(MOBJW2) +endif all: $(OBJS) $(LIBC) @@ -53,6 +74,14 @@ $(LIBC): ar-target ar-target: $(OBJS) $(AR) $(ARFLAGS) $(LIBC) $(OBJS) +$(MOBJW): $(MSRCW) + $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o + $(STRIPTOOL) -x -R .note -R .comment $*.o + +$(MOBJW2): $(MSRCW) + $(CC) $(CFLAGS) -DWANT_WIDE -DL_$* $< -c -o $*.o + $(STRIPTOOL) -x -R .note -R .comment $*.o + $(MOBJ): $(MSRC) $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o $(STRIPTOOL) -x -R .note -R .comment $*.o diff --git a/libc/string/wstring.c b/libc/string/wstring.c new file mode 100644 index 000000000..53c5af99c --- /dev/null +++ b/libc/string/wstring.c @@ -0,0 +1,1273 @@ +/* Copyright (C) 2002 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. + */ + +/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! + * + * Besides uClibc, I'm using this code in my libc for elks, which is + * a 16-bit environment with a fairly limited compiler. It would make + * things much easier for me if this file isn't modified unnecessarily. + * In particular, please put any new or replacement functions somewhere + * else, and modify the makefile to use your version instead. + * Thanks. Manuel + * + * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */ + +#define _GNU_SOURCE +#include <string.h> +#include <strings.h> +#include <limits.h> +#include <ctype.h> +#include <stdlib.h> + +#ifdef WANT_WIDE +#include <wchar.h> +#include <wctype.h> +#include <locale.h> + +#define Wvoid wchar_t +#define Wchar wchar_t +#define Wuchar __uwchar_t +#define Wint wchar_t + +#else + +#define Wvoid void +#define Wchar char +typedef unsigned char __string_uchar_t; +#define Wuchar __string_uchar_t +#define Wint int + +#endif + +/**********************************************************************/ +#ifdef L_wmemcpy +#define L_memcpy +#define Wmemcpy wmemcpy +#else +#define Wmemcpy memcpy +#endif + +#ifdef L_memcpy + +Wvoid *Wmemcpy(Wvoid * __restrict s1, const Wvoid * __restrict s2, size_t n) +{ + register Wchar *r1 = s1; + register const Wchar *r2 = s2; + +#ifdef __BCC__ + while (n--) { + *r1++ = *r2++; + } +#else + while (n) { + *r1++ = *r2++; + --n; + } +#endif + + return s1; +} + +#endif +/**********************************************************************/ +#ifdef L_wmemmove +#define L_memmove +#define Wmemmove wmemmove +#else +#define Wmemmove memmove +#endif + +#ifdef L_memmove + +Wvoid *Wmemmove(Wvoid *s1, const Wvoid *s2, size_t n) +{ +#ifdef __BCC__ + register Wchar *s = (Wchar *) s1; + register const Wchar *p = (const Wchar *) s2; + + if (p >= s) { + while (n--) { + *s++ = *p++; + } + } else { + s += n; + p += n; + while (n--) { + *--s = *--p; + } + } + + return s1; +#else + register Wchar *s = (Wchar *) s1; + register const Wchar *p = (const Wchar *) s2; + + if (p >= s) { + while (n) { + *s++ = *p++; + --n; + } + } else { + while (n) { + --n; + s[n] = p[n]; + } + } + + return s1; +#endif +} + +#endif +/**********************************************************************/ +#ifdef L_wcscpy +#define L_strcpy +#define Wstrcpy wcscpy +#else +#define Wstrcpy strcpy +#endif + +#ifdef L_strcpy + +Wchar *Wstrcpy(Wchar * __restrict s1, const Wchar * __restrict s2) +{ + register Wchar *s = s1; + +#ifdef __BCC__ + do { + *s = *s2++; + } while (*s++ != 0); +#else + while ( (*s++ = *s2++) != 0 ); +#endif + + return s1; +} + +#endif +/**********************************************************************/ +#ifdef L_wcsncpy +#define L_strncpy +#define Wstrncpy wcsncpy +#else +#define Wstrncpy strncpy +#endif + +#ifdef L_strncpy + +Wchar *Wstrncpy(Wchar * __restrict s1, register const Wchar * __restrict s2, + size_t n) +{ + register Wchar *s = s1; + +#ifdef __BCC__ + while (n--) { + if ((*s = *s2) != 0) s2++; /* Need to fill tail with 0s. */ + ++s; + } +#else + while (n) { + if ((*s = *s2) != 0) s2++; /* Need to fill tail with 0s. */ + ++s; + --n; + } +#endif + + return s1; +} + +#endif +/**********************************************************************/ +#ifdef L_wcscat +#define L_strcat +#define Wstrcat wcscat +#else +#define Wstrcat strcat +#endif + +#ifdef L_strcat + +Wchar *Wstrcat(Wchar * __restrict s1, register const Wchar * __restrict s2) +{ + register Wchar *s = s1; + + while (*s++); + --s; + while ((*s++ = *s2++) != 0); + + return s1; +} + +#endif +/**********************************************************************/ +#ifdef L_wcsncat +#define L_strncat +#define Wstrncat wcsncat +#else +#define Wstrncat strncat +#endif + +#ifdef L_strncat + +Wchar *Wstrncat(Wchar * __restrict s1, register const Wchar * __restrict s2, + size_t n) +{ + register Wchar *s = s1; + + while (*s++); + --s; +#if __BCC__ + while (n-- && ((*s = *s2++) != 0)) ++s; +#else + while (n && ((*s = *s2++) != 0)) { + --n; + ++s; + } +#endif + *s = 0; + + return s1; +} + +#endif +/**********************************************************************/ +#ifdef L_wmemcmp +#define L_memcmp +#define Wmemcmp wmemcmp +#else +#define Wmemcmp memcmp +#endif + +#ifdef L_memcmp + +#ifndef L_wmemcmp +weak_alias(memcmp,bcmp) +#endif + +int Wmemcmp(const Wvoid *s1, const Wvoid *s2, size_t n) +{ + register const Wuchar *r1 = (const Wuchar *) s1; + register const Wuchar *r2 = (const Wuchar *) s2; + +#ifdef WANT_WIDE + while (n && (*r1 == *r2)) { + ++r1; + ++r2; + --n; + } + + return (n == 0) ? 0 : ((*r1 < *r2) ? -1 : 1); +#else + int r = 0; + + while (n-- && ((r = ((int)(*r1++)) - *r2++) == 0)); + + return r; +#endif +} + +#endif +/**********************************************************************/ +#ifdef L_wcscmp +#define L_strcmp +#define Wstrcmp wcscmp +#else +#define Wstrcmp strcmp +#endif + +#ifdef L_strcmp + +#ifndef L_wcscmp +#warning implement strcoll and remove weak alias (or enable for C locale only) +weak_alias(strcmp, strcoll); +#endif + +int Wstrcmp(register const Wchar *s1, register const Wchar *s2) +{ +#ifdef WANT_WIDE + while (*((Wuchar *)s1) == *((Wuchar *)s2)) { + if (!*s1++) { + return 0; + } + ++s2; + } + + return (*((Wuchar *)s1) < *((Wuchar *)s2)) ? -1 : 1; +#else + int r; + + while (((r = ((int)(*((Wuchar *)s1))) - *((Wuchar *)s2++)) + == 0) && *s1++); + + return r; +#endif +} +#endif +/**********************************************************************/ +#ifdef L_strcoll +#error implement strcoll and remove weak_alias!! +/* extern unsigned char *_ctype_collate; */ + +/* int strcoll(register const char *s1, const char *s2) */ +/* { */ +/* int r; */ + +/* while (!(r = (_ctype_collate[(int)(*s1++)]-_ctype_collate[(int)(*s2++)]))); */ + +/* return r; */ +/* } */ +#endif +/**********************************************************************/ +#ifdef L_wcsncmp +#define L_strncmp +#define Wstrncmp wcsncmp +#else +#define Wstrncmp strncmp +#endif + +#ifdef L_strncmp + +int Wstrncmp(register const Wchar *s1, register const Wchar *s2, size_t n) +{ +#ifdef WANT_WIDE + while (n && (*((Wuchar *)s1) == *((Wuchar *)s2))) { + if (!*s1++) { + return 0; + } + ++s2; + --n; + } + + return (n == 0) ? 0 : ((*((Wuchar *)s1) < *((Wuchar *)s2)) ? -1 : 1); +#else + int r = 0; + + while (n-- + && ((r = ((int)(*((unsigned char *)s1))) - *((unsigned char *)s2++)) + == 0) + && *s1++); + + return r; +#endif +} + +#endif +/**********************************************************************/ +#ifdef L_strxfrm +#error implement strxfrm +/* size_t strxfrm(char * __restrict s1, const char * __restrict s2, size_t n) */ +#endif +/**********************************************************************/ +#ifdef L_wmemchr +#define L_memchr +#define Wmemchr wmemchr +#else +#define Wmemchr memchr +#endif + +#ifdef L_memchr + +Wvoid *Wmemchr(const Wvoid *s, Wint c, size_t n) +{ + register const Wuchar *r = (const Wuchar *) s; +#ifdef __BCC__ + /* bcc can optimize the counter if it thinks it is a pointer... */ + register const char *np = (const char *) n; +#else +#define np n +#endif + + while (np) { + if (*r == ((Wuchar)c)) { + return (Wvoid *) r; /* silence the warning */ + } + ++r; + --np; + } + + return NULL; +} +#undef np + +#endif +/**********************************************************************/ +#ifdef L_wcschr +#define L_strchr +#define Wstrchr wcschr +#else +#define Wstrchr strchr +#endif + +#ifdef L_strchr + +#ifndef L_wcschr +weak_alias(strchr,index) +#endif + +Wchar *Wstrchr(register const Wchar *s, Wint c) +{ + do { + if (*s == ((Wchar)c)) { + return (Wchar *) s; /* silence the warning */ + } + } while (*s++); + + return NULL; +} + +#endif +/**********************************************************************/ +#ifdef L_wcscspn +#define L_strcspn +#define Wstrcspn wcscspn +#else +#define Wstrcspn strcspn +#endif + +#ifdef L_strcspn + +size_t Wstrcspn(const Wchar *s1, const Wchar *s2) +{ + register const Wchar *s; + register const Wchar *p; + + for ( s=s1 ; *s ; s++ ) { + for ( p=s2 ; *p ; p++ ) { + if (*p == *s) goto done; + } + } + done: + return s - s1; +} + +#endif +/**********************************************************************/ +#ifdef L_wcspbrk +#define L_strpbrk +#define Wstrpbrk wcspbrk +#else +#define Wstrpbrk strpbrk +#endif + +#ifdef L_strpbrk + +Wchar *Wstrpbrk(const Wchar *s1, const Wchar *s2) +{ + register const Wchar *s; + register const Wchar *p; + + for ( s=s1 ; *s ; s++ ) { + for ( p=s2 ; *p ; p++ ) { + if (*p == *s) return (Wchar *) s; /* silence the warning */ + } + } + return NULL; +} +#endif +/**********************************************************************/ +#ifdef L_wcsrchr +#define L_strrchr +#define Wstrrchr wcsrchr +#else +#define Wstrrchr strrchr +#endif + +#ifdef L_strrchr + +#ifndef L_wcsrchr +weak_alias(strrchr,rindex) +#endif + +Wchar *Wstrrchr(register const Wchar *s, Wint c) +{ + register const Wchar *p; + + p = NULL; + do { + if (*s == (Wchar) c) { + p = s; + } + } while (*s++); + + return (Wchar *) p; /* silence the warning */ +} + +#endif +/**********************************************************************/ +#ifdef L_wcsspn +#define L_strspn +#define Wstrspn wcsspn +#else +#define Wstrspn strspn +#endif + +#ifdef L_strspn + +size_t Wstrspn(const Wchar *s1, const Wchar *s2) +{ + register const Wchar *s = s1; + register const Wchar *p = s2; + + while (*p) { + if (*p++ == *s) { + ++s; + p = s2; + } + } + return s - s1; +} + +#endif +/**********************************************************************/ +#ifdef L_wcsstr +#define L_strstr +#define Wstrstr wcsstr +#else +#define Wstrstr strstr +#endif + +#ifdef L_strstr + +/* NOTE: This is the simple-minded O(len(s1) * len(s2)) worst-case approach. */ + +#ifdef L_wcsstr +weak_alias(wcsstr,wcswcs) +#endif + +Wchar *Wstrstr(const Wchar *s1, const Wchar *s2) +{ + register const Wchar *s = s1; + register const Wchar *p = s2; + + do { + if (!*p) { + return (Wchar *) s1;; + } + if (*p == *s) { + ++p; + ++s; + } else { + p = s2; + if (!*s) { + return NULL; + } + s = ++s1; + } + } while (1); +} + +#endif +/**********************************************************************/ +#ifdef L_wcstok +#define L_strtok_r +#define Wstrtok_r wcstok +#define Wstrspn wcsspn +#define Wstrpbrk wcspbrk +#else +#define Wstrtok_r strtok_r +#define Wstrspn strspn +#define Wstrpbrk strpbrk +#endif + +#ifdef L_strtok_r + +Wchar *Wstrtok_r(Wchar * __restrict s1, const Wchar * __restrict s2, + Wchar ** __restrict next_start) +{ + register Wchar *s; + register Wchar *p; + +#if 1 + if (((s = s1) != NULL) || ((s = *next_start) != NULL)) { + if (*(s += Wstrspn(s, s2))) { + if ((p = Wstrpbrk(s, s2)) != NULL) { + *p++ = 0; + } + } else { + p = s = NULL; + } + *next_start = p; + } + return s; +#else + if (!(s = s1)) { + s = *next_start; + } + if (s && *(s += Wstrspn(s, s2))) { + if (*(p = s + Wstrcspn(s, s2))) { + *p++ = 0; + } + *next_start = p; + return s; + } + return NULL; /* TODO: set *next_start = NULL for safety? */ +#endif +} + +#endif +/**********************************************************************/ +/* #ifdef L_wcstok */ +/* #define L_strtok */ +/* #define Wstrtok wcstok */ +/* #define Wstrtok_r wcstok_r */ +/* #else */ +/* #define Wstrtok strtok */ +/* #define Wstrtok_r strtok_r */ +/* #endif */ + +#ifdef L_strtok +#define Wstrtok strtok +#define Wstrtok_r strtok_r + +Wchar *Wstrtok(Wchar * __restrict s1, const Wchar * __restrict s2) +{ + static Wchar *next_start; /* Initialized to 0 since in bss. */ + return Wstrtok_r(s1, s2, &next_start); +} + +#endif +/**********************************************************************/ +#ifdef L_wmemset +#define L_memset +#define Wmemset wmemset +#else +#define Wmemset memset +#endif + +#ifdef L_memset + +Wvoid *Wmemset(Wvoid *s, Wint c, size_t n) +{ + register Wuchar *p = (Wuchar *) s; +#ifdef __BCC__ + /* bcc can optimize the counter if it thinks it is a pointer... */ + register const char *np = (const char *) n; +#else +#define np n +#endif + + while (np) { + *p++ = (Wuchar) c; + --np; + } + + return s; +} +#undef np + +#endif +/**********************************************************************/ +#ifdef L_strerror +#error implement strerror +/* char *strerror(int errnum); */ +#endif +/**********************************************************************/ +#ifdef L_wcslen +#define L_strlen +#define Wstrlen wcslen +#else +#define Wstrlen strlen +#endif + +#ifdef L_strlen + +size_t Wstrlen(const Wchar *s) +{ + register const Wchar *p; + + for (p=s ; *p ; p++); + + return p - s; +} + +#endif +/**********************************************************************/ +/* ANSI/ISO end here */ +/**********************************************************************/ +#ifdef L_ffs + +int ffs(int i) +{ +#if 1 + /* inlined binary search method */ + char n = 1; +#if UINT_MAX == 0xffffU + /* nothing to do here -- just trying to avoiding possible problems */ +#elif UINT_MAX == 0xffffffffU + if (!(i & 0xffff)) { + n += 16; + i >>= 16; + } +#else +#error ffs needs rewriting! +#endif + + if (!(i & 0xff)) { + n += 8; + i >>= 8; + } + if (!(i & 0x0f)) { + n += 4; + i >>= 4; + } + if (!(i & 0x03)) { + n += 2; + i >>= 2; + } + return (i) ? (n + ((i+1) & 0x01)) : 0; + +#else + /* linear search -- slow, but small */ + int n; + + for (n = 0 ; i ; ++n) { + i >>= 1; + } + + return n; +#endif +} + +#endif +/**********************************************************************/ +#ifdef L_wcscasecmp +#define L_strcasecmp +#define Wstrcasecmp wcscasecmp +#else +#define Wstrcasecmp strcasecmp +#endif + +#ifdef L_strcasecmp + +int Wstrcasecmp(register const Wchar *s1, register const Wchar *s2) +{ +#ifdef WANT_WIDE + while ((*s1 == *s2) || (towlower(*s1) == towlower(*s2))) { + if (!*s1++) { + return 0; + } + ++s2; + } + + return (((Wuchar)towlower(*s1)) < ((Wuchar)towlower(*s2))) ? -1 : 1; + /* TODO -- should wide cmp funcs do wchar or Wuchar compares? */ +#else + int r = 0; + + while ( ((s1 == s2) || + !(r = ((int)( tolower(*((Wuchar *)s1)))) + - tolower(*((Wuchar *)s2)))) + && (++s2, *s1++)); + + return r; +#endif +} + +#endif +/**********************************************************************/ +#ifdef L_wcsncasecmp +#define L_strncasecmp +#define Wstrncasecmp wcsncasecmp +#else +#define Wstrncasecmp strncasecmp +#endif + +#ifdef L_strncasecmp + +int Wstrncasecmp(register const Wchar *s1, register const Wchar *s2, size_t n) +{ +#ifdef WANT_WIDE + while (n && ((*s1 == *s2) || (towlower(*s1) == towlower(*s2)))) { + if (!*s1++) { + return 0; + } + ++s2; + --n; + } + + return (n == 0) + ? 0 + : ((((Wuchar)towlower(*s1)) < ((Wuchar)towlower(*s2))) ? -1 : 1); + /* TODO -- should wide cmp funcs do wchar or Wuchar compares? */ +#else + int r = 0; + + while ( n + && ((s1 == s2) || + !(r = ((int)( tolower(*((unsigned char *)s1)))) + - tolower(*((unsigned char *)s2)))) + && (--n, ++s2, *s1++)); + return r; +#endif +} +#endif +/**********************************************************************/ +#ifdef L_wcsnlen +#define L_strnlen +#define Wstrnlen wcsnlen +#else +#define Wstrnlen strnlen +#endif + +#ifdef L_strnlen + +size_t Wstrnlen(const Wchar *s, size_t max) +{ + register const Wchar *p = s; +#ifdef __BCC__ + /* bcc can optimize the counter if it thinks it is a pointer... */ + register const char *maxp = (const char *) max; +#else +#define maxp max +#endif + + while (maxp && *p) { + ++p; + --maxp; + } + + return p - s; +} +#undef maxp +#endif +/**********************************************************************/ +/* No wide analog. */ + +#ifdef L_memccpy + +void *memccpy(void * __restrict s1, const void * __restrict s2, int c, size_t n) +{ + register char *r1 = s1; + register const char *r2 = s2; + + while (n-- && (((unsigned char)(*r1++ = *r2++)) != ((unsigned char) c))); + + return (n == (size_t) -1) ? NULL : r1; +} + +#endif +/**********************************************************************/ +#ifdef L_wcsdup +#define L_strdup +#define Wstrdup wcsdup +#define Wstrlen wcslen +#define Wstrcpy wcscpy +#else +#define Wstrdup strdup +#define Wstrlen strlen +#define Wstrcpy strcpy +#endif + +#ifdef L_strdup + +Wchar *Wstrdup(register const Wchar *s1) +{ + register Wchar *s; + + if ((s = malloc((Wstrlen(s1) + 1) * sizeof(Wchar))) != NULL) { + Wstrcpy(s, s1); + } + + return s; +} + +#endif +/**********************************************************************/ +/* GNU extension functions. */ +/**********************************************************************/ +#ifdef L_wmempcpy +#define L_mempcpy +#define Wmempcpy wmempcpy +#else +#define Wmempcpy mempcpy +#endif + +#ifdef L_mempcpy + +#ifndef L_wmempcpy +/* uClibc's old string implementation did this to cater to some app. */ +weak_alias(mempcpy,__mempcpy) +#endif + +Wvoid *Wmempcpy(Wvoid * __restrict s1, const Wvoid * __restrict s2, size_t n) +{ + register Wchar *r1 = s1; + register const Wchar *r2 = s2; + +#ifdef __BCC__ + while (n--) { + *r1++ = *r2++; + } +#else + while (n) { + *r1++ = *r2++; + --n; + } +#endif + + return r1; +} + +#endif +/**********************************************************************/ +#ifdef L_memrchr + +void *memrchr(const void *s, int c, size_t n) +{ + register const unsigned char *r; +#ifdef __BCC__ + /* bcc can optimize the counter if it thinks it is a pointer... */ + register const char *np = (const char *) n; +#else +#define np n +#endif + + r = ((unsigned char *)s) + ((size_t) np); + + while (np) { + if (*--r == ((unsigned char)c)) { + return (void *) r; /* silence the warning */ + } + --np; + } + + return NULL; +} +#undef np + +#endif +/**********************************************************************/ +#ifdef L_stpcpy + +char *stpcpy(register char * __restrict s1, const char * __restrict s2) +{ +#ifdef __BCC__ + do { + *s1 = *s2++; + } while (*s1++ != 0); +#else + while ( (*s1++ = *s2++) != 0 ); +#endif + + return s1 - 1; +} + +#endif +/**********************************************************************/ +#ifdef L_stpncpy + +char *stpncpy(register char * __restrict s1, + register const char * __restrict s2, + size_t n) +{ + char *s = s1; + const char *p = s2; + +#ifdef __BCC__ + while (n--) { + if ((*s = *s2) != 0) s2++; /* Need to fill tail with 0s. */ + ++s; + } + return s1 + (s2 - p); +#else + while (n) { + if ((*s = *s2) != 0) s2++; /* Need to fill tail with 0s. */ + ++s; + --n; + } + return s1 + (s2 - p); +#endif +} + +#endif +/**********************************************************************/ +#ifdef L_bzero + +void bzero(void *s, size_t n) +{ + register unsigned char *p = s; +#ifdef __BCC__ + /* bcc can optimize the counter if it thinks it is a pointer... */ + register const char *np = (const char *) n; +#else +#define np n +#endif + + while (np) { + *p++ = 0; + --np; + } +} +#undef np + +#endif +/**********************************************************************/ +#ifdef L_bcopy + +void bcopy(const void *s2, void *s1, size_t n) +{ +#if 1 + memmove(s1, s2, n); +#else +#ifdef __BCC__ + register char *s; + register const char *p; + + s = s1; + p = s2; + if (p >= s) { + while (n--) { + *s++ = *p++; + } + } else { + s += n; + p += n; + while (n--) { + *--s = *--p; + } + } +#else + register char *s; + register const char *p; + + s = s1; + p = s2; + if (p >= s) { + while (n) { + *s++ = *p++; + --n; + } + } else { + while (n) { + --n; + s[n] = p[n]; + } + } +#endif +#endif +} + +#endif +/**********************************************************************/ +#ifdef L_strcasestr + +char *strcasestr(const char *s1, const char *s2) +{ + register const char *s = s1; + register const char *p = s2; + +#if 1 + do { + if (!*p) { + return (char *) s1;; + } + if ((*p == *s) + || (tolower(*((unsigned char *)p)) == tolower(*((unsigned char *)s))) + ) { + ++p; + ++s; + } else { + p = s2; + if (!*s) { + return NULL; + } + s = ++s1; + } + } while (1); +#else + while (*p && *s) { + if ((*p == *s) + || (tolower(*((unsigned char *)p)) == tolower(*((unsigned char *)s))) + ) { + ++p; + ++s; + } else { + p = s2; + s = ++s1; + } + } + + return (*p) ? NULL : (char *) s1; +#endif +} + +#endif +/**********************************************************************/ +#ifdef L_strndup + +char *strndup(register const char *s1, size_t n) +{ + register char *s; + + n = strnlen(s1,n); /* Avoid problems if s1 not nul-terminated. */ + + if ((s = malloc(n + 1)) != NULL) { + memcpy(s, s1, n); + s[n] = 0; + } + + return s; +} + +#endif +/**********************************************************************/ +#ifdef L_strsep + +char *strsep(char ** __restrict s1, const char * __restrict s2) +{ + register char *s = *s1; + register char *p; + +#if 1 + p = NULL; + if (s && *s && (p = strpbrk(s, s2))) { + *p++ = 0; + } +#else + if (s && *s && *(p = s + strcspn(s, s2))) { + *p++ = 0; + } else { + p = NULL; + } +#endif + *s1 = p; + return s; +} + +#endif +/**********************************************************************/ +#ifdef L_wcschrnul +#define L_strchrnul +#define Wstrchrnul wcschrnul +#else +#define Wstrchrnul strchrnul +#endif + +#ifdef L_strchrnul + +Wchar *Wstrchrnul(register const Wchar *s, Wint c) +{ + --s; + while (*++s && (*s != ((Wchar)c))); + return (Wchar *) s; +} + +#endif +/**********************************************************************/ +#ifdef L_rawmemchr + +void *rawmemchr(const void *s, int c) +{ + register const unsigned char *r = s; + + while (*r != ((unsigned char)c)) ++r; + + return (void *) r; /* silence the warning */ +} + +#endif +/**********************************************************************/ +#ifdef L_basename + +char *basename(const char *path) +{ + register const char *s; + register const char *p; + + p = s = path; + + while (*s) { + if (*s++ == '/') { + p = s; + } + } + + return (char *) p; +} + +#endif +/**********************************************************************/ +#ifdef L___xpg_basename + +char *__xpg_basename(register char *path) +{ + static const char null_or_empty[] = "."; + char *first; + register char *last; + + first = (char *) null_or_empty; + + if (path && *path) { + first = path; + last = path - 1; + + do { + if ((*path != '/') && (path > ++last)) { + last = first = path; + } + } while (*++path); + + if (*first == '/') { + last = first; + } + last[1] = 0; + } + + return first; +} + +#endif +/**********************************************************************/ +#ifdef L_dirname + +char *dirname(char *path) +{ + static const char null_or_empty_or_noslash[] = "."; + register char *s; + register char *last; + char *first; + + last = s = path; + + if (s != NULL) { + + LOOP: + while (*s && (*s != '/')) ++s; + first = s; + while (*s == '/') ++s; + if (*s) { + last = first; + goto LOOP; + } + + if (last == path) { + if (*last != '/') { + goto DOT; + } + if ((*++last == '/') && (last[1] == 0)) { + ++last; + } + } + *last = 0; + return path; + } + DOT: + return (char *) null_or_empty_or_noslash; +} + +#endif +/**********************************************************************/ diff --git a/libc/sysdeps/linux/common/bits/.cvsignore b/libc/sysdeps/linux/common/bits/.cvsignore new file mode 100644 index 000000000..02b6bca59 --- /dev/null +++ b/libc/sysdeps/linux/common/bits/.cvsignore @@ -0,0 +1 @@ +uClibc_locale_data.h diff --git a/libc/sysdeps/linux/common/bits/uClibc_ctype.h b/libc/sysdeps/linux/common/bits/uClibc_ctype.h new file mode 100644 index 000000000..875070452 --- /dev/null +++ b/libc/sysdeps/linux/common/bits/uClibc_ctype.h @@ -0,0 +1,250 @@ +/* Copyright (C) 2002 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. + */ + +/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! + * + * Besides uClibc, I'm using this code in my libc for elks, which is + * a 16-bit environment with a fairly limited compiler. It would make + * things much easier for me if this file isn't modified unnecessarily. + * In particular, please put any new or replacement functions somewhere + * else, and modify the makefile to use your version instead. + * Thanks. Manuel + * + * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */ + +#if !defined(_CTYPE_H) && !defined(_WCTYPE_H) +#error Always include <{w}ctype.h> rather than <bits/uClibc_ctype.h> +#endif + +#ifndef _BITS_CTYPE_H +#define _BITS_CTYPE_H + +/* 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, +}; + +/* Some macros that test for various (w)ctype classes when passed one of the + * designator values enumerated above. */ +#define __CTYPE_isalnum(D) ((unsigned int)(D-1) <= (__CTYPE_digit-1)) +#define __CTYPE_isalpha(D) ((unsigned int)(D-1) <= (__CTYPE_alpha_upper-1)) +#define __CTYPE_isblank(D) \ + ((((unsigned int)(D - __CTYPE_print_space_nonblank)) <= 5) && (D & 1)) +#define __CTYPE_iscntrl(D) (((unsigned int)(D - __CTYPE_cntrl_space_nonblank)) <= 2) +#define __CTYPE_isdigit(D) (D == __CTYPE_digit) +#define __CTYPE_isgraph(D) ((unsigned int)(D-1) <= (__CTYPE_graph-1)) +#define __CTYPE_islower(D) (((unsigned int)(D - __CTYPE_alpha_lower)) <= 1) +#define __CTYPE_isprint(D) ((unsigned int)(D-1) <= (__CTYPE_print_space_blank-1)) +#define __CTYPE_ispunct(D) (D == __CTYPE_punct) +#define __CTYPE_isspace(D) (((unsigned int)(D - __CTYPE_print_space_nonblank)) <= 5) +#define __CTYPE_isupper(D) (((unsigned int)(D - __CTYPE_alpha_upper_lower)) <= 1) +/* #define __CTYPE_isxdigit(D) -- isxdigit is untestable this way. + * But that's ok as isxdigit() (and isdigit() too) are locale-invariant. */ + +/* 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 wctype(), but it is defined + * here because the ordering must agree with that of the enumeration + * above (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" + +/* Used in implementing iswctype(), but defined here as it must agree + * in ordering with the string above. */ +#define __CTYPE_RANGES \ + 0, -1, /* unclassified */ \ + 1, __CTYPE_digit - 1, /* alnum */ \ + 1, __CTYPE_alpha_upper - 1, /* alpha */ \ + __CTYPE_print_space_blank, 5, /* blank -- also must be odd! */ \ + __CTYPE_cntrl_space_nonblank, 2, /* cntrl */ \ + __CTYPE_digit, 0, /* digit */ \ + 1, __CTYPE_graph - 1, /* graph */ \ + __CTYPE_alpha_lower, 1, /* lower */ \ + 1, __CTYPE_print_space_blank - 1, /* print */ \ + __CTYPE_punct, 0, /* punct */ \ + __CTYPE_print_space_nonblank, 5, /* space */ \ + __CTYPE_alpha_upper_lower, 1, /* upper */ \ + /* No entry for xdigit as it is handled specially. */ + +#define _CTYPE_iswalnum _CTYPE_isalnum +#define _CTYPE_iswalpha _CTYPE_isalpha +#define _CTYPE_iswblank _CTYPE_isblank +#define _CTYPE_iswcntrl _CTYPE_iscntrl +#define _CTYPE_iswdigit _CTYPE_isdigit +#define _CTYPE_iswgraph _CTYPE_isgraph +#define _CTYPE_iswlower _CTYPE_islower +#define _CTYPE_iswprint _CTYPE_isprint +#define _CTYPE_iswpunct _CTYPE_ispunct +#define _CTYPE_iswspace _CTYPE_isspace +#define _CTYPE_iswupper _CTYPE_isupper +#define _CTYPE_iswxdigit _CTYPE_isxdigit + +/* The following is used to implement wctrans(). */ + +enum { + _CTYPE_tolower = 1, + _CTYPE_toupper, + _CTYPE_totitle +}; + +#define __CTYPE_TRANSTRING "\10tolower\0\10toupper\0\10totitle\0\0" + +/* Now define some ctype macros valid for the C/POSIX locale. */ + +/* ASCII ords of \t, \f, \n, \r, and \v are 9, 12, 10, 13, 11 respectively. */ +#define __C_isspace(c) \ + ((sizeof(c) == sizeof(char)) \ + ? ((((c) == ' ') || (((unsigned char)((c) - 9)) <= (13 - 9)))) \ + : ((((c) == ' ') || (((unsigned int)((c) - 9)) <= (13 - 9))))) +#define __C_isblank(c) (((c) == ' ') || ((c) == '\t')) +#define __C_isdigit(c) \ + ((sizeof(c) == sizeof(char)) \ + ? (((unsigned char)((c) - '0')) < 10) \ + : (((unsigned int)((c) - '0')) < 10)) +#define __C_isxdigit(c) \ + (__C_isdigit(c) \ + || ((sizeof(c) == sizeof(char)) \ + ? (((unsigned char)((((c)) | 0x20) - 'a')) < 6) \ + : (((unsigned int)((((c)) | 0x20) - 'a')) < 6))) +#define __C_iscntrl(c) \ + ((sizeof(c) == sizeof(char)) \ + ? ((((unsigned char)(c)) < 0x20) || ((c) == 0x7f)) \ + : ((((unsigned int)(c)) < 0x20) || ((c) == 0x7f))) +#define __C_isalpha(c) \ + ((sizeof(c) == sizeof(char)) \ + ? (((unsigned char)(((c) | 0x20) - 'a')) < 26) \ + : (((unsigned int)(((c) | 0x20) - 'a')) < 26)) +#define __C_isalnum(c) (__C_isalpha(c) || __C_isdigit(c)) +#define __C_isprint(c) \ + ((sizeof(c) == sizeof(char)) \ + ? (((unsigned char)((c) - 0x20)) <= (0x7e - 0x20)) \ + : (((unsigned int)((c) - 0x20)) <= (0x7e - 0x20))) +#define __C_islower(c) \ + ((sizeof(c) == sizeof(char)) \ + ? (((unsigned char)((c) - 'a')) < 26) \ + : (((unsigned int)((c) - 'a')) < 26)) +#define __C_isupper(c) \ + ((sizeof(c) == sizeof(char)) \ + ? (((unsigned char)((c) - 'A')) < 26) \ + : (((unsigned int)((c) - 'A')) < 26)) +#define __C_ispunct(c) \ + ((!__C_isalnum(c)) \ + && ((sizeof(c) == sizeof(char)) \ + ? (((unsigned char)((c) - 0x21)) <= (0x7e - 0x21)) \ + : (((unsigned int)((c) - 0x21)) <= (0x7e - 0x21)))) +#define __C_isgraph(c) \ + ((sizeof(c) == sizeof(char)) \ + ? (((unsigned int)((c) - 0x21)) <= (0x7e - 0x21)) \ + : (((unsigned int)((c) - 0x21)) <= (0x7e - 0x21))) + +#define __C_tolower(c) (__C_isupper(c) ? ((c) | 0x20) : (c)) +#define __C_toupper(c) (__C_islower(c) ? ((c) ^ 0x20) : (c)) + +#define __C_isxlower(c) \ + (__C_isdigit(c) \ + || ((sizeof(c) == sizeof(char)) \ + ? (((unsigned char)(((c)) - 'a')) < 6) \ + : (((unsigned int)(((c)) - 'a')) < 6))) +#define __C_isxupper(c) \ + (__C_isdigit(c) \ + || ((sizeof(c) == sizeof(char)) \ + ? (((unsigned char)(((c)) - 'A')) < 6) \ + : (((unsigned int)(((c)) - 'A')) < 6))) + +/* TODO: Replace the above with expressions like the following? */ +/* #define __C_isdigit(c) ((sizeof(c) == sizeof(char)) \ */ +/* ? (((unsigned char)((c) - '0')) < 10) \ */ +/* : (((unsigned int)((c) - '0')) < 10)) */ + +/* Similarly, define some wctype macros valid for the C/POSIX locale. */ + +/* First, we need some way to make sure the arg is in range. */ +#define __C_classed(c) \ + ((sizeof(c) <= sizeof(int)) || (c == ((unsigned char)c))) + +#define __C_iswspace(c) (__C_classed(c) && __C_isspace(c)) +#define __C_iswblank(c) (__C_classed(c) && __C_isblank(c)) +#define __C_iswdigit(c) (__C_classed(c) && __C_isdigit(c)) +#define __C_iswxdigit(c) (__C_classed(c) && __C_isxdigit(c)) +#define __C_iswcntrl(c) (__C_classed(c) && __C_iscntrl(c)) +#define __C_iswalpha(c) (__C_classed(c) && __C_isalpha(c)) +#define __C_iswalnum(c) (__C_classed(c) && __C_isalnum(c)) +#define __C_iswprint(c) (__C_classed(c) && __C_isprint(c)) +#define __C_iswlower(c) (__C_classed(c) && __C_islower(c)) +#define __C_iswupper(c) (__C_classed(c) && __C_isupper(c)) +#define __C_iswpunct(c) (__C_classed(c) && __C_ispunct(c)) +#define __C_iswgraph(c) (__C_classed(c) && __C_isgraph(c)) +#define __C_towlower(c) \ + ((__C_classed(c) && __C_isupper(c)) ? ((c) | 0x20) : (c)) +#define __C_towupper(c) \ + ((__C_classed(c) && __C_islower(c)) ? ((c) ^ 0x20) : (c)) + +/* Now define some macros to aviod the extra wrapper-function call. */ +#define __iswalnum(c) iswctype(c, _CTYPE_iswalnum) +#define __iswalpha(c) iswctype(c, _CTYPE_iswalpha) +#define __iswblank(c) iswctype(c, _CTYPE_iswblank) +#define __iswcntrl(c) iswctype(c, _CTYPE_iswcntrl) +#define __iswgraph(c) iswctype(c, _CTYPE_iswgraph) +#define __iswlower(c) iswctype(c, _CTYPE_iswlower) +#define __iswprint(c) iswctype(c, _CTYPE_iswprint) +#define __iswpunct(c) iswctype(c, _CTYPE_iswpunct) +#define __iswspace(c) iswctype(c, _CTYPE_iswspace) +#define __iswupper(c) iswctype(c, _CTYPE_iswupper) +#define __iswdigit(c) __C_iswdigit(c) +#define __iswxdigit(c) __C_iswxdigit(c) + +#endif /* _BITS_CTYPE_H */ diff --git a/libc/sysdeps/linux/common/bits/uClibc_locale.h b/libc/sysdeps/linux/common/bits/uClibc_locale.h new file mode 100644 index 000000000..2a35d38ec --- /dev/null +++ b/libc/sysdeps/linux/common/bits/uClibc_locale.h @@ -0,0 +1,261 @@ +/* Copyright (C) 2002 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. + */ + +/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! + * + * Besides uClibc, I'm using this code in my libc for elks, which is + * a 16-bit environment with a fairly limited compiler. It would make + * things much easier for me if this file isn't modified unnecessarily. + * In particular, please put any new or replacement functions somewhere + * else, and modify the makefile to use your version instead. + * Thanks. Manuel + * + * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */ + +#ifndef _UCLIBC_LOCALE_H +#define _UCLIBC_LOCALE_H + +/**********************************************************************/ +/* uClibc compatibilty stuff */ + +#ifdef __UCLIBC_HAS_WCHAR__ +#define __WCHAR_ENABLED +#endif + + +#ifdef __UCLIBC_HAS_LOCALE__ + +#undef __LOCALE_C_ONLY + +#else /* __UCLIBC_HAS_LOCALE__ */ + +#define __LOCALE_C_ONLY + +#endif /* __UCLIBC_HAS_LOCALE__ */ + +/**********************************************************************/ + +#define __NL_ITEM_CATEGORY_SHIFT (8) +#define __NL_ITEM_INDEX_MASK (0xff) + +/* TODO: Make sure these agree with the locale mmap file gererator! */ + +#define __LC_CTYPE 0 +#define __LC_NUMERIC 1 +#define __LC_MONETARY 2 +#define __LC_TIME 3 +#define __LC_COLLATE 4 +#define __LC_MESSAGES 5 +#define __LC_ALL 6 + +/**********************************************************************/ +#if defined(_LIBC) && !defined(__LOCALE_C_ONLY) + +#include <stddef.h> +#include <stdint.h> +#include <bits/uClibc_locale_data.h> + +/* TODO: This really needs to be somewhere else... */ +#include <limits.h> +#include <stdint.h> + +#if WCHAR_MIN == 0 +typedef wchar_t __uwchar_t; +#elif WCHAR_MAX <= USHRT_MAX +typedef unsigned short __uwchar_t; +#elif WCHAR_MAX <= UINT_MAX +typedef unsigned int __uwchar_t; +#elif WCHAR_MAX <= ULONG_MAX +typedef unsigned long __uwchar_t; +#elif defined(ULLONG_MAX) && (WCHAR_MAX <= ULLONG_MAX) +typedef unsigned long long __uwchar_t; +#elif WCHAR_MAX <= UINT_MAX +typedef uintmax_t __uwchar_t; +#else +#error Can not determine an appropriate type for __uwchar_t! +#endif + + + +extern void _locale_set(const unsigned char *p); +extern void _locale_init(void); + +/* TODO: assumes 8-bit chars!!! */ + +enum { + __ctype_encoding_7_bit, /* C/POSIX */ + __ctype_encoding_utf8, /* UTF-8 */ + __ctype_encoding_8_bit /* for 8-bit codeset locales */ +}; + +#define LOCALE_STRING_SIZE (2 * __LC_ALL + 2) + + /* + * '#' + 2_per_category + '\0' + * {locale row # : 0 = C|POSIX} + 0x8001 + * encoded in two chars as (((N+1) >> 8) | 0x80) and ((N+1) & 0xff) + * so decode is ((((uint16_t)(*s & 0x7f)) << 8) + s[1]) - 1 + * + * Note: 0s are not used as they are nul-terminators for strings. + * Note: 0xff, 0xff is the encoding for a non-selected locale. + * (see setlocale() below). + * In particular, C/POSIX locale is '#' + "\x80\x01"}*LC_ALL + nul. + */ + + +/* static unsigned char cur_locale[LOCALE_STRING_SIZE]; */ + +typedef struct { +/* int tables_loaded; */ +/* unsigned char lctypes[LOCALE_STRING_SIZE]; */ + unsigned char cur_locale[LOCALE_STRING_SIZE]; + + /* NL_LANGINFO stuff. BEWARE ORDERING!!! must agree with NL_* constants! */ + /* Also, numeric must be followed by monetary and the items must be in + * the "struct lconv" order. */ + + uint16_t category_offsets[__LC_ALL]; /* TODO -- fix? */ + unsigned char category_item_count[__LC_ALL]; /* TODO - fix */ + + /* ctype */ + unsigned char encoding; /* C/POSIX, 8-bit, UTF-8 */ + unsigned char mb_cur_max; /* determined by encoding _AND_ translit!!! */ + + const char *codeset; + +#ifdef __CTYPE_HAS_8_BIT_LOCALES + const unsigned char *idx8ctype; + const unsigned char *tbl8ctype; + const unsigned char *idx8uplow; + const unsigned char *tbl8uplow; +#ifdef __WCHAR_ENABLED + const unsigned char *idx8c2wc; + const uint16_t *tbl8c2wc; /* char > 0x7f to wide char */ + const unsigned char *idx8wc2c; + const unsigned char *tbl8wc2c; + /* translit */ +#endif /* __WCHAR_ENABLED */ +#endif /* __CTYPE_HAS_8_BIT_LOCALES */ +#ifdef __WCHAR_ENABLED + const unsigned char *tblwctype; + const unsigned char *tblwuplow; + const unsigned char *tblwcomb; + const int16_t *tblwuplow_diff; /* yes... signed */ + /* width?? */ +#endif /* __WCHAR_ENABLED */ + + /* numeric */ + const char *decimal_point; + const char *thousands_sep; + const char *grouping; + + /* monetary */ + const char *int_curr_symbol; + const char *currency_symbol; + const char *mon_decimal_point; + const char *mon_thousands_sep; + const char *mon_grouping; + const char *positive_sign; + const char *negative_sign; + const char *int_frac_digits; + const char *frac_digits; + const char *p_cs_precedes; + const char *p_sep_by_space; + const char *n_cs_precedes; + const char *n_sep_by_space; + const char *p_sign_posn; + const char *n_sign_posn; + const char *int_p_cs_precedes; + const char *int_p_sep_by_space; + const char *int_n_cs_precedes; + const char *int_n_sep_by_space; + const char *int_p_sign_posn; + const char *int_n_sign_posn; + + const char *crncystr; /* not returned by localeconv */ + + /* time */ + const char *abday_1; + const char *abday_2; + const char *abday_3; + const char *abday_4; + const char *abday_5; + const char *abday_6; + const char *abday_7; + + const char *day_1; + const char *day_2; + const char *day_3; + const char *day_4; + const char *day_5; + const char *day_6; + const char *day_7; + + const char *abmon_1; + const char *abmon_2; + const char *abmon_3; + const char *abmon_4; + const char *abmon_5; + const char *abmon_6; + const char *abmon_7; + const char *abmon_8; + const char *abmon_9; + const char *abmon_10; + const char *abmon_11; + const char *abmon_12; + + const char *mon_1; + const char *mon_2; + const char *mon_3; + const char *mon_4; + const char *mon_5; + const char *mon_6; + const char *mon_7; + const char *mon_8; + const char *mon_9; + const char *mon_10; + const char *mon_11; + const char *mon_12; + + const char *am_str; + const char *pm_str; + + const char *d_t_fmt; + const char *d_fmt; + const char *t_fmt; + const char *t_fmt_ampm; + const char *era; + + const char *era_year; /* non SUSv3 */ + const char *era_d_fmt; + const char *alt_digits; + const char *era_d_t_fmt; + const char *era_t_fmt; + + /* collate */ + + /* messages */ + const char *yesexpr; + const char *noexpr; + +} __locale_t; + +extern __locale_t __global_locale; + +#endif /* defined(_LIBC) && !defined(__LOCALE_C_ONLY) */ + +#endif /* _UCLIBC_LOCALE_H */ |