summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2002-05-06 07:37:32 +0000
committerManuel Novoa III <mjn3@codepoet.org>2002-05-06 07:37:32 +0000
commitd07fdf8b9ece2c4339b325921add50792077bf97 (patch)
treeb0886656bdd854728f2d1c05597368c4739ecc1b /libc
parent7f09a14cabbec158d683542e53f53ccfe75031fa (diff)
New locale support (in development). Supports LC_CTYPE, LC_NUMERIC,
LC_TIME, LC_MONETARY, and LC_MESSAGES for the SUSv3 items. Also, nl_langinfo() when real locale support is enabled. New implementation of ctype.h. New implementation of wctype.h. New implementation of most of the string functions (smaller). New implementation of the wcs/wmem functions. These are untested, but they're also just preprocessor-modified versions ot the corresponding str/mem functions. Tweaked qsort and new bsearch. Stuff still pending: stdlib.h and wchar.h mb<->wc functions. I actually have working versions of the stdlib ones, but the reentrant versions from wchar.h require some reworking. Basic replacement and translit support for wc->mb conversions. (groundwork laid). Simple-minded collate support such as was provided by the previous locale implementation. (mostly done -- 8-bit codesets only) Shared mmaping of the locale data and strerror message text.
Diffstat (limited to 'libc')
-rw-r--r--libc/misc/Makefile3
-rw-r--r--libc/misc/ctype/Makefile5
-rw-r--r--libc/misc/ctype/ctype.c486
-rw-r--r--libc/misc/ctype/ctype_C.c517
-rw-r--r--libc/misc/internals/__uClibc_main.c12
-rw-r--r--libc/misc/locale/Makefile15
-rw-r--r--libc/misc/locale/_locale.h22
-rw-r--r--libc/misc/locale/locale.c719
-rw-r--r--libc/misc/locale/localeconv.c52
-rw-r--r--libc/misc/wctype/Makefile47
-rw-r--r--libc/misc/wctype/wctype.c480
-rw-r--r--libc/stdlib/Makefile5
-rw-r--r--libc/stdlib/stdlib.c181
-rw-r--r--libc/string/Makefile55
-rw-r--r--libc/string/wstring.c1273
-rw-r--r--libc/sysdeps/linux/common/bits/.cvsignore1
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_ctype.h250
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_locale.h261
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 */