aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1996-03-28 08:30:38 +0000
committerRoland McGrath <roland@gnu.org>1996-03-28 08:30:38 +0000
commit19bc17a90548ee427035994bbc4b14395723ff1f (patch)
treee7a17eda196c2610ca4be26c9e7985815162eafb
parent53f770e0f9d405ea8d1888254c6f7ce431b04c6e (diff)
downloadglibc-19bc17a90548ee427035994bbc4b14395723ff1f.tar
glibc-19bc17a90548ee427035994bbc4b14395723ff1f.tar.gz
glibc-19bc17a90548ee427035994bbc4b14395723ff1f.tar.bz2
glibc-19bc17a90548ee427035994bbc4b14395723ff1f.zip
Thu Mar 28 03:25:10 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
* intl/Makefile (copysrc): Add missing > in sed cmd. Sat Mar 23 17:52:49 1996 Ulrich Drepper <drepper@gnu.ai.mit.edu> * Makeconfig: Rename Makefile variable nlsdir to i18ndir and change value to $(datadir)/i18n. `nls' is not an appropriate name. * Makefile (subdirs): Add new subdir wctype. * ctype/ctype-info.c: Add new global variable __ctype_names and initialize from _nl_C_LC_CTYPE. * ctype/ctype.h: In P1003.3b/D11 `alnum' is a separate character class. Use bit 11. [_ISbit]: Protect definition of bitmasks because they are also used in wctype.h. * libio/genops.c (_IO_sputbackc, _IO_sungetc): Clear EOF flag after successfully pushing back a character. Fundamental changes in locale implementation. Almost nothing from the old code is used anymore. * locale/charmap.c, locale/collate.c, locale/config.h, locale/ctypedump.c, locale/hash.h, locale/keyword.gperf, locale/keyword.h, locale/loadlocale.c, locale/locale-ctype.c, locale/locale.c locale/localeconv.c, locale/localedef.c, locale/localedef.h, locale/locfile-hash.c, locale/locfile-lex.c, locale/locfile-parse.c, locale/messages.c, locale/monetary.c, locale/numeric.c, locale/setlocale.c, locale/token.h, locale/xmalloc.c: Removed. * locale/Makefile: Update for new locale implementation with program source code distributed in subdir. * locale/categories.def, locale/iso-4217.def: Updated file for new locale implementation. * locale/langinfo.h: Updated for new locale implementation. (ERA_D_T_FMT, ERA_T_FMT): New official values according to P1003.2b/D11. (_NL_COLLATE_NRULES, _NL_COLLATE_RULES, _NL_COLLATE_HASH_SIZE, _NL_COLLATE_HASH_LAYERS, _NL_COLLATE_TABLE_EB, _NL_COLLATE_TABLE_EL, _NL_COLLATE_UNDEFINED, _NL_COLLATE_EXTRA_EB, _NL_COLLATE_EXTRA_EL, _NL_CTYPE_NAMES_EB, _NL_CTYPE_NAMES_EL, _NL_CTYPE_HASH_SIZE, _NL_CTYPE_HASH_LAYERS, _NL_CTYPE_CLASS_NAMES, _NL_CTYPE_MAP_NAMES, _NL_CTYPE_WIDTH): New internal values for extended LC_CTYPE and LC_COLLATE implementation. * locale/simple-hash.c, locale/simple-hash.h, locale/xmalloc.c, locale/xstrdup.c: Helper functions for locale related programs. * locale/C-collate.c, locale/C-ctype.c, locale/C-messages.c, locale/C-monetary.c, locale/C-numeric.c, locale/C-time.c, locale/lc-collate.c, locale/lc-ctype.c, locale/lc-messages.c, locale/lc-monetary.c, locale/lc-numeric.c, locale/lc-time.c: New implementation of locale functions, and new generated "C" locale data. * locale/loadlocale.c: Now handles word fields in locale binary automatically by changing the endianess if necessary. * locale/localeinfo.h (LIMAGIC): Changed magic number because of incompatible changes. (locale_data): Changed definition to allow word as a value type. (coll_sort_rule): Values for collation sorting mode. (_NL_CURRENT_WORD): New macro to access word value of locale entry. (__collate_table, __collate_extra): Declare new global variables for collation tables. * locale/programs/charmap-kw.gperf, locale/programs/charmap-kw.h, locale/programs/charmap.c, locale/programs/charset.c, locale/programs/charset.h, locale/programs/config.h, locale/programs/ctypedump.c, locale/programs/ld-collate.c, locale/programs/ld-ctype.c, locale/programs/ld-messages.c, locale/programs/ld-monetary.c, locale/programs/ld-numeric.c, locale/programs/ld-time.c, locale/programs/linereader.c, locale/programs/linereader.h, locale/programs/locale.c, locale/programs/localedef.c, locale/programs/locales.h, locale/programs/locfile-kw.gperf, locale/programs/locfile-kw.h, locale/programs/locfile-token.h, locale/programs/locfile.c, locale/programs/locfile.h, locale/programs/stringtrans.c, locale/programs/stringtrans.h: Implementation of locale related programs. * locale/weight.h: Functions to access collation tables. * posix/unistd.h: Define _POSIX2_LOCALEDEF. * stdio-common/printf_fp.c: Fix bug with printing certain numbers < 10^-1. Reported by Bill Metzenthen. * stdio-common/tfformat.c: Add new test for above bug. * string/strcoll.c, string/strxfrm.c: Real implementation of string collation according to ISO C. * wctype/Makefile, wctype/cname-lookup.h, wctype/iswctype.c, wctype/test_wctype.c, wctype/towctrans.c, wctype/wcfuncs.c, wctype/wctrans.c, wctype/wctype.c, wctype/wctype.h: New files. Implementation of wide character classes and mapping.
-rw-r--r--ChangeLog105
-rw-r--r--Makeconfig4
-rw-r--r--Makefile2
-rw-r--r--ctype/ctype-info.c14
-rw-r--r--ctype/ctype.h12
-rw-r--r--intl/Makefile2
-rw-r--r--libio/genops.c23
-rw-r--r--locale/C-ctype.c344
-rw-r--r--locale/C-messages.c10
-rw-r--r--locale/C-monetary.c32
-rw-r--r--locale/C-numeric.c8
-rw-r--r--locale/C-time.c93
-rw-r--r--locale/Makefile35
-rw-r--r--locale/categories.def177
-rw-r--r--locale/charmap.c524
-rw-r--r--locale/collate.c212
-rw-r--r--locale/config.h45
-rw-r--r--locale/hash.h50
-rw-r--r--locale/keyword.gperf77
-rw-r--r--locale/keyword.h180
-rw-r--r--locale/langinfo.h29
-rw-r--r--locale/lc-collate.c31
-rw-r--r--locale/lc-ctype.c5
-rw-r--r--locale/loadlocale.c34
-rw-r--r--locale/locale-ctype.c821
-rw-r--r--locale/localedef.c259
-rw-r--r--locale/localedef.h196
-rw-r--r--locale/localeinfo.h63
-rw-r--r--locale/locfile-hash.c254
-rw-r--r--locale/locfile-lex.c533
-rw-r--r--locale/locfile-parse.c838
-rw-r--r--locale/messages.c76
-rw-r--r--locale/monetary.c132
-rw-r--r--locale/numeric.c62
-rw-r--r--locale/programs/charmap-kw.gperf40
-rw-r--r--locale/programs/charmap-kw.h117
-rw-r--r--locale/programs/charmap.c593
-rw-r--r--locale/programs/charset.c132
-rw-r--r--locale/programs/charset.h61
-rw-r--r--locale/programs/config.h33
-rw-r--r--locale/programs/ctypedump.c (renamed from locale/ctypedump.c)16
-rw-r--r--locale/programs/ld-collate.c1549
-rw-r--r--locale/programs/ld-ctype.c1310
-rw-r--r--locale/programs/ld-messages.c237
-rw-r--r--locale/programs/ld-monetary.c385
-rw-r--r--locale/programs/ld-numeric.c208
-rw-r--r--locale/programs/ld-time.c310
-rw-r--r--locale/programs/linereader.c579
-rw-r--r--locale/programs/linereader.h158
-rw-r--r--locale/programs/locale.c (renamed from locale/locale.c)51
-rw-r--r--locale/programs/localedef.c461
-rw-r--r--locale/programs/locales.h207
-rw-r--r--locale/programs/locfile-kw.gperf99
-rw-r--r--locale/programs/locfile-kw.h211
-rw-r--r--locale/programs/locfile-token.h147
-rw-r--r--locale/programs/locfile.c979
-rw-r--r--locale/programs/locfile.h75
-rw-r--r--locale/programs/stringtrans.c146
-rw-r--r--locale/programs/stringtrans.h38
-rw-r--r--locale/setlocale.c4
-rw-r--r--locale/token.h54
-rw-r--r--locale/weight.h171
-rw-r--r--misc/error.c75
-rw-r--r--misc/error.h9
-rw-r--r--posix/unistd.h4
-rw-r--r--stdio-common/printf_fp.c13
-rw-r--r--stdio-common/tfformat.c19
-rw-r--r--string/strcoll.c142
-rw-r--r--string/strxfrm.c175
-rw-r--r--wctype/Makefile30
-rw-r--r--wctype/cname-lookup.h45
-rw-r--r--wctype/iswctype.c39
-rw-r--r--wctype/test_wctype.c75
-rw-r--r--wctype/towctrans.c36
-rw-r--r--wctype/wcfuncs.c52
-rw-r--r--wctype/wctrans.c59
-rw-r--r--wctype/wctype.c56
-rw-r--r--wctype/wctype.h215
78 files changed, 10103 insertions, 4594 deletions
diff --git a/ChangeLog b/ChangeLog
index c5f49f215b..aedd2d0d90 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,108 @@
+Thu Mar 28 03:25:10 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
+
+ * intl/Makefile (copysrc): Add missing > in sed cmd.
+
+Sat Mar 23 17:52:49 1996 Ulrich Drepper <drepper@gnu.ai.mit.edu>
+
+ * Makeconfig: Rename Makefile variable nlsdir to i18ndir and
+ change value to $(datadir)/i18n. `nls' is not an appropriate
+ name.
+
+ * Makefile (subdirs): Add new subdir wctype.
+
+ * ctype/ctype-info.c: Add new global variable __ctype_names
+ and initialize from _nl_C_LC_CTYPE.
+
+ * ctype/ctype.h: In P1003.3b/D11 `alnum' is a separate character
+ class. Use bit 11.
+ [_ISbit]: Protect definition of bitmasks because they are also
+ used in wctype.h.
+
+ * libio/genops.c (_IO_sputbackc, _IO_sungetc): Clear EOF flag
+ after successfully pushing back a character.
+
+ Fundamental changes in locale implementation. Almost nothing
+ from the old code is used anymore.
+ * locale/charmap.c, locale/collate.c, locale/config.h,
+ locale/ctypedump.c, locale/hash.h, locale/keyword.gperf,
+ locale/keyword.h, locale/loadlocale.c, locale/locale-ctype.c,
+ locale/locale.c locale/localeconv.c, locale/localedef.c,
+ locale/localedef.h, locale/locfile-hash.c, locale/locfile-lex.c,
+ locale/locfile-parse.c, locale/messages.c, locale/monetary.c,
+ locale/numeric.c, locale/setlocale.c, locale/token.h,
+ locale/xmalloc.c: Removed.
+
+ * locale/Makefile: Update for new locale implementation with
+ program source code distributed in subdir.
+
+ * locale/categories.def, locale/iso-4217.def: Updated file
+ for new locale implementation.
+
+ * locale/langinfo.h: Updated for new locale implementation.
+ (ERA_D_T_FMT, ERA_T_FMT): New official values according to
+ P1003.2b/D11.
+ (_NL_COLLATE_NRULES, _NL_COLLATE_RULES, _NL_COLLATE_HASH_SIZE,
+ _NL_COLLATE_HASH_LAYERS, _NL_COLLATE_TABLE_EB,
+ _NL_COLLATE_TABLE_EL, _NL_COLLATE_UNDEFINED, _NL_COLLATE_EXTRA_EB,
+ _NL_COLLATE_EXTRA_EL, _NL_CTYPE_NAMES_EB, _NL_CTYPE_NAMES_EL,
+ _NL_CTYPE_HASH_SIZE, _NL_CTYPE_HASH_LAYERS, _NL_CTYPE_CLASS_NAMES,
+ _NL_CTYPE_MAP_NAMES, _NL_CTYPE_WIDTH): New internal values for
+ extended LC_CTYPE and LC_COLLATE implementation.
+
+ * locale/simple-hash.c, locale/simple-hash.h, locale/xmalloc.c,
+ locale/xstrdup.c: Helper functions for locale related programs.
+
+ * locale/C-collate.c, locale/C-ctype.c,
+ locale/C-messages.c, locale/C-monetary.c,
+ locale/C-numeric.c, locale/C-time.c,
+ locale/lc-collate.c, locale/lc-ctype.c,
+ locale/lc-messages.c, locale/lc-monetary.c,
+ locale/lc-numeric.c, locale/lc-time.c: New implementation of locale
+ functions, and new generated "C" locale data.
+
+ * locale/loadlocale.c: Now handles word fields in locale binary
+ automatically by changing the endianess if necessary.
+
+ * locale/localeinfo.h (LIMAGIC): Changed magic number because
+ of incompatible changes.
+ (locale_data): Changed definition to allow word as a value type.
+ (coll_sort_rule): Values for collation sorting mode.
+ (_NL_CURRENT_WORD): New macro to access word value of locale entry.
+ (__collate_table, __collate_extra): Declare new global variables
+ for collation tables.
+
+ * locale/programs/charmap-kw.gperf, locale/programs/charmap-kw.h,
+ locale/programs/charmap.c, locale/programs/charset.c,
+ locale/programs/charset.h, locale/programs/config.h,
+ locale/programs/ctypedump.c, locale/programs/ld-collate.c,
+ locale/programs/ld-ctype.c, locale/programs/ld-messages.c,
+ locale/programs/ld-monetary.c, locale/programs/ld-numeric.c,
+ locale/programs/ld-time.c, locale/programs/linereader.c,
+ locale/programs/linereader.h, locale/programs/locale.c,
+ locale/programs/localedef.c, locale/programs/locales.h,
+ locale/programs/locfile-kw.gperf, locale/programs/locfile-kw.h,
+ locale/programs/locfile-token.h, locale/programs/locfile.c,
+ locale/programs/locfile.h, locale/programs/stringtrans.c,
+ locale/programs/stringtrans.h: Implementation of locale related
+ programs.
+
+ * locale/weight.h: Functions to access collation tables.
+
+ * posix/unistd.h: Define _POSIX2_LOCALEDEF.
+
+ * stdio-common/printf_fp.c: Fix bug with printing certain numbers
+ < 10^-1. Reported by Bill Metzenthen.
+
+ * stdio-common/tfformat.c: Add new test for above bug.
+
+ * string/strcoll.c, string/strxfrm.c: Real implementation of
+ string collation according to ISO C.
+
+ * wctype/Makefile, wctype/cname-lookup.h, wctype/iswctype.c,
+ wctype/test_wctype.c, wctype/towctrans.c, wctype/wcfuncs.c,
+ wctype/wctrans.c, wctype/wctype.c, wctype/wctype.h: New files.
+ Implementation of wide character classes and mapping.
+
Wed Mar 27 14:52:11 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
* elf/rtld.c (dl_main): Call _dl_sysdep_start_cleanup after
diff --git a/Makeconfig b/Makeconfig
index 46da933327..fe4db0ba48 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -171,8 +171,8 @@ localedir = $(datadir)/locale
endif
# Where to install the locale charmap source files.
-ifndef nlsdir
-nlsdir = $(datadir)/nls
+ifndef i18ndir
+i18ndir = $(datadir)/i18n
endif
diff --git a/Makefile b/Makefile
index a52d845859..30e0204bb6 100644
--- a/Makefile
+++ b/Makefile
@@ -54,7 +54,7 @@ endif
subdirs = csu assert ctype db locale intl math setjmp signal stdlib \
stdio-common $(stdio) malloc string wcsmbs time dirent grp pwd\
posix io termios resource misc socket sysvipc gmon gnulib \
- $(wildcard crypt) manual $(sysdep-subdirs) elf
+ wctype $(wildcard crypt) manual $(sysdep-subdirs) elf
export subdirs := $(subdirs) # Benign, useless in GNU make before 3.63.
# The mach and hurd subdirectories have many generated header files which
diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c
index a1054b2d16..3a47b3460c 100644
--- a/ctype/ctype-info.c
+++ b/ctype/ctype-info.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -21,11 +21,15 @@ Cambridge, MA 02139, USA. */
/* Defined in locale/C-ctype.c. */
extern const char _nl_C_LC_CTYPE_class[];
+extern const char _nl_C_LC_CTYPE_class32[];
extern const char _nl_C_LC_CTYPE_toupper[];
extern const char _nl_C_LC_CTYPE_tolower[];
+extern const char _nl_C_LC_CTYPE_names[];
-#define b(u,x) (((u int *) _nl_C_LC_CTYPE_##x) + 128);
+#define b(u,x,o) (((const u int *) _nl_C_LC_CTYPE_##x) + o);
-const unsigned short int *__ctype_b = b(unsigned short, class);
-const int *__ctype_tolower = b(, tolower);
-const int *__ctype_toupper = b(, toupper);
+const unsigned short int *__ctype_b = b (unsigned short, class, 128);
+const unsigned int *__ctype32_b = b (unsigned, class32, 0);
+const int *__ctype_tolower = b (, tolower, 128);
+const int *__ctype_toupper = b (, toupper, 128);
+const unsigned int *__ctype_names = b (unsigned, names, 0);
diff --git a/ctype/ctype.h b/ctype/ctype.h
index 025373c381..af2d6a90dd 100644
--- a/ctype/ctype.h
+++ b/ctype/ctype.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1993, 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -27,6 +27,7 @@ Cambridge, MA 02139, USA. */
__BEGIN_DECLS
+#ifndef _ISbit
/* These are all the characteristics of characters.
If there get to be more than 16 distinct characteristics,
many things must be changed that use `unsigned short int's.
@@ -55,11 +56,9 @@ enum
_ISblank = _ISbit (8), /* Blank (usually SPC and TAB). */
_IScntrl = _ISbit (9), /* Control character. */
_ISpunct = _ISbit (10), /* Punctuation. */
-
- /* The following are defined in POSIX.2 as being combinations of the
- classes above. */
- _ISalnum = _ISalpha | _ISdigit /* Alphanumeric. */
+ _ISalnum = _ISbit (11) /* Alphanumeric. */
};
+#endif /* ! _ISbit */
/* These are defined in ctype-info.c.
The declarations here must match those in localeinfo.h.
@@ -70,7 +69,8 @@ enum
char' values and for EOF; we also support negative `signed char' values
for broken old programs. The case conversion arrays are of `int's
rather than `unsigned char's because tolower (EOF) must be EOF, which
- doesn't fit into an `unsigned char'. */
+ doesn't fit into an `unsigned char'. But today more important is that
+ the arrays are also used for multi-byte character sets. */
extern __const unsigned short int *__ctype_b; /* Characteristics. */
extern __const int *__ctype_tolower; /* Case conversions. */
extern __const int *__ctype_toupper; /* Case conversions. */
diff --git a/intl/Makefile b/intl/Makefile
index 8b1c056fe2..159d1b1534 100644
--- a/intl/Makefile
+++ b/intl/Makefile
@@ -36,7 +36,7 @@ ifdef gettext-srcdir
%.h:: ../gpl2lgpl.sed $(gettext-srcdir)/intl/%.h; $(copysrc)
define copysrc
-sed -f $^ $@.new
+sed -f $^ > $@.new
chmod a-w $@.new
mv -f $@.new $@
test ! -d CVS || cvs commit -m'Updated from $<' $@
diff --git a/libio/genops.c b/libio/genops.c
index 7eb2d43ee1..23a6fdeaea 100644
--- a/libio/genops.c
+++ b/libio/genops.c
@@ -511,26 +511,41 @@ int
DEFUN(_IO_sputbackc, (fp, c),
register _IO_FILE *fp AND int c)
{
+ int result;
+
if (fp->_IO_read_ptr > fp->_IO_read_base
&& (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c)
{
fp->_IO_read_ptr--;
- return (unsigned char)c;
+ result = (unsigned char)c;
}
- return _IO_PBACKFAIL (fp, c);
+ else
+ result = _IO_PBACKFAIL (fp, c);
+
+ if (result != EOF)
+ fp->_flags &= ~_IO_EOF_SEEN;
+
+ return result;
}
int
DEFUN(_IO_sungetc, (fp),
register _IO_FILE *fp)
{
+ int result;
+
if (fp->_IO_read_ptr > fp->_IO_read_base)
{
fp->_IO_read_ptr--;
- return (unsigned char)*fp->_IO_read_ptr;
+ result = (unsigned char)*fp->_IO_read_ptr;
}
else
- return _IO_PBACKFAIL (fp, EOF);
+ result = _IO_PBACKFAIL (fp, EOF);
+
+ if (result != EOF)
+ fp->_flags &= ~_IO_EOF_SEEN;
+
+ return result;
}
#if 0 /* Work in progress */
diff --git a/locale/C-ctype.c b/locale/C-ctype.c
index 7a5c0c7b7f..8bf6beeea5 100644
--- a/locale/C-ctype.c
+++ b/locale/C-ctype.c
@@ -3,7 +3,7 @@
#include "localeinfo.h"
#include <endian.h>
-const char _nl_C_LC_CTYPE_class[] =
+const char _nl_C_LC_CTYPE_class[768] =
/* 0x80 */ "\002\000" "\002\000" "\002\000" "\002\000" "\002\000" "\002\000"
/* 0x86 */ "\002\000" "\002\000" "\002\000" "\002\000" "\002\000" "\002\000"
/* 0x8c */ "\002\000" "\002\000" "\002\000" "\002\000" "\002\000" "\002\000"
@@ -33,19 +33,19 @@ const char _nl_C_LC_CTYPE_class[] =
/* 0x1c */ "\002\000" "\002\000" "\002\000" "\002\000" "\001\140" "\004\300"
/* 0x22 */ "\004\300" "\004\300" "\004\300" "\004\300" "\004\300" "\004\300"
/* 0x28 */ "\004\300" "\004\300" "\004\300" "\004\300" "\004\300" "\004\300"
- /* 0x2e */ "\004\300" "\004\300" "\000\330" "\000\330" "\000\330" "\000\330"
- /* 0x34 */ "\000\330" "\000\330" "\000\330" "\000\330" "\000\330" "\000\330"
+ /* 0x2e */ "\004\300" "\004\300" "\010\330" "\010\330" "\010\330" "\010\330"
+ /* 0x34 */ "\010\330" "\010\330" "\010\330" "\010\330" "\010\330" "\010\330"
/* 0x3a */ "\004\300" "\004\300" "\004\300" "\004\300" "\004\300" "\004\300"
- /* 0x40 */ "\004\300" "\000\325" "\000\325" "\000\325" "\000\325" "\000\325"
- /* 0x46 */ "\000\325" "\000\305" "\000\305" "\000\305" "\000\305" "\000\305"
- /* 0x4c */ "\000\305" "\000\305" "\000\305" "\000\305" "\000\305" "\000\305"
- /* 0x52 */ "\000\305" "\000\305" "\000\305" "\000\305" "\000\305" "\000\305"
- /* 0x58 */ "\000\305" "\000\305" "\000\305" "\004\300" "\004\300" "\004\300"
- /* 0x5e */ "\004\300" "\004\300" "\004\300" "\000\326" "\000\326" "\000\326"
- /* 0x64 */ "\000\326" "\000\326" "\000\326" "\000\306" "\000\306" "\000\306"
- /* 0x6a */ "\000\306" "\000\306" "\000\306" "\000\306" "\000\306" "\000\306"
- /* 0x70 */ "\000\306" "\000\306" "\000\306" "\000\306" "\000\306" "\000\306"
- /* 0x76 */ "\000\306" "\000\306" "\000\306" "\000\306" "\000\306" "\004\300"
+ /* 0x40 */ "\004\300" "\010\325" "\010\325" "\010\325" "\010\325" "\010\325"
+ /* 0x46 */ "\010\325" "\010\305" "\010\305" "\010\305" "\010\305" "\010\305"
+ /* 0x4c */ "\010\305" "\010\305" "\010\305" "\010\305" "\010\305" "\010\305"
+ /* 0x52 */ "\010\305" "\010\305" "\010\305" "\010\305" "\010\305" "\010\305"
+ /* 0x58 */ "\010\305" "\010\305" "\010\305" "\004\300" "\004\300" "\004\300"
+ /* 0x5e */ "\004\300" "\004\300" "\004\300" "\010\326" "\010\326" "\010\326"
+ /* 0x64 */ "\010\326" "\010\326" "\010\326" "\010\306" "\010\306" "\010\306"
+ /* 0x6a */ "\010\306" "\010\306" "\010\306" "\010\306" "\010\306" "\010\306"
+ /* 0x70 */ "\010\306" "\010\306" "\010\306" "\010\306" "\010\306" "\010\306"
+ /* 0x76 */ "\010\306" "\010\306" "\010\306" "\010\306" "\010\306" "\004\300"
/* 0x7c */ "\004\300" "\004\300" "\004\300" "\002\000" "\002\000" "\002\000"
/* 0x82 */ "\002\000" "\002\000" "\002\000" "\002\000" "\002\000" "\002\000"
/* 0x88 */ "\002\000" "\002\000" "\002\000" "\002\000" "\002\000" "\002\000"
@@ -69,8 +69,96 @@ const char _nl_C_LC_CTYPE_class[] =
/* 0xf4 */ "\002\000" "\002\000" "\002\000" "\002\000" "\002\000" "\002\000"
/* 0xfa */ "\002\000" "\002\000" "\002\000" "\002\000" "\002\000" "\002\000"
;
+const char _nl_C_LC_CTYPE_class32[1024] =
+ /* 0x00 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x03 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x06 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x09 */ "\003\040\000\000" "\002\040\000\000" "\002\040\000\000"
+ /* 0x0c */ "\002\040\000\000" "\002\040\000\000" "\002\000\000\000"
+ /* 0x0f */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x12 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x15 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x18 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x1b */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x1e */ "\002\000\000\000" "\002\000\000\000" "\001\140\000\000"
+ /* 0x21 */ "\004\300\000\000" "\004\300\000\000" "\004\300\000\000"
+ /* 0x24 */ "\004\300\000\000" "\004\300\000\000" "\004\300\000\000"
+ /* 0x27 */ "\004\300\000\000" "\004\300\000\000" "\004\300\000\000"
+ /* 0x2a */ "\004\300\000\000" "\004\300\000\000" "\004\300\000\000"
+ /* 0x2d */ "\004\300\000\000" "\004\300\000\000" "\004\300\000\000"
+ /* 0x30 */ "\010\330\000\000" "\010\330\000\000" "\010\330\000\000"
+ /* 0x33 */ "\010\330\000\000" "\010\330\000\000" "\010\330\000\000"
+ /* 0x36 */ "\010\330\000\000" "\010\330\000\000" "\010\330\000\000"
+ /* 0x39 */ "\010\330\000\000" "\004\300\000\000" "\004\300\000\000"
+ /* 0x3c */ "\004\300\000\000" "\004\300\000\000" "\004\300\000\000"
+ /* 0x3f */ "\004\300\000\000" "\004\300\000\000" "\010\325\000\000"
+ /* 0x42 */ "\010\325\000\000" "\010\325\000\000" "\010\325\000\000"
+ /* 0x45 */ "\010\325\000\000" "\010\325\000\000" "\010\305\000\000"
+ /* 0x48 */ "\010\305\000\000" "\010\305\000\000" "\010\305\000\000"
+ /* 0x4b */ "\010\305\000\000" "\010\305\000\000" "\010\305\000\000"
+ /* 0x4e */ "\010\305\000\000" "\010\305\000\000" "\010\305\000\000"
+ /* 0x51 */ "\010\305\000\000" "\010\305\000\000" "\010\305\000\000"
+ /* 0x54 */ "\010\305\000\000" "\010\305\000\000" "\010\305\000\000"
+ /* 0x57 */ "\010\305\000\000" "\010\305\000\000" "\010\305\000\000"
+ /* 0x5a */ "\010\305\000\000" "\004\300\000\000" "\004\300\000\000"
+ /* 0x5d */ "\004\300\000\000" "\004\300\000\000" "\004\300\000\000"
+ /* 0x60 */ "\004\300\000\000" "\010\326\000\000" "\010\326\000\000"
+ /* 0x63 */ "\010\326\000\000" "\010\326\000\000" "\010\326\000\000"
+ /* 0x66 */ "\010\326\000\000" "\010\306\000\000" "\010\306\000\000"
+ /* 0x69 */ "\010\306\000\000" "\010\306\000\000" "\010\306\000\000"
+ /* 0x6c */ "\010\306\000\000" "\010\306\000\000" "\010\306\000\000"
+ /* 0x6f */ "\010\306\000\000" "\010\306\000\000" "\010\306\000\000"
+ /* 0x72 */ "\010\306\000\000" "\010\306\000\000" "\010\306\000\000"
+ /* 0x75 */ "\010\306\000\000" "\010\306\000\000" "\010\306\000\000"
+ /* 0x78 */ "\010\306\000\000" "\010\306\000\000" "\010\306\000\000"
+ /* 0x7b */ "\004\300\000\000" "\004\300\000\000" "\004\300\000\000"
+ /* 0x7e */ "\004\300\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x81 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x84 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x87 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x8a */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x8d */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x90 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x93 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x96 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x99 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x9c */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0x9f */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xa2 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xa5 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xa8 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xab */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xae */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xb1 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xb4 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xb7 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xba */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xbd */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xc0 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xc3 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xc6 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xc9 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xcc */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xcf */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xd2 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xd5 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xd8 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xdb */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xde */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xe1 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xe4 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xe7 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xea */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xed */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xf0 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xf3 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xf6 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xf9 */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xfc */ "\002\000\000\000" "\002\000\000\000" "\002\000\000\000"
+ /* 0xff */ "\002\000\000\000"
+;
#if BYTE_ORDER == LITTLE_ENDIAN
-const char _nl_C_LC_CTYPE_toupper[] =
+const char _nl_C_LC_CTYPE_toupper[1536] =
/* 0x80 */ "\200\000\000\000" "\201\000\000\000" "\202\000\000\000"
/* 0x83 */ "\203\000\000\000" "\204\000\000\000" "\205\000\000\000"
/* 0x86 */ "\206\000\000\000" "\207\000\000\000" "\210\000\000\000"
@@ -200,7 +288,7 @@ const char _nl_C_LC_CTYPE_toupper[] =
/* 0xfa */ "\372\000\000\000" "\373\000\000\000" "\374\000\000\000"
/* 0xfd */ "\375\000\000\000" "\376\000\000\000" "\377\000\000\000"
;
-const char _nl_C_LC_CTYPE_tolower[] =
+const char _nl_C_LC_CTYPE_tolower[1536] =
/* 0x80 */ "\200\000\000\000" "\201\000\000\000" "\202\000\000\000"
/* 0x83 */ "\203\000\000\000" "\204\000\000\000" "\205\000\000\000"
/* 0x86 */ "\206\000\000\000" "\207\000\000\000" "\210\000\000\000"
@@ -330,8 +418,96 @@ const char _nl_C_LC_CTYPE_tolower[] =
/* 0xfa */ "\372\000\000\000" "\373\000\000\000" "\374\000\000\000"
/* 0xfd */ "\375\000\000\000" "\376\000\000\000" "\377\000\000\000"
;
+const char _nl_C_LC_CTYPE_names[1024] =
+ /* 0x00 */ "\000\000\000\000" "\001\000\000\000" "\002\000\000\000"
+ /* 0x03 */ "\003\000\000\000" "\004\000\000\000" "\005\000\000\000"
+ /* 0x06 */ "\006\000\000\000" "\007\000\000\000" "\010\000\000\000"
+ /* 0x09 */ "\011\000\000\000" "\012\000\000\000" "\013\000\000\000"
+ /* 0x0c */ "\014\000\000\000" "\015\000\000\000" "\016\000\000\000"
+ /* 0x0f */ "\017\000\000\000" "\020\000\000\000" "\021\000\000\000"
+ /* 0x12 */ "\022\000\000\000" "\023\000\000\000" "\024\000\000\000"
+ /* 0x15 */ "\025\000\000\000" "\026\000\000\000" "\027\000\000\000"
+ /* 0x18 */ "\030\000\000\000" "\031\000\000\000" "\032\000\000\000"
+ /* 0x1b */ "\033\000\000\000" "\034\000\000\000" "\035\000\000\000"
+ /* 0x1e */ "\036\000\000\000" "\037\000\000\000" "\040\000\000\000"
+ /* 0x21 */ "\041\000\000\000" "\042\000\000\000" "\043\000\000\000"
+ /* 0x24 */ "\044\000\000\000" "\045\000\000\000" "\046\000\000\000"
+ /* 0x27 */ "\047\000\000\000" "\050\000\000\000" "\051\000\000\000"
+ /* 0x2a */ "\052\000\000\000" "\053\000\000\000" "\054\000\000\000"
+ /* 0x2d */ "\055\000\000\000" "\056\000\000\000" "\057\000\000\000"
+ /* 0x30 */ "\060\000\000\000" "\061\000\000\000" "\062\000\000\000"
+ /* 0x33 */ "\063\000\000\000" "\064\000\000\000" "\065\000\000\000"
+ /* 0x36 */ "\066\000\000\000" "\067\000\000\000" "\070\000\000\000"
+ /* 0x39 */ "\071\000\000\000" "\072\000\000\000" "\073\000\000\000"
+ /* 0x3c */ "\074\000\000\000" "\075\000\000\000" "\076\000\000\000"
+ /* 0x3f */ "\077\000\000\000" "\100\000\000\000" "\101\000\000\000"
+ /* 0x42 */ "\102\000\000\000" "\103\000\000\000" "\104\000\000\000"
+ /* 0x45 */ "\105\000\000\000" "\106\000\000\000" "\107\000\000\000"
+ /* 0x48 */ "\110\000\000\000" "\111\000\000\000" "\112\000\000\000"
+ /* 0x4b */ "\113\000\000\000" "\114\000\000\000" "\115\000\000\000"
+ /* 0x4e */ "\116\000\000\000" "\117\000\000\000" "\120\000\000\000"
+ /* 0x51 */ "\121\000\000\000" "\122\000\000\000" "\123\000\000\000"
+ /* 0x54 */ "\124\000\000\000" "\125\000\000\000" "\126\000\000\000"
+ /* 0x57 */ "\127\000\000\000" "\130\000\000\000" "\131\000\000\000"
+ /* 0x5a */ "\132\000\000\000" "\133\000\000\000" "\134\000\000\000"
+ /* 0x5d */ "\135\000\000\000" "\136\000\000\000" "\137\000\000\000"
+ /* 0x60 */ "\140\000\000\000" "\141\000\000\000" "\142\000\000\000"
+ /* 0x63 */ "\143\000\000\000" "\144\000\000\000" "\145\000\000\000"
+ /* 0x66 */ "\146\000\000\000" "\147\000\000\000" "\150\000\000\000"
+ /* 0x69 */ "\151\000\000\000" "\152\000\000\000" "\153\000\000\000"
+ /* 0x6c */ "\154\000\000\000" "\155\000\000\000" "\156\000\000\000"
+ /* 0x6f */ "\157\000\000\000" "\160\000\000\000" "\161\000\000\000"
+ /* 0x72 */ "\162\000\000\000" "\163\000\000\000" "\164\000\000\000"
+ /* 0x75 */ "\165\000\000\000" "\166\000\000\000" "\167\000\000\000"
+ /* 0x78 */ "\170\000\000\000" "\171\000\000\000" "\172\000\000\000"
+ /* 0x7b */ "\173\000\000\000" "\174\000\000\000" "\175\000\000\000"
+ /* 0x7e */ "\176\000\000\000" "\177\000\000\000" "\200\000\000\000"
+ /* 0x81 */ "\201\000\000\000" "\202\000\000\000" "\203\000\000\000"
+ /* 0x84 */ "\204\000\000\000" "\205\000\000\000" "\206\000\000\000"
+ /* 0x87 */ "\207\000\000\000" "\210\000\000\000" "\211\000\000\000"
+ /* 0x8a */ "\212\000\000\000" "\213\000\000\000" "\214\000\000\000"
+ /* 0x8d */ "\215\000\000\000" "\216\000\000\000" "\217\000\000\000"
+ /* 0x90 */ "\220\000\000\000" "\221\000\000\000" "\222\000\000\000"
+ /* 0x93 */ "\223\000\000\000" "\224\000\000\000" "\225\000\000\000"
+ /* 0x96 */ "\226\000\000\000" "\227\000\000\000" "\230\000\000\000"
+ /* 0x99 */ "\231\000\000\000" "\232\000\000\000" "\233\000\000\000"
+ /* 0x9c */ "\234\000\000\000" "\235\000\000\000" "\236\000\000\000"
+ /* 0x9f */ "\237\000\000\000" "\240\000\000\000" "\241\000\000\000"
+ /* 0xa2 */ "\242\000\000\000" "\243\000\000\000" "\244\000\000\000"
+ /* 0xa5 */ "\245\000\000\000" "\246\000\000\000" "\247\000\000\000"
+ /* 0xa8 */ "\250\000\000\000" "\251\000\000\000" "\252\000\000\000"
+ /* 0xab */ "\253\000\000\000" "\254\000\000\000" "\255\000\000\000"
+ /* 0xae */ "\256\000\000\000" "\257\000\000\000" "\260\000\000\000"
+ /* 0xb1 */ "\261\000\000\000" "\262\000\000\000" "\263\000\000\000"
+ /* 0xb4 */ "\264\000\000\000" "\265\000\000\000" "\266\000\000\000"
+ /* 0xb7 */ "\267\000\000\000" "\270\000\000\000" "\271\000\000\000"
+ /* 0xba */ "\272\000\000\000" "\273\000\000\000" "\274\000\000\000"
+ /* 0xbd */ "\275\000\000\000" "\276\000\000\000" "\277\000\000\000"
+ /* 0xc0 */ "\300\000\000\000" "\301\000\000\000" "\302\000\000\000"
+ /* 0xc3 */ "\303\000\000\000" "\304\000\000\000" "\305\000\000\000"
+ /* 0xc6 */ "\306\000\000\000" "\307\000\000\000" "\310\000\000\000"
+ /* 0xc9 */ "\311\000\000\000" "\312\000\000\000" "\313\000\000\000"
+ /* 0xcc */ "\314\000\000\000" "\315\000\000\000" "\316\000\000\000"
+ /* 0xcf */ "\317\000\000\000" "\320\000\000\000" "\321\000\000\000"
+ /* 0xd2 */ "\322\000\000\000" "\323\000\000\000" "\324\000\000\000"
+ /* 0xd5 */ "\325\000\000\000" "\326\000\000\000" "\327\000\000\000"
+ /* 0xd8 */ "\330\000\000\000" "\331\000\000\000" "\332\000\000\000"
+ /* 0xdb */ "\333\000\000\000" "\334\000\000\000" "\335\000\000\000"
+ /* 0xde */ "\336\000\000\000" "\337\000\000\000" "\340\000\000\000"
+ /* 0xe1 */ "\341\000\000\000" "\342\000\000\000" "\343\000\000\000"
+ /* 0xe4 */ "\344\000\000\000" "\345\000\000\000" "\346\000\000\000"
+ /* 0xe7 */ "\347\000\000\000" "\350\000\000\000" "\351\000\000\000"
+ /* 0xea */ "\352\000\000\000" "\353\000\000\000" "\354\000\000\000"
+ /* 0xed */ "\355\000\000\000" "\356\000\000\000" "\357\000\000\000"
+ /* 0xf0 */ "\360\000\000\000" "\361\000\000\000" "\362\000\000\000"
+ /* 0xf3 */ "\363\000\000\000" "\364\000\000\000" "\365\000\000\000"
+ /* 0xf6 */ "\366\000\000\000" "\367\000\000\000" "\370\000\000\000"
+ /* 0xf9 */ "\371\000\000\000" "\372\000\000\000" "\373\000\000\000"
+ /* 0xfc */ "\374\000\000\000" "\375\000\000\000" "\376\000\000\000"
+ /* 0xff */ "\377\000\000\000"
+;
#elif BYTE_ORDER == BIG_ENDIAN
-const char _nl_C_LC_CTYPE_toupper[] =
+const char _nl_C_LC_CTYPE_toupper[1536] =
/* 0x80 */ "\000\000\000\200" "\000\000\000\201" "\000\000\000\202"
/* 0x83 */ "\000\000\000\203" "\000\000\000\204" "\000\000\000\205"
/* 0x86 */ "\000\000\000\206" "\000\000\000\207" "\000\000\000\210"
@@ -461,7 +637,7 @@ const char _nl_C_LC_CTYPE_toupper[] =
/* 0xfa */ "\000\000\000\372" "\000\000\000\373" "\000\000\000\374"
/* 0xfd */ "\000\000\000\375" "\000\000\000\376" "\000\000\000\377"
;
-const char _nl_C_LC_CTYPE_tolower[] =
+const char _nl_C_LC_CTYPE_tolower[1536] =
/* 0x80 */ "\000\000\000\200" "\000\000\000\201" "\000\000\000\202"
/* 0x83 */ "\000\000\000\203" "\000\000\000\204" "\000\000\000\205"
/* 0x86 */ "\000\000\000\206" "\000\000\000\207" "\000\000\000\210"
@@ -591,18 +767,140 @@ const char _nl_C_LC_CTYPE_tolower[] =
/* 0xfa */ "\000\000\000\372" "\000\000\000\373" "\000\000\000\374"
/* 0xfd */ "\000\000\000\375" "\000\000\000\376" "\000\000\000\377"
;
+const char _nl_C_LC_CTYPE_names[1024] =
+ /* 0x00 */ "\000\000\000\000" "\000\000\000\001" "\000\000\000\002"
+ /* 0x03 */ "\000\000\000\003" "\000\000\000\004" "\000\000\000\005"
+ /* 0x06 */ "\000\000\000\006" "\000\000\000\007" "\000\000\000\010"
+ /* 0x09 */ "\000\000\000\011" "\000\000\000\012" "\000\000\000\013"
+ /* 0x0c */ "\000\000\000\014" "\000\000\000\015" "\000\000\000\016"
+ /* 0x0f */ "\000\000\000\017" "\000\000\000\020" "\000\000\000\021"
+ /* 0x12 */ "\000\000\000\022" "\000\000\000\023" "\000\000\000\024"
+ /* 0x15 */ "\000\000\000\025" "\000\000\000\026" "\000\000\000\027"
+ /* 0x18 */ "\000\000\000\030" "\000\000\000\031" "\000\000\000\032"
+ /* 0x1b */ "\000\000\000\033" "\000\000\000\034" "\000\000\000\035"
+ /* 0x1e */ "\000\000\000\036" "\000\000\000\037" "\000\000\000\040"
+ /* 0x21 */ "\000\000\000\041" "\000\000\000\042" "\000\000\000\043"
+ /* 0x24 */ "\000\000\000\044" "\000\000\000\045" "\000\000\000\046"
+ /* 0x27 */ "\000\000\000\047" "\000\000\000\050" "\000\000\000\051"
+ /* 0x2a */ "\000\000\000\052" "\000\000\000\053" "\000\000\000\054"
+ /* 0x2d */ "\000\000\000\055" "\000\000\000\056" "\000\000\000\057"
+ /* 0x30 */ "\000\000\000\060" "\000\000\000\061" "\000\000\000\062"
+ /* 0x33 */ "\000\000\000\063" "\000\000\000\064" "\000\000\000\065"
+ /* 0x36 */ "\000\000\000\066" "\000\000\000\067" "\000\000\000\070"
+ /* 0x39 */ "\000\000\000\071" "\000\000\000\072" "\000\000\000\073"
+ /* 0x3c */ "\000\000\000\074" "\000\000\000\075" "\000\000\000\076"
+ /* 0x3f */ "\000\000\000\077" "\000\000\000\100" "\000\000\000\101"
+ /* 0x42 */ "\000\000\000\102" "\000\000\000\103" "\000\000\000\104"
+ /* 0x45 */ "\000\000\000\105" "\000\000\000\106" "\000\000\000\107"
+ /* 0x48 */ "\000\000\000\110" "\000\000\000\111" "\000\000\000\112"
+ /* 0x4b */ "\000\000\000\113" "\000\000\000\114" "\000\000\000\115"
+ /* 0x4e */ "\000\000\000\116" "\000\000\000\117" "\000\000\000\120"
+ /* 0x51 */ "\000\000\000\121" "\000\000\000\122" "\000\000\000\123"
+ /* 0x54 */ "\000\000\000\124" "\000\000\000\125" "\000\000\000\126"
+ /* 0x57 */ "\000\000\000\127" "\000\000\000\130" "\000\000\000\131"
+ /* 0x5a */ "\000\000\000\132" "\000\000\000\133" "\000\000\000\134"
+ /* 0x5d */ "\000\000\000\135" "\000\000\000\136" "\000\000\000\137"
+ /* 0x60 */ "\000\000\000\140" "\000\000\000\141" "\000\000\000\142"
+ /* 0x63 */ "\000\000\000\143" "\000\000\000\144" "\000\000\000\145"
+ /* 0x66 */ "\000\000\000\146" "\000\000\000\147" "\000\000\000\150"
+ /* 0x69 */ "\000\000\000\151" "\000\000\000\152" "\000\000\000\153"
+ /* 0x6c */ "\000\000\000\154" "\000\000\000\155" "\000\000\000\156"
+ /* 0x6f */ "\000\000\000\157" "\000\000\000\160" "\000\000\000\161"
+ /* 0x72 */ "\000\000\000\162" "\000\000\000\163" "\000\000\000\164"
+ /* 0x75 */ "\000\000\000\165" "\000\000\000\166" "\000\000\000\167"
+ /* 0x78 */ "\000\000\000\170" "\000\000\000\171" "\000\000\000\172"
+ /* 0x7b */ "\000\000\000\173" "\000\000\000\174" "\000\000\000\175"
+ /* 0x7e */ "\000\000\000\176" "\000\000\000\177" "\000\000\000\200"
+ /* 0x81 */ "\000\000\000\201" "\000\000\000\202" "\000\000\000\203"
+ /* 0x84 */ "\000\000\000\204" "\000\000\000\205" "\000\000\000\206"
+ /* 0x87 */ "\000\000\000\207" "\000\000\000\210" "\000\000\000\211"
+ /* 0x8a */ "\000\000\000\212" "\000\000\000\213" "\000\000\000\214"
+ /* 0x8d */ "\000\000\000\215" "\000\000\000\216" "\000\000\000\217"
+ /* 0x90 */ "\000\000\000\220" "\000\000\000\221" "\000\000\000\222"
+ /* 0x93 */ "\000\000\000\223" "\000\000\000\224" "\000\000\000\225"
+ /* 0x96 */ "\000\000\000\226" "\000\000\000\227" "\000\000\000\230"
+ /* 0x99 */ "\000\000\000\231" "\000\000\000\232" "\000\000\000\233"
+ /* 0x9c */ "\000\000\000\234" "\000\000\000\235" "\000\000\000\236"
+ /* 0x9f */ "\000\000\000\237" "\000\000\000\240" "\000\000\000\241"
+ /* 0xa2 */ "\000\000\000\242" "\000\000\000\243" "\000\000\000\244"
+ /* 0xa5 */ "\000\000\000\245" "\000\000\000\246" "\000\000\000\247"
+ /* 0xa8 */ "\000\000\000\250" "\000\000\000\251" "\000\000\000\252"
+ /* 0xab */ "\000\000\000\253" "\000\000\000\254" "\000\000\000\255"
+ /* 0xae */ "\000\000\000\256" "\000\000\000\257" "\000\000\000\260"
+ /* 0xb1 */ "\000\000\000\261" "\000\000\000\262" "\000\000\000\263"
+ /* 0xb4 */ "\000\000\000\264" "\000\000\000\265" "\000\000\000\266"
+ /* 0xb7 */ "\000\000\000\267" "\000\000\000\270" "\000\000\000\271"
+ /* 0xba */ "\000\000\000\272" "\000\000\000\273" "\000\000\000\274"
+ /* 0xbd */ "\000\000\000\275" "\000\000\000\276" "\000\000\000\277"
+ /* 0xc0 */ "\000\000\000\300" "\000\000\000\301" "\000\000\000\302"
+ /* 0xc3 */ "\000\000\000\303" "\000\000\000\304" "\000\000\000\305"
+ /* 0xc6 */ "\000\000\000\306" "\000\000\000\307" "\000\000\000\310"
+ /* 0xc9 */ "\000\000\000\311" "\000\000\000\312" "\000\000\000\313"
+ /* 0xcc */ "\000\000\000\314" "\000\000\000\315" "\000\000\000\316"
+ /* 0xcf */ "\000\000\000\317" "\000\000\000\320" "\000\000\000\321"
+ /* 0xd2 */ "\000\000\000\322" "\000\000\000\323" "\000\000\000\324"
+ /* 0xd5 */ "\000\000\000\325" "\000\000\000\326" "\000\000\000\327"
+ /* 0xd8 */ "\000\000\000\330" "\000\000\000\331" "\000\000\000\332"
+ /* 0xdb */ "\000\000\000\333" "\000\000\000\334" "\000\000\000\335"
+ /* 0xde */ "\000\000\000\336" "\000\000\000\337" "\000\000\000\340"
+ /* 0xe1 */ "\000\000\000\341" "\000\000\000\342" "\000\000\000\343"
+ /* 0xe4 */ "\000\000\000\344" "\000\000\000\345" "\000\000\000\346"
+ /* 0xe7 */ "\000\000\000\347" "\000\000\000\350" "\000\000\000\351"
+ /* 0xea */ "\000\000\000\352" "\000\000\000\353" "\000\000\000\354"
+ /* 0xed */ "\000\000\000\355" "\000\000\000\356" "\000\000\000\357"
+ /* 0xf0 */ "\000\000\000\360" "\000\000\000\361" "\000\000\000\362"
+ /* 0xf3 */ "\000\000\000\363" "\000\000\000\364" "\000\000\000\365"
+ /* 0xf6 */ "\000\000\000\366" "\000\000\000\367" "\000\000\000\370"
+ /* 0xf9 */ "\000\000\000\371" "\000\000\000\372" "\000\000\000\373"
+ /* 0xfc */ "\000\000\000\374" "\000\000\000\375" "\000\000\000\376"
+ /* 0xff */ "\000\000\000\377"
+;
#else
#error "BYTE_ORDER" BYTE_ORDER " not handled."
#endif
+const char _nl_C_LC_CTYPE_width[256] =
+/* 0x00 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0x10 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0x20 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0x30 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0x40 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0x50 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0x60 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0x70 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0x80 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0x90 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0xa0 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0xb0 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0xc0 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0xd0 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0xe0 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+/* 0xf0 */ "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001"
+;
-const struct locale_data _nl_C_LC_CTYPE =
+const struct locale_data _nl_C_LC_CTYPE =
{
NULL, 0, /* no file mapped */
- 5,
+ 13,
{
- _nl_C_LC_CTYPE_class,
- NULL, NULL,
- _nl_C_LC_CTYPE_toupper,
- _nl_C_LC_CTYPE_tolower
+ { string: _nl_C_LC_CTYPE_class },
+#if BYTE_ORDER == LITTLE_ENDIAN
+ { string: NULL }, { string: NULL },
+#endif
+ { string: _nl_C_LC_CTYPE_toupper },
+ { string: _nl_C_LC_CTYPE_tolower },
+ { string: NULL },
+#if BYTE_ORDER == BIG_ENDIAN
+ { string: NULL },
+#endif
+ { string: _nl_C_LC_CTYPE_class32 },
+ { string: _nl_C_LC_CTYPE_names },
+#if BYTE_ORDER == BIG_ENDIAN
+ { string: NULL },
+#endif
+ { word: 256 }, { word: 1 },
+ { string: "upper\0" "lower\0" "alpha\0" "digit\0" "xdigit\0" "space\0"
+ "print\0" "graph\0" "blank\0" "cntrl\0" "punct\0" "alnum\0" },
+ { string: "tolower\0" "toupper\0" },
+ { string: _nl_C_LC_CTYPE_width }
}
};
diff --git a/locale/C-messages.c b/locale/C-messages.c
index f59cde3bb8..6f89919f7b 100644
--- a/locale/C-messages.c
+++ b/locale/C-messages.c
@@ -1,5 +1,5 @@
/* Generated by GNU locale 0.1.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. */
@@ -11,9 +11,9 @@ const struct locale_data _nl_C_LC_MESSAGES =
NULL, 0, /* no file mapped */
4,
{
- "[yY][[:alpha:]]",
- "[nN][[:alpha:]]",
- "",
- ""
+ { string: "[yY][[:alpha:]]" },
+ { string: "[nN][[:alpha:]]" },
+ { string: "" },
+ { string: "" }
}
};
diff --git a/locale/C-monetary.c b/locale/C-monetary.c
index bf2cede799..18594225a4 100644
--- a/locale/C-monetary.c
+++ b/locale/C-monetary.c
@@ -1,5 +1,5 @@
/* Generated by GNU locale 0.1.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. */
@@ -11,20 +11,20 @@ const struct locale_data _nl_C_LC_MONETARY =
NULL, 0, /* no file mapped */
15,
{
- "",
- "",
- "",
- "",
- "\177",
- "",
- "",
- "\177",
- "\177",
- "\177",
- "\177",
- "\177",
- "\177",
- "\177",
- "\177"
+ { string: "" },
+ { string: "" },
+ { string: "" },
+ { string: "" },
+ { string: "\177" },
+ { string: "" },
+ { string: "" },
+ { string: "\177" },
+ { string: "\177" },
+ { string: "\177" },
+ { string: "\177" },
+ { string: "\177" },
+ { string: "\177" },
+ { string: "\177" },
+ { string: "\177" }
}
};
diff --git a/locale/C-numeric.c b/locale/C-numeric.c
index 248e2eb7bd..5d68a89892 100644
--- a/locale/C-numeric.c
+++ b/locale/C-numeric.c
@@ -1,5 +1,5 @@
/* Generated by GNU locale 0.1.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. */
@@ -11,8 +11,8 @@ const struct locale_data _nl_C_LC_NUMERIC =
NULL, 0, /* no file mapped */
3,
{
- ".",
- "",
- "\177"
+ { string: "." },
+ { string: "" },
+ { string: "\177" }
}
};
diff --git a/locale/C-time.c b/locale/C-time.c
index 15bf15ae46..6fb5e3ed86 100644
--- a/locale/C-time.c
+++ b/locale/C-time.c
@@ -1,5 +1,5 @@
/* Generated by GNU locale 0.1.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. */
@@ -9,51 +9,52 @@ PARTICULAR PURPOSE. */
const struct locale_data _nl_C_LC_TIME =
{
NULL, 0, /* no file mapped */
- 44,
+ 45,
{
- "Sun",
- "Mon",
- "Tue",
- "Wed",
- "Thu",
- "Fri",
- "Sat",
- "Sunday",
- "Monday",
- "Tuesday",
- "Wednesday",
- "Thursday",
- "Friday",
- "Saturday",
- "Jan",
- "Feb",
- "Mar",
- "Apr",
- "May",
- "Jun",
- "Jul",
- "Aug",
- "Sep",
- "Oct",
- "Nov",
- "Dec",
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December",
- "AM",
- "PM",
- "%a %b %d %H:%M:%S %Y",
- "%m/%d/%y",
- "%H:%M:%S",
- NULL
+ { string: "Sun" },
+ { string: "Mon" },
+ { string: "Tue" },
+ { string: "Wed" },
+ { string: "Thu" },
+ { string: "Fri" },
+ { string: "Sat" },
+ { string: "Sunday" },
+ { string: "Monday" },
+ { string: "Tuesday" },
+ { string: "Wednesday" },
+ { string: "Thursday" },
+ { string: "Friday" },
+ { string: "Saturday" },
+ { string: "Jan" },
+ { string: "Feb" },
+ { string: "Mar" },
+ { string: "Apr" },
+ { string: "May" },
+ { string: "Jun" },
+ { string: "Jul" },
+ { string: "Aug" },
+ { string: "Sep" },
+ { string: "Oct" },
+ { string: "Nov" },
+ { string: "Dec" },
+ { string: "January" },
+ { string: "February" },
+ { string: "March" },
+ { string: "April" },
+ { string: "May" },
+ { string: "June" },
+ { string: "July" },
+ { string: "August" },
+ { string: "September" },
+ { string: "October" },
+ { string: "November" },
+ { string: "December" },
+ { string: "AM" },
+ { string: "PM" },
+ { string: "%a %b %d %H:%M:%S %Y" },
+ { string: "%m/%d/%y" },
+ { string: "%H:%M:%S" },
+ { string: "%I:%M:%S %p" },
+ { string: NULL }
}
};
diff --git a/locale/Makefile b/locale/Makefile
index b180b6e672..675052aa03 100644
--- a/locale/Makefile
+++ b/locale/Makefile
@@ -13,8 +13,8 @@
# You should have received a copy of the GNU Library General Public
# License along with the GNU C Library; see the file COPYING.LIB. If
-# not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-# Cambridge, MA 02139, USA.
+# not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Makefile for locales.
@@ -24,20 +24,25 @@ subdir := locale
headers = locale.h
distribute = localeinfo.h categories.def \
$(localedef-modules:=.c) $(locale-modules:=.c) \
- $(lib-modules:=.c) config.h hash.h iso-4217.def \
- keyword.gperf keyword.h localedef.h token.h
+ $(lib-modules:=.c) config.h simple-hash.h iso-4217.def \
+ charmap-kw.gperf charmap-kw.h locfile-token.h \
+ locfile-kw.gperf locfile-kw.h linereader.h \
+ locales.h locfile.h stringtrans.h
routines = setlocale loadlocale localeconv nl_langinfo
categories = ctype messages monetary numeric time collate
aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc
-others = localedef locale
-install-bin = localedef locale
+others = localedef# locale
+install-bin = localedef# locale
extra-objs = $(localedef-modules:=.o) $(locale-modules:=.o) \
$(lib-modules:=.o)
-localedef-modules := charmap locfile-lex locfile-parse locale-ctype \
- monetary messages collate numeric
+vpath %.c programs
+vpath %.h programs
+
+localedef-modules := $(categories:%=ld-%) charmap charset linereader \
+ locfile stringtrans
locale-modules := ctypedump
-lib-modules := locfile-hash xmalloc
+lib-modules := simple-hash xmalloc xstrdup
GPERF = gperf
@@ -45,14 +50,18 @@ GPERFFLAGS = -acCgopt -k1,2,5,$$
include ../Rules
-keyword.h: keyword.gperf
- $(GPERF) $(GPERFFLAGS) $< > $@.new
+programs/%-kw.h: programs/%-kw.gperf
+ $(GPERF) $(GPERFFLAGS) -N $(@F:-kw.h=_hash) $< > $@.new
mv -f $@.new $@
$(objpfx)localedef: $(localedef-modules:%=$(objpfx)%.o)
$(objpfx)locale: $(locale-modules:%=$(objpfx)%.o)
$(objpfx)localedef $(objpfx)locale: $(lib-modules:%=$(objpfx)%.o)
-CPPFLAGS += -DLOCALE_PATH='"$(localedir)"' -DCHARMAP_PATH='"$(nlsdir)/charmap"'
+CPPFLAGS := -DLOCALE_PATH='"$(localedir)"' \
+ -DCHARMAP_PATH='"$(i18ndir)/charmap"' \
+ -DLOCSRCDIR='"$(i18ndir)/locales"' -DHAVE_CONFIG_H \
+ -Iliblib -Iprograms $(CPPFLAGS)
-CFLAGS-locfile-lex.c = -Wno-write-strings
+CFLAGS-charmap.c = -Wno-write-strings
+CFLAGS-locfile.c = -Wno-write-strings
diff --git a/locale/categories.def b/locale/categories.def
index be3c6bc549..f65140f7af 100644
--- a/locale/categories.def
+++ b/locale/categories.def
@@ -1,5 +1,5 @@
/* Definition of all available locale categories and their items. -*- C -*-
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
@@ -32,88 +32,111 @@ Cambridge, MA 02139, USA. */
program code which loads this file.
The various value types for the items are `string', `stringarray', `byte'
- and `bytearray'. These cover all possible values in the current locale
- definitions. `min' and `max' can be individually used again. */
+ `bytearray', and `word'. These cover all possible values in the current
+ locale definitions. `min' and `max' can be individually used again. */
#ifndef NO_POSTLOAD
#define NO_POSTLOAD NULL
#endif
-DEFINE_CATEGORY (LC_COLLATE, "LC_COLLATE",
- (
- { 0 } /* No data encoding yet. */
- ), NO_POSTLOAD, collate_input, NULL, NULL )
+DEFINE_CATEGORY
+(
+ LC_COLLATE, "LC_COLLATE",
+ (
+ DEFINE_ELEMENT (_NL_COLLATE_NRULES, "collate-nrules", std, word)
+ DEFINE_ELEMENT (_NL_COLLATE_RULES, "collate-rules", std, string)
+ DEFINE_ELEMENT (_NL_COLLATE_HASH_SIZE, "collate-hash-size", std, word)
+ DEFINE_ELEMENT (_NL_COLLATE_HASH_LAYERS, "collate-hash-layers", std, word)
+ DEFINE_ELEMENT (_NL_COLLATE_TABLE_EB, "collate-table-eb", std, string)
+ DEFINE_ELEMENT (_NL_COLLATE_TABLE_EL, "collate-table-el", std, string)
+ DEFINE_ELEMENT (_NL_COLLATE_UNDEFINED, "collate-undefined", std, word)
+ DEFINE_ELEMENT (_NL_COLLATE_EXTRA_EB, "collate-extra-eb", std, string)
+ DEFINE_ELEMENT (_NL_COLLATE_EXTRA_EL, "collate-extra-el", std, string)
+ ), _nl_postload_collate, collate_input, NULL, NULL)
/* The actual definition of ctype is meaningless here. It is hard coded in
the code because it has to be handled very specially. Only the names of
- the functions are important. */
-DEFINE_CATEGORY (LC_CTYPE, "LC_CTYPE",
- (
- { _NL_CTYPE_CLASS, "ctype-class", std, string },
- { _NL_CTYPE_TOUPPER_EB, "ctype-toupper-eb", std, string },
- { _NL_CTYPE_TOLOWER_EB, "ctype-tolower-eb", std, string },
- { _NL_CTYPE_TOUPPER_EL, "ctype-toupper-el", std, string },
- { _NL_CTYPE_TOLOWER_EL, "ctype-tolower-el", std, string },
- { 0 }
- ), _nl_postload_ctype,
- ctype_input, ctype_check, ctype_output )
-
-
-DEFINE_CATEGORY (LC_MONETARY, "LC_MONETARY",
- (
- { INT_CURR_SYMBOL, "int_curr_symbol", std, string },
- { CURRENCY_SYMBOL, "currency_symbol", std, string },
- { MON_DECIMAL_POINT, "mon_decimal_point", std, string },
- { MON_THOUSANDS_SEP, "mon_thousands_sep", std, string },
- { MON_GROUPING, "mon_grouping", std, bytearray },
- { POSITIVE_SIGN, "positive_sign", std, string },
- { NEGATIVE_SIGN, "negative_sign", std, string },
- { INT_FRAC_DIGITS, "int_frac_digits", std, byte },
- { FRAC_DIGITS, "frac_digits", std, byte },
- { P_CS_PRECEDES, "p_cs_precedes", std, byte, 0, 1 },
- { P_SEP_BY_SPACE, "p_sep_by_space", std, byte, 0, 2 },
- { N_CS_PRECEDES, "n_cs_precedes", std, byte, 0, 1 },
- { N_SEP_BY_SPACE, "n_sep_by_space", std, byte, 0, 2 },
- { P_SIGN_POSN, "p_sign_posn", std, byte, 0, 4 },
- { N_SIGN_POSN, "n_sign_posn", std, byte, 0, 4 },
- { 0 }
- ), NO_POSTLOAD, NULL, monetary_check, NULL )
-
-
-DEFINE_CATEGORY (LC_NUMERIC, "LC_NUMERIC",
- (
- { DECIMAL_POINT, "decimal_point", std, string },
- { THOUSANDS_SEP, "thousands_sep", std, string },
- { GROUPING, "grouping", std, bytearray },
- { 0 }
- ), NO_POSTLOAD, NULL, numeric_check, NULL)
-
-
-DEFINE_CATEGORY (LC_TIME, "LC_TIME",
- (
- { ABDAY_1, "abday", std, stringarray, 7, 7 },
- { DAY_1, "day", std, stringarray, 7, 7 },
- { ABMON_1, "abmon", std, stringarray, 12, 12 },
- { MON_1, "mon", std, stringarray, 12, 12 },
- { AM_STR, "am_pm", std, stringarray, 2, 2 },
- { D_T_FMT, "d_t_fmt", std, string },
- { D_FMT, "d_fmt", std, string },
- { T_FMT, "t_fmt", std, string },
- { T_FMT_AMPM, "t_fmt_ampm", std, string },
- { ERA, "era", opt, string },
- { ERA_YEAR, "era_year", opt, string },
- { ERA_D_FMT, "era_d_fmt", opt, string },
- { ALT_DIGITS, "alt_digits", opt, stringarray, 0, 100 },
- { 0 }
- ), NO_POSTLOAD, NULL, NULL, NULL )
-
-
-DEFINE_CATEGORY (LC_MESSAGES, "LC_MESSAGES",
- (
- { YESEXPR, "yesexpr", std, string },
- { NOEXPR, "noexpr", std, string },
- { YESSTR, "yesstr", opt, string },
- { NOSTR, "nostr", opt, string },
- { 0 }
- ), NO_POSTLOAD, NULL, messages_check, NULL )
+ the functions and the value types are important. */
+DEFINE_CATEGORY
+(
+ LC_CTYPE, "LC_CTYPE",
+ (
+ DEFINE_ELEMENT (_NL_CTYPE_CLASS, "ctype-class", std, string)
+ DEFINE_ELEMENT (_NL_CTYPE_TOUPPER_EB, "ctype-toupper-eb", std, string)
+ DEFINE_ELEMENT (_NL_CTYPE_TOLOWER_EB, "ctype-tolower-eb", std, string)
+ DEFINE_ELEMENT (_NL_CTYPE_TOUPPER_EL, "ctype-toupper-el", std, string)
+ DEFINE_ELEMENT (_NL_CTYPE_TOLOWER_EL, "ctype-tolower-el", std, string)
+ DEFINE_ELEMENT (_NL_CTYPE_NAMES_EB, "ctype-names-eb", std, string)
+ DEFINE_ELEMENT (_NL_CTYPE_NAMES_EL, "ctype-names-eb", std, string)
+ DEFINE_ELEMENT (_NL_CTYPE_HASH_SIZE, "ctype-hash-size", std, word)
+ DEFINE_ELEMENT (_NL_CTYPE_HASH_LAYERS, "ctype-hash-layers", std, word)
+ DEFINE_ELEMENT (_NL_CTYPE_CLASS_NAMES, "ctype-class-names", std, string)
+ DEFINE_ELEMENT (_NL_CTYPE_MAP_NAMES, "ctype-map-names", std, string)
+ DEFINE_ELEMENT (_NL_CTYPE_WIDTH, "ctype-width", std, bytearray)
+ ), _nl_postload_ctype, ctype_input, ctype_check, ctype_output)
+
+
+DEFINE_CATEGORY
+(
+ LC_MONETARY, "LC_MONETARY",
+ (
+ DEFINE_ELEMENT (INT_CURR_SYMBOL, "int_curr_symbol", std, string)
+ DEFINE_ELEMENT (CURRENCY_SYMBOL, "currency_symbol", std, string)
+ DEFINE_ELEMENT (MON_DECIMAL_POINT, "mon_decimal_point", std, string)
+ DEFINE_ELEMENT (MON_THOUSANDS_SEP, "mon_thousands_sep", std, string)
+ DEFINE_ELEMENT (MON_GROUPING, "mon_grouping", std, bytearray)
+ DEFINE_ELEMENT (POSITIVE_SIGN, "positive_sign", std, string)
+ DEFINE_ELEMENT (NEGATIVE_SIGN, "negative_sign", std, string)
+ DEFINE_ELEMENT (INT_FRAC_DIGITS, "int_frac_digits", std, byte)
+ DEFINE_ELEMENT (FRAC_DIGITS, "frac_digits", std, byte)
+ DEFINE_ELEMENT (P_CS_PRECEDES, "p_cs_precedes", std, byte, 0, 1)
+ DEFINE_ELEMENT (P_SEP_BY_SPACE, "p_sep_by_space", std, byte, 0, 2)
+ DEFINE_ELEMENT (N_CS_PRECEDES, "n_cs_precedes", std, byte, 0, 1)
+ DEFINE_ELEMENT (N_SEP_BY_SPACE, "n_sep_by_space", std, byte, 0, 2)
+ DEFINE_ELEMENT (P_SIGN_POSN, "p_sign_posn", std, byte, 0, 4)
+ DEFINE_ELEMENT (N_SIGN_POSN, "n_sign_posn", std, byte, 0, 4)
+ ), NO_POSTLOAD, NULL, monetary_check, NULL)
+
+
+DEFINE_CATEGORY
+(
+ LC_NUMERIC, "LC_NUMERIC",
+ (
+ DEFINE_ELEMENT (DECIMAL_POINT, "decimal_point", std, string)
+ DEFINE_ELEMENT (THOUSANDS_SEP, "thousands_sep", std, string)
+ DEFINE_ELEMENT (GROUPING, "grouping", std, bytearray)
+ ), NO_POSTLOAD, NULL, numeric_check, NULL)
+
+
+DEFINE_CATEGORY
+(
+ LC_TIME, "LC_TIME",
+ (
+ DEFINE_ELEMENT (ABDAY_1, "abday", std, stringarray, 7, 7)
+ DEFINE_ELEMENT (DAY_1, "day", std, stringarray, 7, 7)
+ DEFINE_ELEMENT (ABMON_1, "abmon", std, stringarray, 12, 12)
+ DEFINE_ELEMENT (MON_1, "mon", std, stringarray, 12, 12)
+ DEFINE_ELEMENT (AM_STR, "am_pm", std, stringarray, 2, 2)
+ DEFINE_ELEMENT (D_T_FMT, "d_t_fmt", std, string)
+ DEFINE_ELEMENT (D_FMT, "d_fmt", std, string)
+ DEFINE_ELEMENT (T_FMT, "t_fmt", std, string)
+ DEFINE_ELEMENT (T_FMT_AMPM, "t_fmt_ampm", std, string)
+ DEFINE_ELEMENT (ERA, "era", opt, string)
+ DEFINE_ELEMENT (ERA_YEAR, "era_year", opt, string)
+ DEFINE_ELEMENT (ERA_D_FMT, "era_d_fmt", opt, string)
+ DEFINE_ELEMENT (ALT_DIGITS, "alt_digits", opt, stringarray, 0, 100)
+ DEFINE_ELEMENT (ERA_D_T_FMT, "era_d_t_fmt", opt, string)
+ DEFINE_ELEMENT (ERA_T_FMT, "era_t_fmt", opt, string)
+ ), NO_POSTLOAD, NULL, NULL, NULL)
+
+
+DEFINE_CATEGORY
+(
+ LC_MESSAGES, "LC_MESSAGES",
+ (
+ DEFINE_ELEMENT (YESEXPR, "yesexpr", std, string)
+ DEFINE_ELEMENT (NOEXPR, "noexpr", std, string)
+ DEFINE_ELEMENT (YESSTR, "yesstr", opt, string)
+ DEFINE_ELEMENT (NOSTR, "nostr", opt, string)
+ ), NO_POSTLOAD, NULL, messages_check, NULL)
diff --git a/locale/charmap.c b/locale/charmap.c
deleted file mode 100644
index ad1075e5bc..0000000000
--- a/locale/charmap.c
+++ /dev/null
@@ -1,524 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <ctype.h>
-#include <errno.h>
-#include <libintl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "localedef.h"
-#include "hash.h"
-
-/* Data structure for representing charmap database. */
-struct charmap charmap_data;
-
-/* Line number in charmap file. */
-static unsigned int line_no;
-
-/* Prototypes for local functions. */
-static void read_prolog (FILE *infile);
-static unsigned long read_body (FILE *infile);
-
-
-/* Read complete table of symbolic names for character set from file. If
- this file does not exist or is not readable a default file is tried.
- If this also is not readable no character map is defined. */
-void
-charmap_read (const char *filename)
-{
- unsigned long max_char;
- long path_max = pathconf (".", _PC_PATH_MAX);
- char buf[path_max];
- FILE *infile = NULL;
-
- /* Initialize charmap data. */
- charmap_data.codeset_name = NULL;
- charmap_data.mb_cur_max = -1;
- charmap_data.mb_cur_min = -1;
- charmap_data.escape_char = '\\';
- charmap_data.comment_char = '#';
-
- if (filename != NULL)
- {
- strcpy (buf, filename);
- infile = fopen (filename, "r");
- if (infile == NULL && filename[0] != '/')
- {
- snprintf (buf, path_max, "%s/%s", CHARMAP_PATH, filename);
- infile = fopen (buf, "r");
- }
- }
- if (infile == NULL)
- {
- if (filename != NULL)
- error (0, errno, gettext ("input file `%s' not found"), filename);
-
- snprintf (buf, path_max, "%s/%s", CHARMAP_PATH, DEFAULT_CHARMAP);
- infile = fopen (buf, "r");
-
- if (infile == NULL)
- error (4, errno, gettext ("input file `%s' not found"), filename);
- }
-
- charmap_data.filename = buf;
- init_hash (&charmap_data.table, 500);
- line_no = 0;
-
- /* Read the prolog of the charmap file. */
- read_prolog (infile);
-
- /* Last works on the charmap tables global data. */
- if (charmap_data.mb_cur_max == -1)
- charmap_data.mb_cur_max = 1;
- if (charmap_data.mb_cur_min == -1)
- charmap_data.mb_cur_min = charmap_data.mb_cur_max;
-
- if ((size_t) charmap_data.mb_cur_max > sizeof (long))
- {
- error (2, 0, gettext ("program limitation: for now only upto %Zu "
- "bytes per character are allowed"), sizeof (long));
- }
-
- /* Now process all entries. */
- max_char = read_body (infile);
-
- /* We don't need the file anymore. */
- fclose (infile);
-
-
- /* Determine the optimal table size when using the simple modulo hashing
- function. */
- if (max_char >= 256)
- {
- int size;
- /* Current best values, initialized to some never reached high value. */
- int best_count = 10000;
- int best_size = 10000;
- int best_product = best_count * best_size;
-
- /* Give warning. */
- error (-1, 0, gettext ("computing character table size: this may take "
- "a while"));
-
- for (size = 256; size <= best_product; ++size)
- {
- /* Array with slot counters. */
- int cnt[size];
- /* Current character. */
- int ch;
- /* Maximal number of characters in any slot. */
- int maxcnt = 0;
- /* Product of current size and maximal count. */
- int product = 0;
- /* Iteration pointer through hashing table. */
- char *ptr = NULL;
-
- /* Initializes counters to zero. */
- memset(cnt, 0, size * sizeof (int));
-
- /* Iterate through whole hashing table. */
- while (product < best_product
- && iterate_table (&charmap_data.table, (void **) &ptr,
- (void **) &ch))
- {
- /* Increment slot counter. */
- ++cnt[ch % size];
- /* Test for current maximum. */
- if (cnt[ch % size] > maxcnt)
- {
- maxcnt = cnt[ch % size];
- product = maxcnt * size;
- }
- }
-
- if (product < best_product)
- {
- best_count = maxcnt;
- best_size = size;
- best_product = best_count * best_size;
- }
- }
-
- charmap_data.hash_size = best_size;
- charmap_data.hash_layers = best_count;
- }
- else
- {
- charmap_data.hash_size = 256;
- charmap_data.hash_layers = 1;
- }
-}
-
-
-#define SYNTAX_ERROR \
- do { error (0, 0, gettext ("%s:%u: syntax error in charmap file"), \
- charmap_data.filename, line_no); \
- goto end_of_loop; } while (0)
-
-/* Read the prolog of the charmap file until the line containing `CHARMAP'.
- All possible entries are processed. */
-static void
-read_prolog (FILE *infile)
-{
- size_t bufsize = sysconf (_SC_LINE_MAX);
- char buf[bufsize];
-
- while (1)
- {
- char *cp = buf;
- char len;
-
- /* Read the next line. */
- fgets (buf, bufsize, infile);
- len = strlen (buf);
-
- /* On EOF simply return. */
- if (len == 0 || buf[len - 1] != '\n')
- error (4, 0, gettext ("%s: unexpected end of file in charmap"),
- charmap_data.filename);
-
- /* This is the next line. */
- ++line_no;
-
- /* Comments and empty lines are ignored. */
- if (len == 1 || buf[0] == charmap_data.comment_char)
- continue;
-
- buf[len - 1] = '\0';
-
- /* Throw away leading white spaces. This is not defined in POSIX.2
- so don't do it if conformance is requested. */
- if (!posix_conformance)
- while (isspace (*cp))
- ++cp;
-
- /* If `CHARMAP' is read the prolog is over. */
- if (strncmp (cp, "CHARMAP", 7) == 0
- && (!posix_conformance || cp[7] == '\0'))
- return;
-
- /* Now it can be only one of special symbols defining the charmap
- parameters. All are beginning with '<'. */
- if (*cp != '<')
- SYNTAX_ERROR;
-
- ++cp;
- if (strncmp (cp, "code_set_name>", 14) == 0)
- {
- char *startp;
-
-#define cp_to_arg(no,pred) \
- cp += no; \
- while (isspace (*cp)) \
- ++cp; \
- if (*cp == '\0' || !pred (*cp)) \
- SYNTAX_ERROR;
-
- cp_to_arg (14,isgraph)
-
- if (charmap_data.codeset_name != NULL)
- {
- error (0, 0, gettext ("%s:%u: duplicate code set name "
- "specification"),
- charmap_data.filename, line_no);
- free (charmap_data.codeset_name);
- }
-
- startp = cp;
- while (*cp != '\0' && isgraph (*cp) && !isspace (*cp))
- ++cp;
-
- charmap_data.codeset_name = (char *) xmalloc (cp - startp + 1);
- strncpy (startp, startp, cp - startp);
- }
- else if (strncmp (cp, "mb_cur_max>", 11) == 0)
- {
- int new_val;
- cp_to_arg (11,isdigit)
-
- if (charmap_data.mb_cur_max != -1)
- error (0, 0,
- gettext ("%s:%u: duplicate definition of mb_cur_max"),
- charmap_data.filename, line_no);
-
- new_val = (int) strtol (cp, &cp, posix_conformance ? 10 : 0);
- if (new_val < 1)
- error (0, 0, gettext ("%s:%u: illegal value for mb_cur_max: %d"),
- charmap_data.filename, line_no, new_val);
- else
- charmap_data.mb_cur_max = new_val;
- }
- else if (strncmp (cp, "mb_cur_min>", 11) == 0)
- {
- int new_val;
- cp_to_arg (11,isdigit)
-
- if (charmap_data.mb_cur_max != -1)
- error (0, 0,
- gettext ("%s:%u: duplicate definition of mb_cur_min"),
- charmap_data.filename, line_no);
-
- new_val = (int) strtol (cp, &cp, posix_conformance ? 10 : 0);
- if (new_val < 1)
- error (0, 0, gettext ("%s:%u: illegal value for mb_cur_min: %d"),
- charmap_data.filename, line_no, new_val);
- else
- charmap_data.mb_cur_min = new_val;
- }
- else if (strncmp (cp, "escape_char>", 12) == 0)
- {
- cp_to_arg (12, isgraph)
- charmap_data.escape_char = *cp;
- }
- else if (strncmp (cp, "comment_char>", 13) == 0)
- {
- cp_to_arg (13, isgraph)
- charmap_data.comment_char = *cp;
- }
- else
- SYNTAX_ERROR;
- end_of_loop:
- }
-}
-#undef cp_to_arg
-
-
-static unsigned long
-read_body (FILE *infile)
-{
- unsigned long max_char = 0;
- size_t bufsize = sysconf (_SC_LINE_MAX);
- char buf[bufsize];
- char name_str[bufsize / 2];
- char code_str[bufsize / 2];
-
- while (1)
- {
- char *cp = buf;
- size_t len;
-
- /* Read the next line. */
- fgets (buf, bufsize, infile);
- len = strlen (buf);
-
- /* On EOF simply return. */
- if (len == 0)
- error (0, 0, gettext ("%s: `END CHARMAP' is missing"),
- charmap_data.filename);
-
- /* This is the next line. */
- ++line_no;
-
- if (len == bufsize - 1)
- {
- error (0, 0, gettext ("%s:%u: line too long; use `getconf "
- "LINE_MAX' to get the current maximum line"
- "length"), charmap_data.filename, line_no);
- do
- {
- fgets (buf, bufsize, infile);
- len = strlen (buf);
- }
- while (len == bufsize - 1);
- continue;
- }
-
- /* Comments and empty lines are ignored. */
- if (len == 1 || buf[0] == charmap_data.comment_char)
- continue;
-
- buf[len - 1] = '\0';
-
- /* Throw away leading white spaces. This is not defined in POSIX.2
- so don't do it if conformance is requested. */
- if (!posix_conformance)
- while (isspace (*cp))
- ++cp;
-
- if (*cp == '<')
- {
- char *end1p, *end2p, *start2p;
- size_t cnt = 0;
- unsigned long char_value = 0;
-
- if (sscanf (cp + 1, "%s %s", name_str, code_str) != 2)
- SYNTAX_ERROR;
-
- end1p = cp = name_str;
- while (*cp != '\0' && *cp != '>')
- {
- if (*cp == charmap_data.escape_char)
- if (*++cp == '\0')
- SYNTAX_ERROR;
- *end1p++ = *cp++;
- }
- if (*cp == '\0')
- /* No final '>'. Make error condition. */
- end1p = name_str;
- else
- ++cp;
-
- *end1p = '\0';
-
- if (*cp == '.' && *++cp == '.' && *++cp == '.' && *++cp == '<')
- {
- /* This might be the alternate form. */
- start2p = end2p = ++cp;
- while (*cp != '\0' && *cp != '>')
- {
- if (*cp == charmap_data.escape_char)
- if (*++cp == '\0')
- SYNTAX_ERROR;
- *end2p = *cp++;
- }
- if (*cp == '\0')
- /* NO final '>'. Make error condition. */
- end2p = start2p;
- else
- ++cp;
- }
- else
- start2p = end2p = NULL;
-
-
- if (end1p == name_str || (start2p != NULL && start2p != end2p)
- || *cp != '\0'
- || *code_str != charmap_data.escape_char)
- SYNTAX_ERROR;
-
- cp = code_str;
- do
- {
- char *begin;
- long val;
-
- switch (*++cp)
- {
- case 'd':
- val = strtol ((begin = cp + 1), &cp, 10);
- break;
- case 'x':
- val = strtol ((begin = cp + 1), &cp, 16);
- break;
- default:
- val = strtol ((begin = cp), &cp, 8);
- break;
- }
- if (begin == cp)
- SYNTAX_ERROR;
-
- if (posix_conformance && cp - begin < 2)
- error (0, 0, gettext ("%s:%u: byte constant has less than "
- "two digits"),
- charmap_data.filename, line_no);
-
- if (val < 0 || val > 255)
- {
- error (0, 0, gettext ("%s:%u: character encoding must be "
- "given in 8-bit bytes"),
- charmap_data.filename, line_no);
- goto end_of_loop;
- }
-
- if (cnt < (size_t) charmap_data.mb_cur_max)
- {
- if (cnt < sizeof (long)) /* FIXME */
- char_value = (char_value << 8) | val;
- }
- else
- {
- error (0, 0, gettext ("%s:%u: number of bytes in character "
- "definition exceeds `mb_cur_max'"),
- charmap_data.filename, line_no);
- break;
- }
- ++cnt;
- }
- while (*cp == charmap_data.escape_char);
-
- /* Ignore the rest of the line (comment). */
- if (end2p == NULL)
- {
- if (insert_entry (&charmap_data.table, name_str,
- end1p - name_str, (void *) char_value))
- error (0, 0, gettext ("%s:%u: duplicate entry"),
- charmap_data.filename, line_no);
-
- max_char = MAX (max_char, char_value);
- }
- else
- {
- char *en1, *en2, *start1p;
- long n1, n2, n;
-
- start1p = name_str;
-
- while (*start1p == *start2p && !isdigit (*start1p)
- && start1p < end1p)
- ++start1p, ++start2p;
-
- n1 = strtol (start1p, &en1, 10);
- n2 = strtol (start2p, &en2, 10);
-
- if (en1 - start1p != en2 - start2p || en1 != end1p
- || en2 != end2p)
- SYNTAX_ERROR;
-
- if (n1 > n2)
- error (0, 0, gettext ("%s:%u: starting character is bigger "
- "than last"),
- charmap_data.filename, line_no);
-
- n = n1;
- while (n <= n2)
- {
- snprintf(start1p, en1 - start1p, "%0*d", en1 - start1p, n);
-
- if (insert_entry (&charmap_data.table, name_str,
- en1 - name_str,
- (void *) (char_value + n - n1)))
- error (0, 0, gettext ("%s:%u: duplicate entry"),
- charmap_data.filename, line_no);
-
- max_char = MAX (max_char, char_value + n - n1);
- ++n;
- }
- }
- }
- else
- {
- if (strncmp (cp, "END CHARMAP", 11) == 0)
- return max_char;
-
- SYNTAX_ERROR;
- }
- end_of_loop:
- }
-
- return max_char;
-}
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
diff --git a/locale/collate.c b/locale/collate.c
deleted file mode 100644
index f06964efcb..0000000000
--- a/locale/collate.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <langinfo.h>
-#include <libintl.h>
-
-#include "localedef.h"
-#include "token.h"
-
-
-/* defined in locfile-lex.c: flag to indicate that unknown element names
- are allowed. */
-extern int reject_new_char;
-
-
-#define SYNTAX_ERROR \
- error (0, 0, gettext ("%s:%Zd: syntax error in locale definition file"), \
- locfile_data.filename, locfile_data.line_no);
-
-void
-collate_input (int token)
-{
- int read_order_start = 0;
-
- while (1)
- {
- char *ptr;
- int len;
-
- if (token == TOK_END)
- /* This is the end of the category. */
- {
- token = xlocfile_lex (&ptr, &len);
-
- if (token != _NL_NUM_LC_COLLATE)
- {
- error (0, 0, gettext ("%s:%Zd: category `%s' does not end "
- "with `END %s'"), locfile_data.filename,
- locfile_data.line_no, "LC_COLLATE", "LC_COLLATE");
- ignore_to_eol (0, 0);
- }
- else
- ignore_to_eol (0, 1);
-
- /* Start next category. */
- break;
- }
-
-#if 0
- /* Process line. */
- if (read_order_start == 0)
- /* We're still in the preambel. */
- {
- switch (token)
- {
- case TOK_COLLATING_ELEMENT:
- reject_new_char = 0;
- token = xlocfile_lex (&ptr, &len);
- reject_new_char = 1;
- if (token == TOK_CHAR)
- {
- error (0, 0, gettext ("%s:%Zd: symbolic name must not be "
- "duplicate name in charmap"),
- locfile_data.filename, locfile_data.line_no);
- ignore_to_eol (0, 0);
- break;
- }
- else if (token != TOK_ILL_CHAR)
- {
- SYNTAX_ERROR;
- ignore_to_eol (0, 0);
- break;
- }
- else
- {
- char elem_name[len + 1];
- memcpy (elem_name, ptr, len);
- elem_name[len] = '\0';
-
- /* Test whether defined in symbol table. */
-
- token = xlocfile_lex (&ptr, &len);
- if (token != TOK_FROM)
- {
- SYNTAX_ERROR;
- ignore_to_eol (0, 0);
- break;
- }
-
- token = xlocfile_lex (&ptr, &len);
- if (token != TOK_STRING)
- {
- SYNTAX_ERROR;
- ignore_to_eol (0, 0);
- break;
- }
-
- /* Insert collating element into table. */
-
- /* Rest of the line should be empty. */
- ignore_to_eol (0, 1);
- }
- break;
- case TOK_COLLATING_SYMBOL:
- reject_new_char = 0;
- token = xlocfile_lex (&ptr, &len);
- reject_new_char = 1;
- if (token == TOK_CHAR)
- {
- error (0, 0, gettext ("%s:%Zd: symbolic name must not "
- "duplicate name in charmap"),
- locfile_data.filename, locfile_data.line_no);
- ignore_to_eol (0, 0);
- break;
- }
- else if (token != TOK_ILL_CHAR)
- {
- SYNTAX_ERROR;
- ignore_to_eol (0, 0);
- break;
- }
- else
- {
- /* Test whether defined in element table. */
-
- /* Insert collating symbol into table. */
-
- ignore_to_eol (0, 1);
- }
- case TOK_ORDER_START:
- nsort_rules = 0;
-
- do
- {
- token = xlocfile_lex (&ptr, &len);
-
- if (nsort_rules == 0 && token == ENDOFLINE)
- break;
-
- if (token != TOK_BACKWARD && token != TOK_FORWARD
- && token != TOK_POSITION)
- {
- SYNTAX_ERROR;
- break;
- }
-
- switch (token)
- {
- case TOK_BACKWARD:
- if ((sort_rule[nsort_rules] & FORWARD_BIT) != 0)
- error (0, 0, gettext ("%s:%Zd: directives `forward' "
- "and `backward' are mutually "
- "exclusive"),
- locfile_data.filename, locfile_data.lineno);
- else
- sort_rule[nsort_rules] |= BACKWARD_BIT;
- break;
- case TOK_FORWARD:
- if ((sort_rule[nsort_rules] & BACKWARD_BIT) != 0)
- error (0, 0, gettext ("%s:%Zd: directives `forward' "
- "and `backward' are mutually "
- "exclusive"),
- locfile_data.filename, locfile_data.lineno);
- else
- sort_rule[nsort_rules] |= FORWARD_BIT;
- break;
- case TOK_POSITION:
- sort_rule[nsort_rules] |= POSITION_BIT;
- break;
- }
-
- ++nsort_rules;
-
-
- }
- break;
- default:
- SYNTAX_ERROR;
- ignore_to_eol (token, 0);
- }
- }
- else
- {
- }
-#endif
-
- ignore_to_eol(token,0);
- /* Get next token. */
- token = xlocfile_lex (&ptr, &len);
- }
-}
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
diff --git a/locale/config.h b/locale/config.h
deleted file mode 100644
index 65dfb33e9a..0000000000
--- a/locale/config.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* config.h used by locale and localedef programs in GNU libc.
-Copyright (C) 1995 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#ifndef _CONFIG_H
-#define _CONFIG_H
-
-#define PACKAGE "libc"
-#define VERSION __libc_version
-extern const char __libc_version[];
-
-#define DEFAULT_CHARMAP "POSIX"
-
-
-/* These are tested by xmalloc.c and error.c. */
-#define HAVE_VPRINTF 1
-#define STDC_HEADERS 1
-#define HAVE_STRERROR 1
-
-#define program_name program_invocation_name
-
-typedef unsigned short u16;
-typedef int i32;
-typedef int u32;
-
-
-/* Get the global libc configuration info. */
-#include_next <config.h>
-
-#endif /* config.h */
diff --git a/locale/hash.h b/locale/hash.h
deleted file mode 100644
index 5f60a44a5b..0000000000
--- a/locale/hash.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#ifndef _HASH_H
-#define _HASH_H
-
-#include <obstack.h>
-
-typedef struct hash_table
- {
- unsigned long size;
- unsigned long filled;
- void *first;
- void *table;
- struct obstack mem_pool;
- }
-hash_table;
-
-
-int init_hash (hash_table *htab, unsigned long init_size);
-int delete_hash(hash_table *htab);
-int insert_entry (hash_table *htab, const char *key, size_t keylen,
- void *data);
-int find_entry (hash_table *htab, const char *key, size_t keylen,
- void **result);
-
-int iterate_table (hash_table *htab, void **ptr, void **result);
-
-#endif /* hash.h */
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
-
diff --git a/locale/keyword.gperf b/locale/keyword.gperf
deleted file mode 100644
index 20941bc03d..0000000000
--- a/locale/keyword.gperf
+++ /dev/null
@@ -1,77 +0,0 @@
-%{
-/* `strncmp' is used for comparison. */
-#include <string.h>
-
-/* This file defines `enum token'. */
-#include "token.h"
-%}
-struct locale_keyword { char *name; enum token token_id; };
-%%
-END, TOK_END
-IGNORE, TOK_IGNORE
-LC_COLLATE, _NL_NUM_LC_COLLATE
-LC_CTYPE, _NL_NUM_LC_CTYPE
-LC_MESSAGES, _NL_NUM_LC_MESSAGES
-LC_MONETARY, _NL_NUM_LC_MONETARY
-LC_NUMERIC, _NL_NUM_LC_NUMERIC
-LC_TIME, _NL_NUM_LC_TIME
-UNDEFINED, TOK_UNDEFINED
-abday, ABDAY_1
-abmon, ABMON_1
-alpha, TOK_ALPHA
-alt_digits, ALT_DIGITS
-am_pm, AM_STR
-backward, TOK_BACKWARD
-blank, TOK_BLANK
-cntrl, TOK_CNTRL
-collating_element, TOK_COLLATING_ELEMENT
-collating_symbol, TOK_COLLATING_SYMBOL
-comment_char, TOK_COMMENT_CHAR
-copy, TOK_COPY
-currency_symbol, CURRENCY_SYMBOL
-d_fmt, D_FMT
-d_t_fmt, D_T_FMT
-day, DAY_1
-decimal_point, DECIMAL_POINT
-digit, TOK_DIGIT
-era, ERA
-era_d_fmt, ERA_D_FMT
-era_year, ERA_YEAR
-escape_char, TOK_ESCAPE_CHAR
-forward, TOK_FORWARD
-frac_digits, FRAC_DIGITS
-from, TOK_FROM
-graph, TOK_GRAPH
-grouping, GROUPING
-int_curr_symbol, INT_CURR_SYMBOL
-int_frac_digits, INT_FRAC_DIGITS
-lower, TOK_LOWER
-mon, MON_1
-mon_decimal_point, MON_DECIMAL_POINT
-mon_grouping, MON_GROUPING
-mon_thousands_sep, MON_THOUSANDS_SEP
-n_cs_precedes, N_CS_PRECEDES
-n_sep_by_space, N_SEP_BY_SPACE
-n_sign_posn, N_SIGN_POSN
-negative_sign, NEGATIVE_SIGN
-noexpr, NOEXPR
-nostr, NOSTR
-order_end, TOK_ORDER_END
-order_start, TOK_ORDER_START
-p_cs_precedes, P_CS_PRECEDES
-p_sep_by_space, P_SEP_BY_SPACE
-p_sign_posn, P_SIGN_POSN
-position, TOK_POSITION
-positive_sign, POSITIVE_SIGN
-print, TOK_PRINT
-punct, TOK_PUNCT
-space, TOK_SPACE
-t_fmt, T_FMT
-t_fmt_ampm, T_FMT_AMPM
-thousands_sep, THOUSANDS_SEP
-tolower, TOK_TOLOWER
-toupper, TOK_TOUPPER
-upper, TOK_UPPER
-xdigit, TOK_XDIGIT
-yesexpr, YESEXPR
-yesstr, YESSTR
diff --git a/locale/keyword.h b/locale/keyword.h
deleted file mode 100644
index 1dc442aee5..0000000000
--- a/locale/keyword.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/* C code produced by gperf version 2.5 (GNU C++ version) */
-/* Command-line: gperf -acCgopt -k1,2,5, keyword.gperf */
-/* `strncmp' is used for comparison. */
-#include <string.h>
-
-/* This file defines `enum token'. */
-#include "token.h"
-struct locale_keyword { char *name; enum token token_id; };
-
-#define TOTAL_KEYWORDS 68
-#define MIN_WORD_LENGTH 3
-#define MAX_WORD_LENGTH 17
-#define MIN_HASH_VALUE 4
-#define MAX_HASH_VALUE 140
-/* maximum key range = 137, duplicates = 0 */
-
-#ifdef __GNUC__
-inline
-#endif
-static unsigned int
-hash (register const char *str, register int len)
-{
- static const unsigned char asso_values[] =
- {
- 141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
- 141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
- 141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
- 141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
- 141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
- 141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
- 141, 141, 141, 141, 141, 141, 141, 0, 141, 65,
- 5, 0, 141, 30, 141, 141, 0, 141, 0, 95,
- 141, 141, 0, 141, 45, 10, 141, 141, 141, 141,
- 141, 141, 141, 141, 141, 5, 141, 10, 85, 0,
- 20, 0, 40, 35, 30, 10, 141, 0, 30, 15,
- 15, 0, 0, 141, 55, 0, 0, 80, 141, 15,
- 10, 0, 141, 141, 141, 141, 141, 141,
- };
- register int hval = len;
-
- switch (hval)
- {
- default:
- case 5:
- hval += asso_values[str[4]];
- case 4:
- case 3:
- case 2:
- hval += asso_values[str[1]];
- case 1:
- hval += asso_values[str[0]];
- }
- return hval;
-}
-
-#ifdef __GNUC__
-inline
-#endif
-const struct locale_keyword *
-in_word_set (register const char *str, register int len)
-{
- static const struct locale_keyword wordlist[] =
- {
- {"",}, {"",}, {"",}, {"",},
- {"copy", TOK_COPY},
- {"space", TOK_SPACE},
- {"yesstr", YESSTR},
- {"toupper", TOK_TOUPPER},
- {"position", TOK_POSITION},
- {"",},
- {"t_fmt", T_FMT},
- {"escape_char", TOK_ESCAPE_CHAR},
- {"comment_char", TOK_COMMENT_CHAR},
- {"positive_sign", POSITIVE_SIGN},
- {"",},
- {"t_fmt_ampm", T_FMT_AMPM},
- {"",},
- {"yesexpr", YESEXPR},
- {"mon", MON_1},
- {"p_sep_by_space", P_SEP_BY_SPACE},
- {"LC_NUMERIC", _NL_NUM_LC_NUMERIC},
- {"noexpr", NOEXPR},
- {"tolower", TOK_TOLOWER},
- {"p_cs_precedes", P_CS_PRECEDES},
- {"UNDEFINED", TOK_UNDEFINED},
- {"",},
- {"collating_symbol", TOK_COLLATING_SYMBOL},
- {"collating_element", TOK_COLLATING_ELEMENT},
- {"negative_sign", NEGATIVE_SIGN},
- {"",},
- {"d_fmt", D_FMT},
- {"",},
- {"mon_thousands_sep", MON_THOUSANDS_SEP},
- {"day", DAY_1},
- {"n_sep_by_space", N_SEP_BY_SPACE},
- {"digit", TOK_DIGIT},
- {"IGNORE", TOK_IGNORE},
- {"LC_TIME", _NL_NUM_LC_TIME},
- {"n_cs_precedes", N_CS_PRECEDES},
- {"",},
- {"int_curr_symbol", INT_CURR_SYMBOL},
- {"",}, {"",},
- {"thousands_sep", THOUSANDS_SEP},
- {"",},
- {"am_pm", AM_STR},
- {"xdigit", TOK_XDIGIT},
- {"",},
- {"decimal_point", DECIMAL_POINT},
- {"",},
- {"cntrl", TOK_CNTRL},
- {"p_sign_posn", P_SIGN_POSN},
- {"mon_decimal_point", MON_DECIMAL_POINT},
- {"LC_CTYPE", _NL_NUM_LC_CTYPE},
- {"",},
- {"alpha", TOK_ALPHA},
- {"",},
- {"forward", TOK_FORWARD},
- {"era", ERA},
- {"",},
- {"print", TOK_PRINT},
- {"",},
- {"mon_grouping", MON_GROUPING},
- {"era_year", ERA_YEAR},
- {"",}, {"",},
- {"n_sign_posn", N_SIGN_POSN},
- {"",},
- {"END", TOK_END},
- {"",},
- {"alt_digits", ALT_DIGITS},
- {"",},
- {"d_t_fmt", D_T_FMT},
- {"",}, {"",},
- {"nostr", NOSTR},
- {"LC_MESSAGES", _NL_NUM_LC_MESSAGES},
- {"",}, {"",}, {"",},
- {"int_frac_digits", INT_FRAC_DIGITS},
- {"",}, {"",}, {"",},
- {"era_d_fmt", ERA_D_FMT},
- {"punct", TOK_PUNCT},
- {"",}, {"",}, {"",}, {"",},
- {"lower", TOK_LOWER},
- {"",}, {"",}, {"",}, {"",},
- {"currency_symbol", CURRENCY_SYMBOL},
- {"",}, {"",},
- {"grouping", GROUPING},
- {"from", TOK_FROM},
- {"abday", ABDAY_1},
- {"",}, {"",}, {"",}, {"",},
- {"LC_COLLATE", _NL_NUM_LC_COLLATE},
- {"LC_MONETARY", _NL_NUM_LC_MONETARY},
- {"",}, {"",}, {"",}, {"",},
- {"frac_digits", FRAC_DIGITS},
- {"",}, {"",}, {"",},
- {"abmon", ABMON_1},
- {"",}, {"",},
- {"backward", TOK_BACKWARD},
- {"order_end", TOK_ORDER_END},
- {"blank", TOK_BLANK},
- {"order_start", TOK_ORDER_START},
- {"",}, {"",}, {"",},
- {"graph", TOK_GRAPH},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"",}, {"",}, {"",}, {"",}, {"",},
- {"upper", TOK_UPPER},
- };
-
- if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
- {
- register int key = hash (str, len);
-
- if (key <= MAX_HASH_VALUE && key >= 0)
- {
- register const char *s = wordlist[key].name;
-
- if (*s == *str && !strncmp (str + 1, s + 1, len - 1))
- return &wordlist[key];
- }
- }
- return 0;
-}
diff --git a/locale/langinfo.h b/locale/langinfo.h
index 245dcf8b92..af081e7614 100644
--- a/locale/langinfo.h
+++ b/locale/langinfo.h
@@ -1,5 +1,5 @@
/* nl_langinfo -- Access to locale-dependent parameters.
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -98,9 +98,25 @@ typedef enum
ERA_YEAR, /* Year in alternate era format. */
ERA_D_FMT, /* Date in alternate era format. */
ALT_DIGITS, /* Alternate symbols for digits. */
+ ERA_D_T_FMT, /* Date and time in alternate era format. */
+ ERA_T_FMT, /* Time in alternate era format. */
_NL_NUM_LC_TIME, /* Number of indices in LC_TIME category. */
+ /* LC_COLLATE category: text sorting.
+ This information is accessed by the strcoll and strxfrm functions.
+ These `nl_langinfo' names are used only internally. */
+ _NL_COLLATE_NRULES = _NL_ITEM (LC_COLLATE, 0),
+ _NL_COLLATE_RULES,
+ _NL_COLLATE_HASH_SIZE,
+ _NL_COLLATE_HASH_LAYERS,
+ _NL_COLLATE_TABLE_EB,
+ _NL_COLLATE_TABLE_EL,
+ _NL_COLLATE_UNDEFINED,
+ _NL_COLLATE_EXTRA_EB,
+ _NL_COLLATE_EXTRA_EL,
+ _NL_NUM_LC_COLLATE,
+
/* LC_CTYPE category: character classification.
This information is accessed by the functions in <ctype.h>.
These `nl_langinfo' names are used only internally. */
@@ -109,6 +125,14 @@ typedef enum
_NL_CTYPE_TOLOWER_EB,
_NL_CTYPE_TOUPPER_EL,
_NL_CTYPE_TOLOWER_EL,
+ _NL_CTYPE_CLASS32,
+ _NL_CTYPE_NAMES_EB,
+ _NL_CTYPE_NAMES_EL,
+ _NL_CTYPE_HASH_SIZE,
+ _NL_CTYPE_HASH_LAYERS,
+ _NL_CTYPE_CLASS_NAMES,
+ _NL_CTYPE_MAP_NAMES,
+ _NL_CTYPE_WIDTH,
_NL_NUM_LC_CTYPE,
/* LC_MONETARY category: formatting of monetary quantities.
@@ -144,9 +168,6 @@ typedef enum
NOSTR, /* Output string for ``no''. */
_NL_NUM_LC_MESSAGES,
- /* Stubs for unfinished categories. */
- _NL_NUM_LC_COLLATE = _NL_ITEM (LC_COLLATE, 0),
-
/* This marks the highest value used. */
_NL_NUM
} nl_item;
diff --git a/locale/lc-collate.c b/locale/lc-collate.c
index 8684f23266..911477b6bd 100644
--- a/locale/lc-collate.c
+++ b/locale/lc-collate.c
@@ -1,5 +1,5 @@
/* Define current locale data for LC_COLLATE category.
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -14,9 +14,34 @@ Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
#include "localeinfo.h"
+#include <endian.h>
_NL_CURRENT_DEFINE (LC_COLLATE);
+
+const u32_t *__collate_table;
+const u32_t *__collate_extra;
+
+
+void
+_nl_postload_collate (void)
+{
+#if BYTE_ORDER == BIG_ENDIAN
+#define bo(x) x##_EB
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define bo(x) x##_EL
+#else
+#error bizarre byte order
+#endif
+#define paste(a,b) paste1(a,b)
+#define paste1(a,b) a##b
+
+#define current(x) \
+ ((const unsigned int *) _NL_CURRENT (LC_COLLATE, paste(_NL_COLLATE_,x)))
+
+ __collate_table = current (bo (TABLE));
+ __collate_extra = current (bo (EXTRA));
+}
diff --git a/locale/lc-ctype.c b/locale/lc-ctype.c
index 2384d17a39..4b7dcc5fff 100644
--- a/locale/lc-ctype.c
+++ b/locale/lc-ctype.c
@@ -1,5 +1,5 @@
/* Define current locale data for LC_CTYPE category.
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -47,7 +47,10 @@ _nl_postload_ctype (void)
((const unsigned int *) _NL_CURRENT (LC_CTYPE, paste(_NL_CTYPE_,x)) \
+ 128)
+ extern const unsigned int *__ctype_names;
+
__ctype_b = current (unsigned short, CLASS);
__ctype_toupper = current (, bo (TOUPPER));
__ctype_tolower = current (, bo (TOLOWER));
+ __ctype_names = current (unsigned, bo (NAMES));
}
diff --git a/locale/loadlocale.c b/locale/loadlocale.c
index 7e29c97205..68f9c7a48d 100644
--- a/locale/loadlocale.c
+++ b/locale/loadlocale.c
@@ -1,5 +1,5 @@
/* Functions to read locale data files.
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -28,12 +28,31 @@ Cambridge, MA 02139, USA. */
#include "localeinfo.h"
const size_t _nl_category_num_items[] =
- {
+{
#define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
- [category] = _NL_ITEM_INDEX (_NL_NUM_##category),
+ [category] = _NL_ITEM_INDEX (_NL_NUM_##category),
#include "categories.def"
#undef DEFINE_CATEGORY
- };
+};
+
+
+#define NO_PAREN(arg, rest...) arg, ##rest
+
+#define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
+static const enum value_type _nl_value_type_##category[] = { NO_PAREN items };
+#define DEFINE_ELEMENT(element, element_name, optstd, type, rest...) \
+ [_NL_ITEM_INDEX (element)] = type,
+#include "categories.def"
+#undef DEFINE_CATEGORY
+
+static const enum value_type *_nl_value_types[] =
+{
+#define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \
+ [category] = _nl_value_type_##category,
+#include "categories.def"
+#undef DEFINE_CATEGORY
+};
+
struct locale_data *
_nl_load_locale (int category, char **name)
@@ -178,7 +197,7 @@ _nl_load_locale (int category, char **name)
}
newdata = malloc (sizeof *newdata +
- W (filedata->nstrings) * sizeof (char *));
+ W (filedata->nstrings) * sizeof (union locale_data_value));
if (! newdata)
goto puntmap;
@@ -194,7 +213,10 @@ _nl_load_locale (int category, char **name)
errno = EINVAL;
goto puntmap;
}
- newdata->strings[i] = newdata->filedata + idx;
+ if (_nl_value_types[category][i] == word)
+ newdata->values[i].word = W (*((u32_t *) (newdata->filedata + idx)));
+ else
+ newdata->values[i].string = newdata->filedata + idx;
}
__close (fd);
diff --git a/locale/locale-ctype.c b/locale/locale-ctype.c
deleted file mode 100644
index e7a1e97960..0000000000
--- a/locale/locale-ctype.c
+++ /dev/null
@@ -1,821 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <alloca.h>
-#include <fcntl.h>
-#include <libintl.h>
-#include <locale.h>
-#include <localeinfo.h>
-#include <langinfo.h>
-#include <string.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <sys/uio.h>
-
-#include "localedef.h"
-#include "token.h"
-
-/* Arrays representing ctype tables. They must be initialized for the
- right size to hold the full charmap. */
-static u16 *ctype_b;
-static i32 *names_b, *toupper_b, *tolower_b;
-
-/* For accessing the element of the (possibly sparse) array we use this
- macro. */
-#define ELEM(arr, idx) \
- (arr)[({ int h = idx % charmap_data.hash_size; \
- int n = 0; \
- while (n < charmap_data.hash_layers \
- && names_b[n * charmap_data.hash_size + h] != idx) \
- ++n; \
- if (n >= charmap_data.hash_layers) \
- error (6, 0, gettext ("internal error in %s, line %u"), \
- __FUNCTION__, __LINE__); \
- n * charmap_data.hash_size + h; })]
-
-/* The bit used for representing a special class. */
-#define BITPOS(class) ((class) - TOK_UPPER)
-#define BIT(class) (1 << BITPOS (class))
-
-/* Remember which class or conversion is already done. */
-static unsigned short class_done = 0;
-static unsigned short toupper_done = 0;
-static unsigned short tolower_done = 0;
-
-#define SYNTAX_ERROR \
- error (0, 0, gettext ("%s:%Zd: syntax error in locale definition file"), \
- locfile_data.filename, locfile_data.line_no);
-
-
-/* Prototypes for local functions. */
-static void allocate_arrays (void);
-static void set_class_defaults (void);
-static int valid_char (int ch);
-
-
-/* Read CTYPE category. The initial token is given as a parameter. */
-void
-ctype_input (int token)
-{
- char *ptr;
- int len;
-
- /* If necessary allocate arrays. */
- allocate_arrays ();
-
- while (token != TOK_END)
- {
- switch (token)
- {
- case TOK_UPPER: case TOK_LOWER: case TOK_ALPHA: case TOK_DIGIT:
- case TOK_XDIGIT: case TOK_SPACE: case TOK_PRINT: case TOK_GRAPH:
- case TOK_BLANK: case TOK_CNTRL: case TOK_PUNCT:
- {
- /* TAKE CARE: the order of the tokens in "token.h" determines
- the bit used to indicate the membership in the class. This
- also has to correspond to the values used in <ctype.h>. */
- int bit = BIT (token);
- int was_ell = 0;
- int last = -1;
-
- if ((class_done & bit) != 0)
- {
- char tmp[len + 1];
- memcpy (tmp, ptr, len);
- tmp[len] = '\0';
-
- error (0, 0, gettext ("%s:%Zd: duplicate definiton of item "
- "`%s' in category `LC_CTYPE'"),
- locfile_data.filename, locfile_data.line_no, tmp);
- }
- class_done |= bit;
-
- do
- {
- token = xlocfile_lex (&ptr, &len);
-
- if (token == TOK_ENDOFLINE)
- {
- SYNTAX_ERROR;
- break;
- }
-
- if (token == TOK_ELLIPSIS)
- {
- if (was_ell != 0 || last < 0)
- {
- error (0, 0, gettext ("%s:%Zd: illegal use of `...'"),
- locfile_data.filename, locfile_data.line_no);
- break;
- }
- was_ell = 1;
- continue;
- }
-
- if (token != TOK_CHAR)
- {
- if (token != TOK_ILL_CHAR)
- SYNTAX_ERROR;
- was_ell = 0;
- last = -1;
- continue;
- }
-
- if (len < 0 || !valid_char (len))
- {
- was_ell = 0;
- last = -1;
- continue;
- }
-
- /* We have found a valid character. Include it to
- the class' bit set. */
- if (was_ell == 0)
- {
- ELEM (ctype_b, len) |= bit;
- last = len;
- }
- else
- {
- int i;
-
- if (last > len)
- {
- error (0, 0, gettext ("%s:%Zd: lower bound of "
- "ellipsis not smaller"),
- locfile_data.filename, locfile_data.line_no);
- was_ell = 0;
- last = -1;
- continue;
- }
-
- for (i = last + 1; i <= len; ++i)
- ELEM (ctype_b, i) |= bit;
-
- last = -1;
- }
- was_ell = 0;
- }
- while ((token = locfile_lex (&ptr, &len)) == TOK_CHAR
- && len == ';');
-
- /* Rest of the line should be empty. */
- ignore_to_eol (token, 0);
- }
- break;
- case TOK_TOUPPER: case TOK_TOLOWER:
- {
- int from;
- int to = -1;
- int is_upper = token == TOK_TOUPPER;
-
- if (((is_upper ? toupper_done : tolower_done) & BIT (token)) != 0)
- error (0, 0, gettext ("%s:%Zd: duplicate definition of item "
- "`%s' in category `LC_CTYPE'"),
- locfile_data.filename, locfile_data.line_no,
- is_upper ? "toupper" : "tolower");
- (is_upper ? toupper_done : tolower_done) |= BIT (token);
-
- do
- {
- int ignore;
-
- token = xlocfile_lex (&ptr, &len);
- if (token != TOK_CHAR || len != '(')
- {
- SYNTAX_ERROR;
- break;
- }
-
- token = xlocfile_lex (&ptr, &len);
- if (token != TOK_CHAR && token != TOK_ILL_CHAR)
- {
- SYNTAX_ERROR;
- break;
- }
- from = len;
- ignore = token == TOK_ILL_CHAR;
-
- token = xlocfile_lex (&ptr, &len);
- if (token != TOK_CHAR || len != ',')
- {
- SYNTAX_ERROR;
- break;
- }
-
- token = xlocfile_lex (&ptr, &len);
- if (token != TOK_CHAR && token != TOK_ILL_CHAR)
- {
- SYNTAX_ERROR;
- break;
- }
- to = len;
- ignore |= token == TOK_ILL_CHAR;
-
- token = xlocfile_lex (&ptr, &len);
- if (token != TOK_CHAR || len != ')')
- {
- SYNTAX_ERROR;
- break;
- }
-
- if (!ignore && valid_char (from) && valid_char (to))
- /* Have a valid pair. */
- ELEM (is_upper ? toupper_b : tolower_b, from) = to;
- }
- while ((token = locfile_lex (&ptr, &len)) == TOK_CHAR
- && len == ';');
-
- /* Rest of the line should be empty. */
- ignore_to_eol (token, 1);
- }
- break;
- default:
- SYNTAX_ERROR;
- ignore_to_eol (0, 0);
- break;
- }
-
- /* Read next token. */
- token = xlocfile_lex (&ptr, &len);
- }
-
- token = xlocfile_lex (&ptr, &len);
-
- if (token != _NL_NUM_LC_CTYPE)
- {
- error (0, 0, gettext ("%s:%Zd: category `%s' does not end with "
- "`END %s'"), locfile_data.filename,
- locfile_data.line_no, "LC_CTYPE", "LC_CTYPE");
- ignore_to_eol (0, 0);
- }
- else
- ignore_to_eol (0, posix_conformance);
-}
-
-
-void
-ctype_check(void)
-{
- /* Here are a lot of things to check. See POSIX.2, table 2-6. */
- #define NCLASS 11
- static const struct
- {
- const char *name;
- const char allow[NCLASS];
- }
- valid_table[NCLASS] =
- {
- /* The order is important. See token.h for more information.
- M = Always, D = Default, - = Permitted, X = Mutually exclusive */
- [BITPOS (TOK_UPPER)] = { "upper", "--MX-XDDXXX" },
- [BITPOS (TOK_LOWER)] = { "lower", "--MX-XDDXXX" },
- [BITPOS (TOK_ALPHA)] = { "alpha", "---X-XDDXXX" },
- [BITPOS (TOK_DIGIT)] = { "digit", "XXX--XDDXXX" },
- [BITPOS (TOK_XDIGIT)] = { "xdigit", "-----XDDXXX" },
- [BITPOS (TOK_SPACE)] = { "space", "XXXXX------" },
- [BITPOS (TOK_PRINT)] = { "print", "---------X-" },
- [BITPOS (TOK_GRAPH)] = { "graph", "---------X-" },
- [BITPOS (TOK_BLANK)] = { "blank", "XXXXXM-----" },
- [BITPOS (TOK_CNTRL)] = { "cntrl", "XXXXX-XX--X" },
- [BITPOS (TOK_PUNCT)] = { "punct", "XXXXX-DD-X-" }
- };
- int ch, cls1, cls2, eq, space_char;
- u16 tmp;
-
- /* Set default value for classes not specified. */
- set_class_defaults ();
-
- /* Check according to table. */
- for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers; ++ch)
- {
- if (ch != 0 && names_b[ch] == 0)
- continue;
- tmp = ELEM (ctype_b, names_b[ch]);
- for (cls1 = 0; cls1 < NCLASS; ++cls1)
- if ((tmp & (1 << cls1)) != 0)
- for (cls2 = 0; cls2 < NCLASS; ++cls2)
- if (cls2 != cls1 && valid_table[cls1].allow[cls2] != '-')
- {
- eq = (tmp & (1 << cls2)) != 0;
- switch (valid_table[cls1].allow[cls2])
- {
- case 'M':
- if (!eq)
- error (0, 0, gettext ("character '\\%o' in class `%s' "
- "must be in class `%s'"), ch,
- valid_table[cls1].name, valid_table[cls2].name);
- break;
- case 'X':
- if (eq)
- error (0, 0, gettext ("character '\\%o' inc class `%s' "
- "must not be in class `%s'"), ch,
- valid_table[cls1].name, valid_table[cls2].name);
- break;
- case 'D':
- ELEM (ctype_b, names_b[ch]) |= 1 << cls2;
- break;
- default:
- error (5, 0, gettext ("internal error in %s, line %u"),
- __FUNCTION__, __LINE__);
- }
- }
- }
-
- /* ... and now test <SP> as a special case. */
- if (find_entry (&charmap_data.table, "SP", 2, (void **) &space_char) == 0)
- error (0, 0, gettext ("character <SP> not defined in character map"));
- else if ((tmp = BITPOS (TOK_SPACE),
- (ELEM (ctype_b, space_char) & BIT (TOK_SPACE)) == 0)
- || (tmp = BITPOS (TOK_BLANK),
- (ELEM (ctype_b, space_char) & BIT (TOK_BLANK)) == 0))
- error (0, 0, gettext ("<SP> character not in class `%s'"),
- valid_table[tmp].name);
- else if ((tmp = BITPOS (TOK_PUNCT),
- (ELEM (ctype_b, space_char) & BIT (TOK_PUNCT)) != 0)
- || (tmp = BITPOS (TOK_GRAPH),
- (ELEM (ctype_b, space_char) & BIT (TOK_GRAPH)) != 0))
- error (0, 0, gettext ("<SP> character must not be in class `%s'"),
- valid_table[tmp].name);
- else
- ELEM (ctype_b, space_char) |= BIT (TOK_PRINT);
-}
-
-
-/* These macros can change little to big endian and vice versa. */
-#define SWAP16(v) \
- ((u16) (((((unsigned short) (v)) & 0x00ff) << 8) \
- | ((((unsigned short) (v)) & 0xff00) >> 8)))
-#define SWAP32(v) \
- ((u32) (((((u32) (v)) & 0x000000ff) << 24) \
- | ((((u32) (v)) & 0x0000ff00) << 8) \
- | ((((u32) (v)) & 0x00ff0000) >> 8) \
- | ((((u32) (v)) & 0xff000000) >> 24)))
-
-
-int
-ctype_output (void)
-{
- char *path, *t;
- int ch;
- /* File descriptor for output file. */
- int fd;
- /* Magic number. */
- i32 magic = LIMAGIC (LC_CTYPE);
- /* Number of table. */
- int tables = 6;
- /* Number ints in leading information table. */
-#if 0
- i32 n = 2 + 2 * tables;
-#else
- i32 n = 5;
-#endif
- /* Values describing the character set. */
- char mb_cur_min = (char) charmap_data.mb_cur_min;
- char mb_cur_max = (char) charmap_data.mb_cur_max;
- /* Optimal size of hashing table. */
- i32 hash_size = charmap_data.hash_size;
- i32 hash_layers = charmap_data.hash_layers;
- /* Number of elements in the tables. */
- int size = hash_size * charmap_data.hash_layers;
- /* Positions of the tables. */
- i32 pos[14] =
- {
- /* No, no. We don't play towers of Hanoi. This is a more or less
- readable table of the offsets of the different strings in the
- produced file. It is seperated in three columns which represent
- the number of values with 1, 2, and 4 bytes. */
-
-#if 0
- 4 * (2 + n),
- 1 + 4 * (2 + n),
- 2 + 4 * (2 + n),
- 2 + 4 * (3 + n),
- 2 + 4 * (4 + n),
- 2 + 2 * (128 + size) + 4 * (4 + n),
- 2 + 2 * (128 + size) + 4 * ((4 + n) + (size + 128)),
- 2 + 2 * (128 + size) + 4 * ((4 + n) + 2 * (size + 128)),
- 2 + 2 * (128 + size) + 4 * ((4 + n) + 2 * (size + 128) + 1 * size),
- 2 + 2 * (128 + size) + 4 * ((5 + n) + 2 * (size + 128) + 1 * size),
- 2 + 2 * (128 + size) + 4 * ((6 + n) + 2 * (size + 128) + 1 * size),
- 2 + 2 * (2 * (128 + size)) + 4 * ((6 + n) + 2 * (size + 128) + 1 * size),
- 2 + 2 * (2 * (128 + size)) + 4 * ((6 + n) + 3 * (size + 128) + 1 * size),
- 2 + 2 * (2 * (128 + size)) + 4 * ((6 + n) + 4 * (size + 128) + 1 * size),
-#else
- 4 * (2 + n),
- 2 * (128 + size) + 4 * (2 + n),
- 2 * (128 + size) + 4 * ((2 + n) + (size + 128)),
- 2 * (128 + size) + 4 * ((2 + n) + 2 * (size + 128)),
- 2 * (128 + size) + 4 * ((2 + n) + 3 * (size + 128)),
-#endif
- };
- /* Parameter to writev. */
- struct iovec iov[11] =
- {
- { &magic, sizeof (i32) },
- { &n, sizeof (i32) },
-#if 0
- { pos, sizeof (pos) },
- { &mb_cur_min, 1 },
- { &mb_cur_max, 1 },
- { &hash_size, sizeof (i32) },
- { &hash_layers, sizeof (i32) },
-#else
- { pos, 5 * 4 },
-#endif
- { ctype_b - 128, (size + 128) * sizeof (u16) },
- { toupper_b - 128, (size + 128) * sizeof (i32) },
- { tolower_b - 128, (size + 128) * sizeof (i32) },
- { names_b, size * sizeof (i32) }
- };
- int result = 0;
-
- /* Now we can bring the representations into the right form. */
- for (ch = -128; ch < -1; ++ch)
- {
- ctype_b[ch] = ctype_b[256 + ch];
- toupper_b[ch] = toupper_b[256 + ch];
- tolower_b[ch] = tolower_b[256 + ch];
- }
- /* Set value for EOF. */
- ctype_b[-1] = 0;
- toupper_b[-1] = -1;
- tolower_b[-1] = -1;
-
- for (ch = -128; ch < size; ++ch)
- ctype_b[ch] = htons (ctype_b[ch]);
-
- /* Construct the output filename from the argument given to
- localedef on the command line. */
- path = (char *) alloca (strlen (output_path) +
- strlen (category[LC_CTYPE].name) + 1);
- t = stpcpy (path, output_path);
- strcpy (t, category[LC_CTYPE].name);
-
- fd = creat (path, 0666);
- if (fd == -1)
- {
- error (0, 0, gettext ("cannot open output file `%s': %m"), path);
- result = 1;
- }
- else
- {
- int idx;
-
-#if 0
- if (writev (fd, iov, 10) == -1)
-#else
- if (writev (fd, iov, 6) == -1)
-#endif
- {
- error (0, 0, gettext ("cannot write output file `%s': %m"), path);
- result = 1;
- goto close_and_return;
- }
-
- /* Now we have to write the three tables with different endianess. */
- hash_size = SWAP32 (hash_size);
- for (idx = -128; idx < size; ++idx)
- {
- ctype_b[idx] = SWAP16 (ctype_b[idx]);
- toupper_b[idx] = SWAP32 (toupper_b[idx]);
- tolower_b[idx] = SWAP32 (tolower_b[idx]);
- if (idx >= 0)
- names_b[idx] = SWAP32 (names_b[idx]);
- }
-
-#if 0
- if (writev (fd, iov + 5, 6) == -1)
-#else
- if (writev (fd, iov + 3, 2) == -1)
-#endif
- {
- error (0, 0, gettext ("cannot write output file `%s': %m"), path);
- result = 1;
- }
-
- close_and_return:
- close (fd);
- }
-
- return result;
-}
-
-
-/* If necessary allocate the memory for the arrays according to the
- current character map. */
-static void
-allocate_arrays (void)
-{
- /* Init ctype data structures. */
- if (ctype_b == NULL)
- /* All data structures are not initialized yet. */
- {
- /* You wonder about this amount of memory? This is only because
- some users do not manage to address the array with unsigned
- values or data types with range >= 256. '\200' would result
- in the array index -128. To help these poor people we
- duplicate the entries for 128 upto 255 below the entry for \0. */
- int ch, h, n;
- char *ptr;
- int size = charmap_data.hash_size * charmap_data.hash_layers;
-
- ctype_b = xmalloc ((size - (-128)) * sizeof (u16));
- bzero (ctype_b, (size - (-128)) * sizeof (u16));
- ctype_b += 128;
-
-
- names_b = xmalloc (size * sizeof (i32));
- bzero (names_b, size * sizeof (i32));
-
- toupper_b = xmalloc ((size - (-128)) * sizeof (i32));
- bzero (toupper_b, (size - (-128)) * sizeof (i32));
- toupper_b += 128;
-
- tolower_b = xmalloc ((size - (-128)) * sizeof (i32));
- bzero (tolower_b, (size - (-128)) * sizeof (i32));
- tolower_b += 128;
-
- ptr = NULL;
- /* Mark the place of the NUL character as occupied. */
- names_b[0] = 1;
-
- while (iterate_table (&charmap_data.table, (void **) &ptr,
- (void **) &ch))
- {
- /* We already handled the NUL character. */
- if (ch == 0)
- continue;
-
- h = ch % charmap_data.hash_size;
- n = 0;
- while (names_b[h + n * charmap_data.hash_size] != 0)
- ++n;
-
- names_b[h + n * charmap_data.hash_size] = ch;
- toupper_b[h + n * charmap_data.hash_size] = ch;
- tolower_b[h + n * charmap_data.hash_size] = ch;
- }
- /* Correct the value for NUL character. */
- names_b[0] = 0;
- }
-}
-
-static void
-set_class_defaults (void)
-{
- /* These function defines the default values for the classes and conversions
- according to POSIX.2 2.5.2.1.
- It may seem that the order of these if-blocks is arbitrary but it is NOT.
- Don't move them unless you know what you do! */
-
- void set_default (int bit, int from, int to)
- {
- char tmp[4];
- int ch;
- /* Define string. */
- strcpy (tmp, "<?>");
-
- for (ch = from; ch <= to; ++ch)
- {
- int code;
- tmp[1] = ch;
-
- code = find_char (tmp + 1, 1);
- if (code == -1)
- error (5, 0, gettext ("character `%s' not defined while needed "
- "as default value"), tmp);
- ELEM (ctype_b, code) |= bit;
- }
- }
-
- /* If necessary allocate arrays. */
- allocate_arrays ();
-
- /* Set default values if keyword was not present. */
- if ((class_done & BIT (TOK_UPPER)) == 0)
- /* "If this keyword [lower] is not specified, the lowercase letters
- `A' through `Z', ..., shall automatically belong to this class,
- with implementation defined character values." */
- set_default (BIT (TOK_UPPER), 'A', 'Z');
-
- if ((class_done & BIT (TOK_LOWER)) == 0)
- /* "If this keyword [lower] is not specified, the lowercase letters
- `a' through `z', ..., shall automatically belong to this class,
- with implementation defined character values." */
- set_default (BIT (TOK_LOWER), 'a', 'z');
-
- if ((class_done & BIT (TOK_DIGIT)) == 0)
- /* "If this keyword [digit] is not specified, the digits `0' through
- `9', ..., shall automatically belong to this class, with
- implementation-defined character values." */
- set_default (BIT (TOK_DIGIT), '0', '9');
-
- if ((class_done & BIT (TOK_SPACE)) == 0)
- /* "If this keyword [space] is not specified, the characters <space>,
- <form-feed>, <newline>, <carriage-return>, <tab>, and
- <vertical-tab>, ..., shall automatically belong to this class,
- with implementtation-defined character values." */
- {
- int code;
-
- code = find_char ("space", 5);
- if (code == -1)
- error (5, 0, gettext ("character `%s' not defined while needed as "
- "default value"), "<space>");
- ELEM (ctype_b, code) |= BIT (TOK_SPACE);
-
- code = find_char ("form-feed", 9);
- if (code == -1)
- error (5, 0, gettext ("character `%s' not defined while needed as "
- "default value"), "<form-feed>");
- ELEM (ctype_b, code) |= BIT (TOK_SPACE);
-
- code = find_char ("newline", 7);
- if (code == -1)
- error (5, 0, gettext ("character `%s' not defined while needed as "
- "default value"), "<newline>");
- ELEM (ctype_b, code) |= BIT (TOK_SPACE);
-
- code = find_char ("carriage-return", 15);
- if (code == -1)
- error (5, 0, gettext ("character `%s' not defined while needed as "
- "default value"), "<carriage-return>");
- ELEM (ctype_b, code) |= BIT (TOK_SPACE);
-
- code = find_char ("tab", 3);
- if (code == -1)
- error (5, 0, gettext ("character `%s' not defined while needed as "
- "default value"), "<tab>");
- ELEM (ctype_b, code) |= BIT (TOK_SPACE);
-
- code = find_char ("vertical-tab", 11);
- if (code == -1)
- error (5, 0, gettext ("character `%s' not defined while needed as "
- "default value"), "<vertical-tab>");
- ELEM (ctype_b, code) |= BIT (TOK_SPACE);
- }
-
- if ((class_done & BIT (TOK_XDIGIT)) == 0)
- /* "If this keyword is not specified, the digits `0' to `9', the
- uppercase letters `A' through `F', and the lowercase letters `a'
- through `f', ..., shell automatically belong to this class, with
- implementation defined character values." */
- {
- if ((class_done & BIT (TOK_XDIGIT)) == 0)
- set_default (BIT (TOK_XDIGIT), '0', '9');
-
- if ((class_done & BIT (TOK_XDIGIT)) == 0)
- set_default (BIT (TOK_XDIGIT), 'A', 'F');
-
- if ((class_done & BIT (TOK_XDIGIT)) == 0)
- set_default (BIT (TOK_XDIGIT), 'a', 'f');
- }
-
- if ((class_done & BIT (TOK_BLANK)) == 0)
- /* "If this keyword [blank] is unspecified, the characters <space> and
- <tab> shall belong to this character class." */
- {
- int code;
-
- code = find_char ("space", 5);
- if (code == -1)
- error (5, 0, gettext ("character `%s' not defined while needed as "
- "default value"), "<space>");
- ELEM (ctype_b, code) |= BIT (TOK_BLANK);
-
- code = find_char ("tab", 3);
- if (code == -1)
- error (5, 0, gettext ("character `%s' not defined while needed as "
- "default value"), "<tab>");
- ELEM (ctype_b, code) |= BIT (TOK_BLANK);
- }
-
- if ((class_done & BIT (TOK_GRAPH)) == 0)
- /* "If this keyword [graph] is not specified, characters specified for
- the keywords `upper', `lower', `alpha', `digit', `xdigit' and `punct',
- shall belong to this character class." */
- {
- int ch;
- unsigned short int mask = BIT (TOK_UPPER) | BIT (TOK_LOWER) |
- BIT (TOK_ALPHA) | BIT (TOK_DIGIT) | BIT (TOK_XDIGIT) | BIT (TOK_PUNCT);
-
- for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
- ++ch)
- {
- if (ch != 0 && names_b[ch] == 0)
- continue;
- if ((ELEM (ctype_b, names_b[ch]) & mask) != 0)
- ELEM (ctype_b, names_b[ch]) |= BIT (TOK_GRAPH);
- }
- }
-
- if ((class_done & BIT (TOK_PRINT)) == 0)
- /* "If this keyword [print] is not provided, characters specified for
- the keywords `upper', `lower', `alpha', `digit', `xdigit', `punct',
- and the <space> character shall belong to this character class." */
- {
- int ch;
- int space = find_char ("space", 5);
- unsigned short int mask = BIT (TOK_UPPER) | BIT (TOK_LOWER) |
- BIT (TOK_ALPHA) | BIT (TOK_DIGIT) | BIT (TOK_XDIGIT) | BIT (TOK_PUNCT);
-
- if (space == -1)
- error (5, 0, gettext ("character `%s' not defined while needed as "
- "default value"), "<space>");
-
- for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
- ++ch)
- {
- if (ch != 0 && names_b[ch] == 0)
- continue;
- if ((ELEM (ctype_b, names_b[ch]) & mask) != 0)
- ELEM (ctype_b, names_b[ch]) |= BIT (TOK_PRINT);
- }
- ELEM (ctype_b, space) |= BIT (TOK_PRINT);
- }
-
- if (toupper_done == 0)
- /* "If this keyword [toupper] is not spcified, the lowercase letters
- `a' through `z', and their corresponding uppercase letters `A' to
- `Z', ..., shall automatically be included, with implementation-
- defined character values." */
- {
- char tmp[4];
- int ch;
-
- strcpy (tmp, "<?>");
-
- for (ch = 'a'; ch <= 'z'; ++ch)
- {
- int code_to, code_from;
-
- tmp[1] = ch;
- code_from = find_char (tmp + 1, 1);
- if (code_from == -1)
- error (5, 0, gettext ("character `%s' not defined while needed "
- "as default value"), tmp);
-
- /* This conversion is implementation defined. */
- tmp[1] = ch + ('A' - 'a');
- code_to = find_char (tmp + 1, 1);
- if (code_to == -1)
- error (5, 0, gettext ("character `%s' not defined while needed "
- "as default value"), tmp);
-
- ELEM (toupper_b, code_from) = code_to;
- }
- }
-
- if (tolower_done == 0)
- /* "If this keyword [tolower] is not specified, the mapping shall be
- the reverse mapping of the one specified to `toupper'." */
- {
- int ch;
-
- for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
- ++ch)
- {
- if (ch != 0 && names_b[ch] == 0)
- continue;
-
- if (toupper_b[ch] != names_b[ch])
- ELEM (tolower_b, toupper_b[ch]) = names_b[ch];
- }
- }
-}
-
-
-/* Test whether the given character is valid for the current charmap. */
-static int
-valid_char (int ch)
-{
- /* FIXME: this assumes 32-bit integers. */
- int ok = ch >= 0
- && (charmap_data.mb_cur_max < 4
- ? ch < 1 << (8 * charmap_data.mb_cur_max) : 1);
-
- return ok;
-}
-
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
diff --git a/locale/localedef.c b/locale/localedef.c
deleted file mode 100644
index 56ec1a2f6d..0000000000
--- a/locale/localedef.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <getopt.h>
-#include <libintl.h>
-#include <locale.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include "error.h"
-
-#include "localedef.h"
-
-/* The charmap file used. If none given DEFAULT_CHARMAP is used. */
-static char *charmap_file;
-
-/* If set output is always written, even when warning are given. */
-static int force_output;
-
-/* The input file name. */
-static char *input_file;
-
-/* Path leading to the destination directory for the produced files. */
-char *output_path;
-
-/* If this is defined be POSIX conform. */
-int posix_conformance;
-
-/* If not zero give a lot more messages. */
-int verbose;
-
-/* Long options. */
-static const struct option long_options[] =
- {
- { "charmap", required_argument, NULL, 'f' },
- { "debug", no_argument, NULL, 'd' },
- { "help", no_argument, NULL, 'h' },
- { "force", no_argument, NULL, 'c' },
- { "inputfile", required_argument, NULL, 'i' },
- { "posix", no_argument, &posix_conformance, 1 },
- { "verbose", no_argument, &verbose, 1},
- { "version", no_argument, NULL, 'V' },
- { NULL, 0, NULL, 0 }
- };
-
-
-/* Prototypes for local functions. */
-static void usage (int status) __attribute__ ((noreturn));
-static int construct_output_path (const char *path);
-
-int
-main(int argc, char *argv[])
-{
- int optchar;
- int cannot_write;
- int do_help = 0;
- int do_version = 0;
-
- /* Set initial values for global varaibles. */
- charmap_file = NULL;
- force_output = 0;
- input_file = 0;
- posix_conformance = getenv ("POSIXLY_CORRECT") != NULL;
- verbose = 0;
-
- /* Set locale. Do not set LC_ALL because the other categories must
- not be affected (acccording to POSIX.2). */
- setlocale (LC_MESSAGES, "");
- setlocale (LC_CTYPE, "");
-
- /* Initialize the message catalog. */
- textdomain (PACKAGE);
-
- while ((optchar = getopt_long (argc, argv, "cdf:hi:vV", long_options, NULL))
- != EOF)
- switch (optchar)
- {
- case '\0':
- break;
- case 'c':
- force_output = 1;
- break;
- case 'f':
- if (charmap_file != NULL)
- error (0, 0, gettext ("\"%s %s\" overwrites old option \"%s\""),
- "-f", optarg, charmap_file);
- charmap_file = optarg;
- break;
- case 'h':
- do_help = 1;
- break;
- case 'i':
- if (input_file != NULL)
- error (0, 0, gettext ("\"%s %s\" overwrites old option \"%s\""),
- "-i", optarg, input_file);
- input_file = optarg;
- break;
- case 'v':
- verbose = 1;
- break;
- case 'V':
- do_version = 1;
- break;
- default:
- usage (4);
- break;
- }
-
- /* POSIX.2 requires to be verbose about missing characters in the
- character map. */
- verbose |= posix_conformance;
-
- /* Version information is requested. */
- if (do_version)
- {
- fprintf (stderr, "GNU %s %s\n", PACKAGE, VERSION);
- exit (EXIT_SUCCESS);
- }
-
- /* Help is requested. */
- if (do_help)
- usage (0);
-
- if (argc - optind != 1)
- /* We need exactly one non-option parameter. */
- usage (4);
-
- /* The parameter describes the output path of the constructed files.
- If the files cannot be written return a non-zero value. */
- cannot_write = construct_output_path (argv[optind]);
-
- /* Now that the parameters are processed we have to reset the local
- ctype locale. (POSIX.2 4.35.5.2) */
- setlocale (LC_CTYPE, "POSIX");
-
- /* Look whether the system really allows locale definitions. */
- if (sysconf (_SC_2_LOCALEDEF) < 0)
- error (3, 0,
- gettext ("warning: system does not define `_POSIX2_LOCALEDEF'"));
-
- /* Process charmap file. */
- charmap_read (charmap_file);
-
- /* Now read the locale file. */
- locfile_read (input_file);
-
- /* Check all categories for consistency. */
- categories_check ();
-
- /* We are now able to write the data files. If warning were given we
- do it only if it is explicitly requested (--force). */
- if (error_message_count == 0 || force_output != 0)
- if (cannot_write != 0)
- error (0, 0, gettext ("cannot write output file `%s': %s"),
- output_path, strerror (cannot_write));
- else
- categories_write ();
- else
- error (0, 0,
- gettext ("no output file produced because warning were issued"));
-
- exit (EXIT_SUCCESS);
-}
-
-
-/* Display usage information and exit. */
-static void
-usage(int status)
-{
- if (status != EXIT_SUCCESS)
- fprintf (stderr, gettext ("Try `%s --help' for more information.\n"),
- program_invocation_name);
- else
- printf(gettext ("\
-Usage: %s [OPTION]... name\n\
-Mandatory arguments to long options are mandatory for short options too.\n\
- -c, --force create output even if warning messages have been issued\n\
- -h, --help display this help and exit\n\
- -V, --version output version information and exit\n\
-\n\
- -i, --inputfile=FILE source definitions are found in FILE\n\
- -f, --charmap=FILE symbolic character names defined in FILE\n\
-\n\
- -v, --verbose print more messages\n\
- --posix be strictly POSIX conform\n\
-\n\
-System's directory for character maps: %s\n\
- locale files : %s\n\
-"), program_invocation_name, CHARMAP_PATH, LOCALE_PATH);
-
- exit (status);
-}
-
-
-/* The parameter to localedef describes the output path. If it does
- contain a '/' character it is a relativ path. Otherwise it names the
- locale this definition is for. */
-static int
-construct_output_path (const char *path)
-{
- int result = 0;
-
- if (strchr (path, '/') == NULL)
- {
- /* This is a system path. */
- int path_max_len = pathconf (LOCALE_PATH, _PC_PATH_MAX) + 1;
- output_path = (char *) xmalloc (path_max_len);
-
- snprintf (output_path, path_max_len, "%s/%s", LOCALE_PATH, path);
- }
- else
- {
- char *t;
- /* This is a user path. */
- output_path = malloc (strlen (path) + 2);
- t = stpcpy (output_path, path);
- *t = '\0';
- }
-
- if (euidaccess (output_path, W_OK) == -1)
- /* Perhaps the directory does not exist now. Try to create it. */
- if (errno == ENOENT)
- {
- if (mkdir (output_path, 0777) == -1)
- result = errno;
- }
- else
- result = errno;
-
- if (result == 0)
- strcat (output_path, "/");
-
- return result;
-}
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
diff --git a/locale/localedef.h b/locale/localedef.h
deleted file mode 100644
index 5958a9c5d2..0000000000
--- a/locale/localedef.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#ifndef _LOCALEDEF_H
-#define _LOCALEDEF_H 1
-
-#define __need_wchar_t
-#include <stddef.h>
-
-#include "config.h"
-
-#include "hash.h"
-
-
-/* Needed always. */
-#define MAX(a, b) ({typeof (a) _a = (a); typeof (b) _b = (b); \
- _a > _b ? _a : _b; })
-#define MIN(a, b) ({typeof (a) _a = (a); typeof (b) _b = (b); \
- _a < _b ? _a : _b; })
-
-/* Determine number of elements in ARR. */
-#define NELEMS(arr) ((sizeof (arr)) / (sizeof (arr[0])))
-
-/* I simply love these GCC features ... :) */
-#define NO_PAREN(arg, rest...) arg, ##rest
-
-
-/* The character set used in the locale is defined in a character map file.
- The information of the file is stored in the following struct. */
-struct charmap
- {
- char *filename;
- char *codeset_name;
- int mb_cur_min;
- int mb_cur_max;
- char escape_char;
- char comment_char;
- hash_table table;
- int hash_size;
- int hash_layers;
- };
-
-/* Data structure for representing charmap database. */
-extern struct charmap charmap_data;
-
-
-/* We can map the types of the entries into four categories. */
-enum value_type { none, string, stringarray, byte, bytearray, integer };
-
-/* Definition of the data structure which represents a category and its
- items. */
-struct category
-{
- int cat_id;
- const char *name;
- size_t number;
- struct cat_item
- {
- int item_id;
- const char *name;
- enum { std, opt } status;
- enum value_type value_type;
- int min;
- int max;
- } *item_desc;
- char **item_value;
- void (*infct)(int);
- void (*checkfct)(void);
- int (*outfct)(void);
- int filled;
- char *copy_locale;
-};
-
-/* This a the structure which contains all information about all
- categories. */
-extern struct category category[];
-
-
-/* The function used to load the contents of a charmap file into the
- the global variable `charmap_data'. */
-void charmap_read (const char *filename);
-
-/* Find a character constant given by its name in the hash table. */
-static inline wchar_t find_char (const char *name, size_t len)
-{
- wchar_t retval;
- if (find_entry (&charmap_data.table, name, len, (void **) &retval) != 0)
- return retval;
- else
- return -1;
-}
-
-/* Path to the directory the output files are written in. */
-extern char *output_path;
-
-/* If this is defined be POSIX conform. */
-extern int posix_conformance;
-
-/* If not zero give a lot more messages. */
-extern int verbose;
-
-/* This structure contains all informations about the status of of
- reading the locale definition file. */
-struct locfile_data
- {
- const char *filename;
- char escape_char;
- char comment_char;
- size_t bufsize;
- char *buf;
- char *strbuf;
- size_t buf_ptr;
- int continue_line;
- size_t returned_tokens;
- size_t line_no;
- };
-
-/* The status variable. */
-extern struct locfile_data locfile_data;
-
-/* Open the locale definition file. */
-void locfile_open (const char *fname);
-
-/* Return the next token from the locale definition file. */
-int locfile_lex (char **token, int *token_len);
-/* Dito, but check for EOF. */
-int xlocfile_lex (char **token, int *token_len);
-
-/* Ignore the rest of the line. First TOKEN given if != 0. Warn about
- anything other than end of line if WARN_FLAG nonzero. */
-void ignore_to_eol (int token, int warn_flag);
-
-/* Code a character with UTF-8 if the character map has multi-byte
- characters. */
-int char_to_utf (char *buf, int char_val);
-
-
-/* Read the locale defintion file FNAME and fill the appropriate
- data structures. */
-void locfile_read (const char *fname);
-
-/* Check categories for consistency. */
-void categories_check (void);
-
-/* Write out the binary representation of the category data. */
-void categories_write (void);
-
-
-/* Treat reading the LC_COLLATE definition. */
-void collate_input (int token);
-
-/* Treat reading the LC_CTYPE definition. */
-void ctype_input (int token);
-void ctype_check (void);
-int ctype_output (void);
-
-/* Treat reading the LC_MONETARY definition. */
-void monetary_check (void);
-
-/* Treat reading the LC_MESSAGES definition. */
-void messages_check (void);
-
-/* Treat reading the LC_NUMERIC definition. */
-void numeric_check (void);
-
-
-/* Print an error message, possibly with NLS. */
-void error (int status, int errnum, const char *format, ...)
- __attribute__ ((format (printf, 3, 4)));
-
-/* Library functions. */
-void *xmalloc (size_t n);
-void *xcalloc (size_t n, size_t s);
-void *xrealloc (void *p, size_t n);
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
-#endif /* _LOCALEDEF_H */
diff --git a/locale/localeinfo.h b/locale/localeinfo.h
index 4199bf7a1b..a3049a51dd 100644
--- a/locale/localeinfo.h
+++ b/locale/localeinfo.h
@@ -1,5 +1,5 @@
/* localeinfo.h -- declarations for internal libc locale interfaces
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -25,17 +25,51 @@ Cambridge, MA 02139, USA. */
#include <sys/types.h>
/* Magic number at the beginning of a locale data file for CATEGORY. */
-#define LIMAGIC(category) (0x051472CA ^ (category))
+#define LIMAGIC(category) (0x960316de ^ (category))
+
+/* Two special weight constants for the collation data. */
+#define FORWARD_CHAR 0xfffffffd
+#define ELLIPSIS_CHAR 0xfffffffe
+#define IGNORE_CHAR 0xffffffff
/* Structure describing locale data in core for a category. */
struct locale_data
- {
- const char *filedata; /* Region mapping the file data. */
- off_t filesize; /* Size of the file (and the region). */
+{
+ const char *filedata; /* Region mapping the file data. */
+ off_t filesize; /* Size of the file (and the region). */
- unsigned int nstrings; /* Number of strings below. */
- const char *strings[0]; /* Items, usually pointers into `filedata'. */
- };
+ unsigned int nstrings; /* Number of strings below. */
+ union locale_data_value
+ {
+ const char *string;
+ unsigned int word;
+ }
+ values[0]; /* Items, usually pointers into `filedata'. */
+};
+
+/* We know three kinds of collation sorting rules. */
+enum coll_sort_rule
+{
+ illegal_0__,
+ sort_forward,
+ sort_backward,
+ illegal_3__,
+ sort_position,
+ sort_forward_position,
+ sort_backward_position,
+ sort_mask
+};
+
+/* We can map the types of the entries into four categories. */
+enum value_type
+{
+ none,
+ string,
+ stringarray,
+ byte,
+ bytearray,
+ word
+};
/* For each category declare the variable for the current locale data. */
@@ -49,7 +83,11 @@ extern const struct locale_data * *const _nl_current[LC_ALL];
/* Extract the current CATEGORY locale's string for ITEM. */
#define _NL_CURRENT(category, item) \
- (_nl_current_##category->strings[_NL_ITEM_INDEX (item)])
+ (_nl_current_##category->values[_NL_ITEM_INDEX (item)].string)
+
+/* Extract the current CATEGORY locale's word for ITEM. */
+#define _NL_CURRENT_WORD(category, item) \
+ (_nl_current_##category->values[_NL_ITEM_INDEX (item)].word)
/* This is used in lc-CATEGORY.c to define _nl_current_CATEGORY. */
#define _NL_CURRENT_DEFINE(category) \
@@ -65,4 +103,11 @@ extern struct locale_data *_nl_load_locale (int category, char **name);
extern void _nl_free_locale (struct locale_data *);
+/* XXX For now. */
+typedef unsigned int u32_t;
+
+/* Global variables for LC_COLLATE category data. */
+extern const u32_t *__collate_table;
+extern const u32_t *__collate_extra;
+
#endif /* localeinfo.h */
diff --git a/locale/locfile-hash.c b/locale/locfile-hash.c
deleted file mode 100644
index d977822664..0000000000
--- a/locale/locfile-hash.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <obstack.h>
-#include <stdlib.h>
-#include <string.h>
-#include <values.h>
-
-#include "hash.h"
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
-void *xmalloc (size_t n);
-
-typedef struct hash_entry
- {
- int used;
- char *key;
- void *data;
- struct hash_entry *next;
- }
-hash_entry;
-
-/* Prototypes for local functions. */
-static size_t lookup (hash_table *htab, const char *key, size_t keylen,
- unsigned long hval);
-static unsigned long compute_hashval(const char *key, size_t keylen);
-static unsigned long next_prime(unsigned long seed);
-static int is_prime(unsigned long candidate);
-
-
-int
-init_hash(hash_table *htab, unsigned long init_size)
-{
- /* We need the size to be a prime. */
- init_size = next_prime (init_size);
-
- /* Initialize the data structure. */
- htab->size = init_size;
- htab->filled = 0;
- htab->first = NULL;
- htab->table = calloc (init_size + 1, sizeof (hash_entry));
- obstack_init (&htab->mem_pool);
-
- return htab->table == NULL;
-}
-
-
-int
-delete_hash(hash_table *htab)
-{
- free (htab->table);
- obstack_free (&htab->mem_pool, NULL);
- return 0;
-}
-
-
-int
-insert_entry (hash_table *htab, const char *key, size_t keylen, void *data)
-{
- unsigned long hval = compute_hashval (key, keylen);
- hash_entry *table = (hash_entry *) htab->table;
- size_t idx = lookup (htab, key, keylen, hval);
-
- if (table[idx].used)
- /* We don't want to overwrite the old value. */
- return 1;
- else
- {
- hash_entry **p;
-
- /* An empty bucket has been found. */
- table[idx].used = hval;
- table[idx].key = obstack_copy0 (&htab->mem_pool, key, keylen);
- table[idx].data = data;
-
- /* List the new value in the ordered list. */
- for (p = (hash_entry **) &htab->first; *p != NULL && (*p)->data < data;
- p = &(*p)->next);
- if (*p == NULL || (*p)->data > data)
- /* Insert new value in the list. */
- {
- table[idx].next = *p;
- *p = &table[idx];
- }
-
- ++htab->filled;
- if (100 * htab->filled > 90 * htab->size)
- {
- /* Resize the table. */
- unsigned long old_size = htab->size;
-
- htab->size = next_prime (htab->size * 2);
- htab->filled = 0;
- htab->first = NULL;
- htab->table = calloc (htab->size, sizeof (hash_entry));
-
- for (idx = 1; idx <= old_size; ++idx)
- if (table[idx].used)
- insert_entry (htab, table[idx].key, strlen(table[idx].key),
- table[idx].data);
-
- free (table);
- }
- return 0;
- }
- /* NOTREACHED */
-}
-
-
-int
-find_entry (hash_table *htab, const char *key, size_t keylen, void **result)
-{
- hash_entry *table = (hash_entry *) htab->table;
- size_t idx = lookup (htab, key, keylen, compute_hashval (key, keylen));
- int retval;
-
- retval = table[idx].used;
- *result = retval ? table[idx].data : NULL;
-
- return retval;
-}
-
-
-int
-iterate_table (hash_table *htab, void **ptr, void **result)
-{
- if (*ptr == NULL)
- *ptr = (void *) htab->first;
- else
- {
- *ptr = (void *) (((hash_entry *) *ptr)->next);
- if (*ptr == NULL)
- return 0;
- }
-
- *result = ((hash_entry *) *ptr)->data;
- return 1;
-}
-
-
-static size_t
-lookup (hash_table *htab, const char *key, size_t keylen, unsigned long hval)
-{
- unsigned long hash;
- size_t idx;
- hash_entry *table = (hash_entry *) htab->table;
-
- /* First hash function: simply take the modul but prevent zero. */
- hash = 1 + hval % htab->size;
-
- idx = hash;
-
- if (table[idx].used)
- {
- if (table[idx].used == hval && table[idx].key[keylen] == '\0'
- && strncmp (key, table[idx].key, keylen) == 0)
- return idx;
-
- /* Second hash function as suggested in [Knuth]. */
- hash = 1 + hash % (htab->size - 2);
-
- do
- {
- if (idx <= hash)
- idx = htab->size + idx - hash;
- else
- idx -= hash;
-
- /* If entry is found use it. */
- if (table[idx].used == hval && table[idx].key[keylen] == '\0'
- && strncmp (key, table[idx].key, keylen) == 0)
- return idx;
- }
- while (table[idx].used);
- }
- return idx;
-}
-
-
-static unsigned long
-compute_hashval(const char *key, size_t keylen)
-{
- size_t cnt;
- unsigned long hval, g;
- /* Compute the hash value for the given string. */
- cnt = 0;
- hval = keylen;
- while (cnt < keylen)
- {
- hval <<= 4;
- hval += key[cnt++];
- g = hval & (0xfL << (LONGBITS - 4));
- if (g != 0)
- {
- hval ^= g >> (LONGBITS - 8);
- hval ^= g;
- }
- }
- return hval;
-}
-
-
-static unsigned long
-next_prime(unsigned long seed)
-{
- /* Make it definitely odd. */
- seed |= 1;
-
- while (!is_prime (seed))
- seed += 2;
-
- return seed;
-}
-
-
-static int
-is_prime(unsigned long candidate)
-{
- /* No even number and none less than 10 will be passwd here. */
- unsigned long div = 3;
- unsigned long sq = div * div;
-
- while (sq < candidate && candidate % div != 0)
- {
- ++div;
- sq += 4 * div;
- ++div;
- }
-
- return candidate % div != 0;
-}
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
diff --git a/locale/locfile-lex.c b/locale/locfile-lex.c
deleted file mode 100644
index 20e4f0f9cd..0000000000
--- a/locale/locfile-lex.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <ctype.h>
-#include <langinfo.h>
-#include <libintl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "localedef.h"
-#include "token.h"
-
-
-/* Include the hashing table for the keywords. */
-const struct locale_keyword* in_word_set (register const char *str,
- register int len);
-#include "keyword.h"
-
-
-/* Contains the status of reading the locale definition file. */
-struct locfile_data locfile_data;
-
-/* This is a flag used while collation input. This is the only place
- where element names beside the ones defined in the character map are
- allowed. There we must not give error messages. */
-int reject_new_char = 1;
-
-/* Prototypes for local functions. */
-static int get_char (void);
-
-
-#define LD locfile_data
-
-/* Opens the locale definition file and initializes the status data structure
- for following calls of `locfile_lex'. */
-void
-locfile_open (const char *fname)
-{
- if (fname == NULL)
- /* We read from stdin. */
- LD.filename = "<stdin>";
- else
- {
- if (freopen (fname, "r", stdin) == NULL)
- error (4, 0, gettext ("input file `%s' not found"), fname);
- LD.filename = fname;
- }
-
- /* Set default values. */
- LD.escape_char = '\\';
- LD.comment_char = '#';
-
- LD.bufsize = sysconf (_SC_LINE_MAX);
- LD.buf = (char *) xmalloc (LD.bufsize);
- LD.strbuf = (char *) xmalloc (LD.bufsize);
-
- LD.buf_ptr = LD.returned_tokens = LD.line_no = 0;
-
- /* Now sign that we want immediately read a line. */
- LD.continue_line = 1;
- LD.buf[LD.buf_ptr] = '\0';
-}
-
-
-int
-xlocfile_lex (char **token, int *token_len)
-{
- int retval = locfile_lex (token, token_len);
-
- if (retval == 0)
- /* I.e. end of file. */
- error (4, 0, gettext ("%s: unexpected end of file in locale defintion "
- "file"), locfile_data.filename);
-
- return retval;
-}
-
-int
-locfile_lex (char **token, int *token_len)
-{
- int start_again;
- int retval = 0;
-
- do
- {
- int start_ptr;
-
- start_again = 0;
-
- /* Read the next line. Skip over empty lines and comments. */
- if ((LD.buf[LD.buf_ptr] == '\0' && LD.continue_line != 0)
- || LD.buf_ptr >= LD.bufsize
- || (posix_conformance == 0 && LD.buf[LD.buf_ptr] == LD.comment_char))
- do
- {
- size_t linelen;
-
- LD.buf_ptr = 0;
-
- if (fgets (LD.buf, LD.bufsize, stdin) == NULL)
- {
- /* This makes subsequent calls also return EOF. */
- LD.buf[0] = '\0';
- return 0;
- }
-
- /* Increment line number counter. */
- ++LD.line_no;
-
- /* We now have to look whether this line is continued and
- whether it at all fits into our buffer. */
- linelen = strlen (LD.buf);
-
- if (linelen == LD.bufsize - 1)
- /* The did not fit into the buffer. */
- error (2, 0, gettext ("%s:%Zd: line too long; use "
- "`getconf LINE_MAX' to get the maximum "
- "line length"), LD.filename, LD.line_no);
-
- /* Remove '\n' at end of line. */
- if (LD.buf[linelen - 1] == '\n')
- LD.buf[--linelen] = '\0';
-
- if (linelen > 0 && LD.buf[linelen - 1] == LD.escape_char)
- {
- LD.buf[--linelen] = '\0';
- LD.continue_line = 1;
- }
- else
- LD.continue_line = 0;
-
- while (isspace (LD.buf[LD.buf_ptr]))
- ++LD.buf_ptr;
-
- /* We are not so restrictive and allow white spaces before
- a comment. */
- if (posix_conformance == 0
- && LD.buf[LD.buf_ptr] == LD.comment_char
- && LD.buf_ptr != 0)
- error (0, 0, gettext ("%s:%Zd: comment does not start in "
- "column 1"), LD.filename, LD.line_no);
- }
- while (LD.buf[LD.buf_ptr] == '\0'
- || LD.buf[LD.buf_ptr] == LD.comment_char);
-
-
- /* Get information for return values. */
- *token = LD.buf + LD.buf_ptr;
- start_ptr = LD.buf_ptr;
-
- /* If no further character is in the line this is the end of a logical
- line. This information is needed in the parser. */
- if (LD.buf[LD.buf_ptr] == '\0')
- {
- LD.buf_ptr = LD.bufsize;
- retval = TOK_ENDOFLINE;
- }
- else if (isalpha (LD.buf[LD.buf_ptr]))
- /* The token is an identifier. The POSIX standard does not say
- what characters might be contained but offical POSIX locale
- definition files contain beside alnum characters '_', '-' and
- '+'. */
- {
- const struct locale_keyword *kw;
-
- do
- ++LD.buf_ptr;
- while (isalnum (LD.buf[LD.buf_ptr]) || LD.buf[LD.buf_ptr] == '_'
- || LD.buf[LD.buf_ptr] == '-' || LD.buf[LD.buf_ptr] == '+');
-
- /* Look in table of keywords. */
- kw = in_word_set (*token, LD.buf_ptr - start_ptr);
- if (kw == NULL)
- retval = TOK_IDENT;
- else
- {
- if (kw->token_id == TOK_ESCAPE_CHAR
- || kw->token_id == TOK_COMMENT_CHAR)
- /* `escape_char' and `comment_char' are keywords for the
- lexer. Do not give them to the parser. */
- {
- start_again = 1;
-
- if (!isspace (LD.buf[LD.buf_ptr])
- || (posix_conformance && LD.returned_tokens > 0))
- error (0, 0, gettext ("%s:%Zd: syntax error in locale "
- "definition file"),
- LD.filename, LD.line_no);
-
- do
- ++LD.buf_ptr;
- while (isspace (LD.buf[LD.buf_ptr]));
-
- kw->token_id == TOK_ESCAPE_CHAR
- ? LD.escape_char
- : LD.comment_char = LD.buf[LD.buf_ptr++];
-
- ignore_to_eol (0, posix_conformance);
- }
- else
- /* It is one of the normal keywords. */
- retval = kw->token_id;
- }
-
- *token_len = LD.buf_ptr - start_ptr;
- }
- else if (LD.buf[LD.buf_ptr] == '"')
- /* Read a string. All symbolic character descriptions are expanded.
- This has to be done in a local buffer because a simple symbolic
- character like <A> may expand to upto 6 bytes. */
- {
- char *last = LD.strbuf;
-
- ++LD.buf_ptr;
- while (LD.buf[LD.buf_ptr] != '"')
- {
- int pre = LD.buf_ptr;
- int char_val = get_char (); /* token, token_len); */
-
- if (char_val == 0)
- {
- error (4, 0, gettext ("%s:%Zd: unterminated string at end "
- "of line"), LD.filename, LD.line_no);
- /* NOTREACHED */
- }
-
- if (char_val > 0)
- /* Unknown characters are simply not stored. */
- last += char_to_utf (last, char_val);
- else
- {
- char tmp[LD.buf_ptr - pre + 1];
- memcpy (tmp, &LD.buf[pre], LD.buf_ptr - pre);
- tmp[LD.buf_ptr - pre] = '\0';
- error (0, 0, gettext ("%s:%Zd: character `%s' not defined"),
- LD.filename, LD.line_no, tmp);
- }
- }
- if (LD.buf[LD.buf_ptr] != '\0')
- ++LD.buf_ptr;
-
- *last = '\0';
- *token = LD.strbuf;
- *token_len = last - LD.strbuf;
- retval = TOK_STRING;
- }
- else if (LD.buf[LD.buf_ptr] == '.' && LD.buf[LD.buf_ptr + 1] == '.'
- && LD.buf[LD.buf_ptr + 2] == '.')
- {
- LD.buf_ptr += 3;
- retval = TOK_ELLIPSIS;
- }
- else if (LD.buf[LD.buf_ptr] == LD.escape_char)
- {
- char *endp;
-
- ++LD.buf_ptr;
- switch (LD.buf[LD.buf_ptr])
- {
- case 'x':
- if (isdigit (LD.buf[++LD.buf_ptr]))
- {
- retval = strtol (&LD.buf[LD.buf_ptr], &endp, 16);
- if (endp - (LD.buf + LD.buf_ptr) < 2 || retval > 255)
- retval = 'x';
- else
- LD.buf_ptr = endp - LD.buf;
- }
- else
- retval = 'x';
- break;
- case 'd':
- if (isdigit (LD.buf[++LD.buf_ptr]))
- {
- retval = strtol (&LD.buf[LD.buf_ptr], &endp, 10);
- if (endp - (LD.buf + LD.buf_ptr) < 2 || retval > 255)
- retval = 'd';
- else
- LD.buf_ptr = endp - LD.buf;
- }
- else
- retval = 'd';
- break;
- case '0'...'9':
- retval = strtol (&LD.buf[LD.buf_ptr], &endp, 8);
- if (endp - (LD.buf + LD.buf_ptr) < 2 || retval > 255)
- retval = LD.buf[LD.buf_ptr++];
- else
- LD.buf_ptr = endp - LD.buf;
- break;
- case 'a':
- retval = '\a';
- ++LD.buf_ptr;
- break;
- case 'b':
- retval = '\b';
- ++LD.buf_ptr;
- break;
- case 'f':
- retval = '\f';
- ++LD.buf_ptr;
- break;
- case 'n':
- retval = '\n';
- ++LD.buf_ptr;
- break;
- case 'r':
- retval = '\r';
- ++LD.buf_ptr;
- break;
- case 't':
- retval = '\t';
- ++LD.buf_ptr;
- break;
- case 'v':
- retval = '\v';
- ++LD.buf_ptr;
- break;
- default:
- retval = LD.buf[LD.buf_ptr++];
- break;
- }
- }
- else if (isdigit (LD.buf[LD.buf_ptr]))
- {
- char *endp;
-
- *token_len = strtol (&LD.buf[LD.buf_ptr], &endp, 10);
- LD.buf_ptr = endp - LD.buf;
- retval = TOK_NUMBER;
- }
- else if (LD.buf[LD.buf_ptr] == '-' && LD.buf[LD.buf_ptr + 1] == '1')
- {
- LD.buf_ptr += 2;
- retval = TOK_MINUS1;
- }
- else
- {
- int ch = get_char (); /* token, token_len); */
- if (ch != -1)
- {
- *token_len = ch;
- retval = TOK_CHAR;
- }
- else
- retval = TOK_ILL_CHAR;
- }
-
- /* Ignore white space. */
- while (isspace (LD.buf[LD.buf_ptr]))
- ++LD.buf_ptr;
- }
- while (start_again != 0);
-
- ++LD.returned_tokens;
- return retval;
-}
-
-
-/* Code a character with UTF-8 if the character map has multi-byte
- characters. */
-int
-char_to_utf (char *buf, int char_val)
-{
- if (charmap_data.mb_cur_max == 1)
- {
- *buf++ = char_val;
- return 1;
- }
- else
- {
-/* The number of bits coded in each character. */
-#define CBPC 6
- static struct coding_tab
- {
- int mask;
- int val;
- }
- tab[] =
- {
- { 0x7f, 0x00 },
- { 0x7ff, 0xc0 },
- { 0xffff, 0xe0 },
- { 0x1fffff, 0xf0 },
- { 0x3ffffff, 0xf8 },
- { 0x7fffffff, 0xfc },
- { 0, }
- };
- struct coding_tab *t;
- int c;
- int cnt = 1;
-
- for (t = tab; char_val > t->mask; ++t, ++cnt)
- ;
-
- c = cnt;
-
- buf += cnt;
- while (c > 1)
- {
- *--buf = 0x80 | (char_val & ((1 << CBPC) - 1));
- char_val >>= CBPC;
- --c;
- }
-
- *--buf = t->val | char_val;
-
- return cnt;
- }
-}
-
-
-/* Ignore rest of line upto ENDOFLINE token, starting with given token.
- If WARN_FLAG is set warn about any token but ENDOFLINE. */
-void
-ignore_to_eol (int token, int warn_flag)
-{
- if (token == TOK_ENDOFLINE)
- return;
-
- if (LD.buf[LD.buf_ptr] != '\0' && warn_flag)
- error (0, 0, gettext ("%s:%Zd: trailing garbage at end of line"),
- locfile_data.filename, locfile_data.line_no);
-
- while (LD.continue_line)
- {
- LD.continue_line = 0;
-
- /* Increment line number counter. */
- ++LD.line_no;
-
- if (fgets (LD.buf, LD.bufsize, stdin) != NULL)
- {
- /* We now have to look whether this line is continued and
- whether it at all fits into our buffer. */
- int linelen = strlen (LD.buf);
-
- if (linelen == LD.bufsize - 1)
- /* The did not fit into the buffer. */
- error (2, 0, gettext ("%s:%Zd: line too long; use `getconf "
- "LINE_MAX' to get the current maximum "
- "line length"), LD.filename, LD.line_no);
-
- /* Remove '\n' at end of line. */
- if (LD.buf[linelen - 1] == '\n')
- --linelen;
-
- if (LD.buf[linelen - 1] == LD.escape_char)
- LD.continue_line = 1;
- }
- }
-
- /* This causes to begin the next line. */
- LD.buf_ptr = LD.bufsize;
-}
-
-
-/* Return the value of the character at the beginning of the input buffer.
- Symbolic character constants are expanded. */
-static int
-get_char (void)
-{
- if (LD.buf[LD.buf_ptr] == '<')
- /* This is a symbolic character name. */
- {
- int char_val;
- char *startp = LD.buf + (++LD.buf_ptr);
- char *endp = startp;
-
- while (LD.buf[LD.buf_ptr] != '>' && isprint (LD.buf[LD.buf_ptr]))
- {
- if (LD.buf[LD.buf_ptr] == '\0'
- || (LD.buf[LD.buf_ptr] == LD.escape_char
- && LD.buf[++LD.buf_ptr] == '\0'))
- break;
-
- *endp++ = LD.buf[LD.buf_ptr++];
- }
-
- if (LD.buf[LD.buf_ptr] != '>' && LD.buf[LD.buf_ptr] == '\0')
- {
- error (0, 0, gettext ("%s:%Zd: end of line in character symbol"),
- LD.filename, LD.line_no);
-
- if (startp == endp)
- return -1;
- }
- else
- ++LD.buf_ptr;
-
- char_val = find_char (startp, endp - startp);
- if (char_val == -1 && verbose != 0 && reject_new_char != 0)
- {
- /* Locale defintions are often given very general. Missing
- characters are only reported when explicitely requested. */
- char tmp[endp - startp + 3];
-
- tmp[0] = '<';
- memcpy (tmp + 1, startp, endp - startp);
- tmp[endp - startp + 1] = '>';
- tmp[endp - startp + 2] = '\0';
-
- error (0, 0, gettext ("%s:%Zd: character `%s' not defined"),
- LD.filename, LD.line_no, tmp);
- }
-
- return char_val;
- }
- else
- return (int) LD.buf[LD.buf_ptr++];
-}
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
diff --git a/locale/locfile-parse.c b/locale/locfile-parse.c
deleted file mode 100644
index daf56bcd45..0000000000
--- a/locale/locfile-parse.c
+++ /dev/null
@@ -1,838 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <errno.h>
-#include <assert.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <langinfo.h>
-#include <libintl.h>
-#include <limits.h>
-#include <obstack.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-
-#include "localedef.h"
-#include "localeinfo.h"
-#include "token.h"
-
-/* We don't have these constants defined because we don't use them. Give
- default values. */
-#define CTYPE_MB_CUR_MIN 0
-#define CTYPE_MB_CUR_MAX 0
-#define CTYPE_HASH_SIZE 0
-#define CTYPE_HASH_LAYERS 0
-#define CTYPE_CLASS 0
-#define CTYPE_TOUPPER_EB 0
-#define CTYPE_TOLOWER_EB 0
-#define CTYPE_TOUPPER_EL 0
-#define CTYPE_TOLOWER_EL 0
-
-
-/* We have all categories defined in `categories.def'. Now construct
- the description and data structure used for all categories. */
-#define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \
- struct cat_item category##_desc[] = \
- { \
- NO_PAREN items \
- }; \
- \
- char *category##_values[NELEMS (category##_desc) - 1] = { NULL, };
-#include "categories.def"
-#undef DEFINE_CATEGORY
-
-struct category category[] =
- {
-#define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \
- [category] = { _NL_NUM_##category, name, NELEMS (category##_desc) - 1, \
- category##_desc, category##_values, in, check, out },
-#include "categories.def"
-#undef DEFINE_CATEGORY
- };
-#define NCATEGORIES NELEMS (category)
-
-
-#define SYNTAX_ERROR \
- error (0, 0, gettext ("%s:%Zd: syntax error in locale definition file"), \
- locfile_data.filename, locfile_data.line_no)
-
-
-/* Prototypes for local functions. */
-static int get_byte (char *byte_ptr);
-static char *is_locale_name (int cat_no, const char *str, int len);
-
-
-/* Read a locale definition file FILE. The format is defined in
- POSIX.2 2.5.3. */
-void
-locfile_read (const char *fname)
-{
- /* Pointer to text of last token. */
- char *ptr;
- /* Length of last token (or if NUMBER the value itself). */
- int len;
- /* The last returned token. */
- int token;
- /* For error correction we remember whether the last token was correct. */
- int correct_token = 1;
-
- /* Open the desired input file on stdin. */
- locfile_open (fname);
-
- while ((token = locfile_lex (&ptr, &len)) != 0)
- {
- int cat_no;
-
- for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
- if (token == category[cat_no].cat_id)
- break;
-
- if (cat_no >= NCATEGORIES)
- /* A syntax error occured. No valid category defintion starts. */
- {
- if (correct_token != 0)
- error (0, 0, gettext ("%s:%Zd: locale category start expected"),
- locfile_data.filename, locfile_data.line_no);
-
- /* To prevent following errors mark as error case. */
- correct_token = 0;
-
- /* Synchronization point is the beginning of a new category.
- Overread all line upto this silently. */
- ignore_to_eol (0, 0);
- continue;
- }
-
- /* Rest of the line should be empty. */
- ignore_to_eol (0, 1);
-
- /* Perhaps these category is already specified. We simply give a
- warning and overwrite the values. */
- if (category[cat_no].filled != 0)
- error (0, 0, gettext ("%s:%Zd: multiple definition of locale "
- "category %s"), locfile_data.filename,
- locfile_data.line_no, category[cat_no].name);
-
- /* We read the first token because this could be the copy statement. */
- token = xlocfile_lex (&ptr, &len);
-
- if (token == TOK_COPY)
- /* Copying the definitions from an existing locale is requested. */
- {
- char *str;
-
- /* Get the name of the locale to copy from. */
- token = xlocfile_lex (&ptr, &len);
- if (token != TOK_IDENT && token != TOK_STRING)
- /* No name, then mark error and ignore everything upto next
- start of an category section. */
- {
- /* To prevent following errors mark as error case. */
- correct_token = 0;
-
- /* Synchronization point is the beginning of a new category.
- Overread all line upto this silently. */
- ignore_to_eol (0, 0);
- }
- else if ((str = is_locale_name (cat_no, ptr, len)) != NULL)
- /* Yes the name really names an existing locale file. We are
- returned the complete file name. Store it so that we can
- copy it in the output phase. */
- {
- category[cat_no].copy_locale = str;
- category[cat_no].filled = 1;
-
- ignore_to_eol (0, 1);
- }
- else
- /* No, the name does not address a valid locale file. Mark
- error case and ignore rest of category. */
- {
- char tmp[len + 1];
- memcpy (tmp, ptr, len);
- tmp[len] = '\0';
- error (0, 0, gettext ("%s:%Zd: invalid locale `%s' in copy "
- "statement"), locfile_data.filename,
- locfile_data.line_no, tmp);
- correct_token = 0;
- ignore_to_eol (0, 0);
- }
-
- /* This should END as the next token. */
- token = xlocfile_lex (&ptr, &len);
-
- if (token == TOK_END)
- /* This is the end of the category. */
- {
- token = xlocfile_lex (&ptr, &len);
-
- if (token != category[cat_no].cat_id)
- /* Wrong category name after END. */
- {
- error (0, 0, gettext ("%s:%Zd: category `%s' does not "
- "end with `END %s'"),
- locfile_data.filename, locfile_data.line_no,
- category[cat_no].name, category[cat_no].name);
- ignore_to_eol (0, 0);
- }
- else
- ignore_to_eol (0, 1);
-
- correct_token = 1;
- }
- else
- /* No END following copy. Give error while not in error case. */
- {
- if (correct_token != 0)
- error (0, 0, gettext ("%s:%Zd: `copy' must be sole rule"),
- locfile_data.filename, locfile_data.line_no);
- correct_token = 0;
- ignore_to_eol (0, 0);
- }
-
- continue;
- }
-
- /* Now it's time to mark as mentioned in the locale file. */
- category[cat_no].filled = 1;
-
- if (category[cat_no].infct != NULL)
- /* The category needs a special input handling. */
- {
- category[cat_no].infct(token);
- continue;
- }
-
- /* Now process the given items. */
- while (1)
- {
- int item_no;
-
- if (token == TOK_END)
- /* This is the end of the category. */
- {
- token = xlocfile_lex (&ptr, &len);
-
- if (token != category[cat_no].cat_id)
- {
- error (0, 0, gettext ("%s:%Zd: category `%s' does not end "
- "with `END %s'"),
- locfile_data.filename, locfile_data.line_no,
- category[cat_no].name, category[cat_no].name);
- ignore_to_eol (0, 0);
- }
- else
- ignore_to_eol (0, 1);
-
- /* Start next category. */
- break;
- }
-
- /* All other lines should describe valid items of the category. */
- for (item_no = 0; item_no < category[cat_no].number; ++item_no)
- if (category[cat_no].item_desc[item_no].item_id == token)
- break;
-
- if (item_no >= category[cat_no].number)
- /* This is not a valid item of the category. */
- {
- SYNTAX_ERROR;
- ignore_to_eol (0, 0);
-
- token = xlocfile_lex (&ptr, &len);
-
- /* And process next item. */
- continue;
- }
-
- /* Test whether already a value is defined. */
- if (category[cat_no].item_value[item_no] != NULL)
- error (0, 0, gettext ("%s:%Zd: category item `%s' already "
- "defined"),
- locfile_data.filename, locfile_data.line_no,
- category[cat_no].item_desc[item_no].name);
-
- switch (category[cat_no].item_desc[item_no].value_type)
- {
- case string:
- /* Get next token. This is the argument to the item. */
- token = xlocfile_lex (&ptr, &len);
-
- if (token != TOK_STRING)
- SYNTAX_ERROR;
- else
- category[cat_no].item_value[item_no] = strdup (ptr);
- ignore_to_eol (0, ptr != NULL);
- break;
- case stringarray:
- /* This is a difficult case. The number of strings in
- the array may vary. But for now its only necessary
- with ALT_DIGITS from LC_TIME. This item is the last
- so be can solve it by storing the number of string in
- the first place and the string indeces following
- that. */
- {
- int cnt;
- char **buffer;
- if (category[cat_no].item_value[item_no] != NULL)
- buffer = (char **) category[cat_no].item_value[item_no];
- else
- buffer = (char **) xmalloc (
- sizeof (char *) * category[cat_no].item_desc[item_no].max);
-
- category[cat_no].item_value[item_no] = (char *) buffer;
-
- /* As explained we may need a place to store the real number
- of strings. */
- if (category[cat_no].item_desc[item_no].min
- != category[cat_no].item_desc[item_no].max)
- ++buffer;
-
- cnt = 0;
- do
- {
- token = xlocfile_lex (&ptr, &len);
- if (token != TOK_STRING)
- {
- SYNTAX_ERROR;
- break;
- }
-
- if (cnt >= category[cat_no].item_desc[item_no].max)
- {
- error (0, 0, gettext ("%s:%Zd: too many elements "
- "for item `%s`"),
- locfile_data.filename, locfile_data.line_no,
- category[cat_no].item_desc[item_no].name);
- break;
- }
-
- buffer[cnt++] = strdup (ptr);
-
- token = locfile_lex (&ptr, &len);
- }
- while (token == TOK_CHAR && len == ';');
-
- ignore_to_eol (token, ptr != NULL);
-
- if (cnt < category[cat_no].item_desc[item_no].min)
- error (0, 0, gettext ("%s:%Zd: too few elements for item "
- "`%s'"),
- locfile_data.filename, locfile_data.line_no,
- category[cat_no].item_desc[item_no].name);
-
- if (category[cat_no].item_desc[item_no].min
- != category[cat_no].item_desc[item_no].max)
- *(int *) category[cat_no].item_value[item_no] = cnt;
- }
- break;
- case byte:
- {
- int ok;
- category[cat_no].item_value[item_no] = (char *) xmalloc (
- __alignof__ (char));
- ok = get_byte (category[cat_no].item_value[item_no]);
- ignore_to_eol (0, ok);
- }
- break;
- case bytearray:
- {
- char *buffer;
- int maxsize;
- int cnt;
- char byte;
- int ok;
-
- buffer = (char *) xmalloc ((maxsize = 30));
- cnt = 0;
-
- while ((ok = get_byte (&byte)))
- {
- if (cnt >= maxsize)
- buffer = (char *) xmalloc ((maxsize *= 2));
-
- buffer[cnt++] = byte;
-
- token = locfile_lex (&ptr, &len);
- if (token != TOK_CHAR || len != ';')
- break;
- }
-
- buffer[cnt] = '\0';
- category[cat_no].item_value[item_no] = buffer;
- ignore_to_eol (token, ok);
- }
- break;
- default:
- error (5, 0, gettext ("internal error in %s, line %u"),
- __FUNCTION__, __LINE__);
- /* NOTREACHED */
- }
-
- /* Get next token. */
- token = xlocfile_lex (&ptr, &len);
- } /* while (1) */
- }
-}
-
-
-/* Check given values for categories for consistency. */
-void
-categories_check (void)
-{
- int cat_no;
-
- for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
- if (category[cat_no].copy_locale == NULL)
- if (category[cat_no].filled != 0)
- if (category[cat_no].checkfct)
- category[cat_no].checkfct();
- else
- {
- int item_no;
-
- for (item_no = 0; item_no < category[cat_no].number; ++item_no)
- if (category[cat_no].item_value[item_no] == NULL)
- {
- int errcode;
-
- /* If the item is defined in the standard is it an error to
- have it not defined. */
- errcode = category[cat_no].item_desc[item_no].status == std
- ? 5 : 0;
-
- error (errcode, 0, gettext ("item `%s' of category `%s' "
- "undefined"),
- category[cat_no].item_desc[item_no].name,
- category[cat_no].name);
- }
- }
- else
- error (0, 0, gettext ("category `%s' not defined"),
- category[cat_no].name);
-}
-
-
-/* Write out the binary representation of the category data which can be
- loaded by setlocale(1). */
-void
-categories_write (void)
-{
- struct locale_file
- {
- int magic;
- int n;
- int idx[0];
- } *data;
- struct obstack obstk;
- int cat_no;
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
- obstack_init (&obstk);
-
- for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
- {
- int result = 0;
-
- if (category[cat_no].copy_locale != NULL)
- /* Simply copy the addressed locale file of the specified
- category. Please note that this is tried before the distinction
- between categories which need special handling is made. */
- {
- int source;
-
- /* Open source file. */
- source = open (category[cat_no].copy_locale, O_RDONLY);
- if (source < 0)
- error (0, 0, gettext ("cannot copy locale definition file `%s'"),
- category[cat_no].copy_locale);
- else
- {
- /* Construct file name of output file and open for writing. */
- char path[strlen (output_path)
- + strlen(category[cat_no].name) + 1];
- int dest;
- char *t;
-
- t = stpcpy (path, output_path);
- strcpy (t, category[cat_no].name);
-
- dest = creat (path, 0666);
- if (dest == -1)
- error (0, 0, gettext ("cannot open output file `%s': %m"),
- path);
- else
- {
- char buffer[BUFSIZ];
- int size;
-
- /* Copy the files. */
- do
- {
- size = read (source, buffer, BUFSIZ);
- write (dest, buffer, size);
- }
- while (size > 0);
-
- close (dest);
-
- /* Show success. */
- puts (category[cat_no].name);
- }
- close (source);
- }
-
- /* Next category. */
- continue;
- }
-
- if (category[cat_no].outfct)
- result = category[cat_no].outfct();
- else
- {
- char *path, *t;
- int fd;
- struct iovec *iov;
- int item_no, len, slen, cnt;
- int elems = 0;
-
- /* Count number of elements. */
- for (item_no = 0; item_no < category[cat_no].number; ++item_no)
- {
- switch (category[cat_no].item_desc[item_no].value_type)
- {
- case string:
- case byte:
- case bytearray:
- ++elems;
- break;
- case stringarray:
- elems += category[cat_no].item_desc[item_no].max;
- break;
- default:
- error (5, 0, gettext ("internal error in %s, line %u"),
- __FUNCTION__, __LINE__);
- /* NOTREACHED */
- }
- }
-
- /* We now have the number of elements. We build the structure
- and a helper structure for writing all out. */
- len = sizeof (struct locale_file) + elems * sizeof (int);
- data = obstack_alloc (&obstk, len);
- iov = obstack_alloc (&obstk, (elems + 1) * sizeof (struct iovec));
-
- data->magic = LIMAGIC (cat_no);
- data->n = elems;
- iov[0].iov_base = data;
- iov[0].iov_len = len;
-
- cnt = 0;
- for (item_no = 0; item_no < category[cat_no].number; ++item_no)
- if (category[cat_no].item_value[item_no] == NULL)
- {
- switch (category[cat_no].item_desc[item_no].value_type)
- {
- case string:
- case byte:
- case bytearray:
- data->idx[cnt] = len;
- ++len; /* We reserve one single byte for this entry. */
- iov[1 + cnt].iov_base = (char *) "";
- iov[1 + cnt].iov_len = 1;
- ++cnt;
- break;
- case stringarray:
- {
- int max;
- int nstr;
-
- max = category[cat_no].item_desc[item_no].max;
-
- for (nstr = 0; nstr < max; ++nstr)
- {
- data->idx[cnt] = len;
- ++len;
- iov[1 + cnt].iov_base = (char *) "";
- iov[1 + cnt].iov_len = 1;
- ++cnt;
- }
- }
- }
- }
- else
- switch (category[cat_no].item_desc[item_no].value_type)
- {
- case string:
- case bytearray:
- data->idx[cnt] = len;
- slen = strlen (category[cat_no].item_value[item_no]) + 1;
- len += slen;
- iov[1 + cnt].iov_base = category[cat_no].item_value[item_no];
- iov[1 + cnt].iov_len = slen;
- ++cnt;
- break;
- case byte:
- data->idx[cnt] = len;
- slen = 1;
- len += slen;
- iov[1 + cnt].iov_base = category[cat_no].item_value[item_no];
- iov[1 + cnt].iov_len = slen;
- ++cnt;
- break;
- case stringarray:
- {
- int nstr, nact;
- char **first;
-
- if (category[cat_no].item_desc[item_no].min
- == category[cat_no].item_desc[item_no].max)
- {
- nstr = category[cat_no].item_desc[item_no].min;
- first = (char **) category[cat_no].item_value[item_no];
- }
- else
- {
- nstr = *(int *) category[cat_no].item_value[item_no];
- first =
- ((char **) category[cat_no].item_value[item_no]) + 1;
- }
- nact = nstr;
- while (nstr > 0)
- {
- data->idx[cnt] = len;
- if (*first != NULL)
- {
- slen = strlen (*first) + 1;
- iov[1 + cnt].iov_base = *first;
- }
- else
- {
- slen = 1;
- iov[1 + cnt].iov_base = (char *) "";
- }
- len += slen;
- iov[1 + cnt].iov_len = slen;
- ++cnt;
- ++first;
- --nstr;
- }
- while (nact < category[cat_no].item_desc[item_no].max)
- {
- data->idx[cnt] = len;
- len += 1;
- iov[1 + cnt].iov_base = (char *) "";
- iov[1 + cnt].iov_len = 1;
- ++cnt;
- ++nact;
- }
- }
- break;
- default:
- /* Cannot happen. */
- break;
- }
- assert (cnt <= elems);
-
- /* Construct the output filename from the argument given to
- localedef on the command line. */
- path = (char *) obstack_alloc (&obstk, strlen (output_path) +
- 2 * strlen (category[cat_no].name) + 5);
- t = stpcpy (path, output_path);
- strcpy (t, category[cat_no].name);
-
- fd = creat (path, 0666);
-
- if (fd == -1)
- {
- /* Check whether it failed because the named file is a directory.
- In that case we use the file .../LC_xxx/SYS_LC_xxx, as the
- loading functions of the C Library do. */
- struct stat st;
-
- if (stat (path, &st) == 0 && S_ISDIR (st.st_mode))
- {
- stpcpy (stpcpy (strchr (path, '\0'), "/SYS_"),
- category[cat_no].name);
- fd = creat (path, 0666);
- }
- }
-
- if (fd == -1)
- {
- error (0, 0, gettext ("cannot open output file `%s': %m"),
- path);
- result = 1;
- }
- else
- {
- if (writev (fd, iov, cnt + 1) == -1)
- {
- error (0, 0, gettext ("cannot write output file `%s': %m"),
- path);
- result = 1;
- }
-
-if (elems==0) write(fd, &elems, 10);
-
- close (fd);
- }
- /* The old data is not needed anymore, but keep the obstack
- intact. */
- obstack_free (&obstk, data);
- }
-
- if (result == 0)
- puts (category[cat_no].name);
- }
- /* Now the whole obstack can be removed. */
- obstack_free (&obstk, NULL);
-}
-
-
-/* Get the representation of a number. This is a positive integer or
- the number -1 which is handled as a special symbol by the scanner. */
-static int
-get_byte (char *byte_ptr)
-{
- int token;
- char *ptr;
- int len;
-
- token = locfile_lex (&ptr, &len);
- if (token != TOK_NUMBER && token != TOK_MINUS1)
- /* None of the valid number format. */
- {
- error (0, 0, gettext ("%s:%Zd: number expected"),
- locfile_data.filename, locfile_data.line_no);
- *byte_ptr = 0;
- return 0;
- }
-
- if (token == TOK_MINUS1)
- {
- *byte_ptr = CHAR_MAX;
- return 1;
- }
-
- if (len > CHAR_MAX)
- /* The value of the numbers has to be less than CHAR_MAX. This is
- ok for the information they have to express. */
- {
- error (0, 0, gettext ("%s:%Zd: invalid number"),
- locfile_data.filename, locfile_data.line_no);
- *byte_ptr = 0;
- return 0;
- }
-
- *byte_ptr = len;
- return 1;
-}
-
-
-/* Test whether the string STR with length LEN is the name of an existing
- locale and whether a file for category CAT_NO is found in this directory.
- This categories are looked for in the system locale definition file
- directory.
- Return the complete file name for the category file. */
-static char *
-is_locale_name (int cat_no, const char *str, int len)
-{
- static char **locale_names = NULL;
- static int max_count = 0;
- static int locale_count = 0;
- int cnt, exist, fd;
- char *fname;
- struct stat st;
-
- if (locale_names == NULL)
- /* Read in the list of all available locales. */
- {
- DIR *dir;
- struct dirent *dirent;
-
- /* LOCALE_NAMES is not NULL anymore, but LOCALE_COUNT == 0. */
- ++locale_names;
-
- dir = opendir (LOCALE_PATH);
- if (dir == NULL)
- {
- error (1, errno, gettext ("cannot read locale directory `%s'"),
- LOCALE_PATH);
-
- return NULL;
- }
-
- /* Now we can look for all files in the directory. */
- while ((dirent = readdir (dir)) != NULL)
- if (strcmp (dirent->d_name, ".") != 0
- && strcmp (dirent->d_name, "..") != 0)
- {
- if (max_count == 0)
- locale_names = (char **) xmalloc ((max_count = 10)
- * sizeof (char *));
- else if (locale_count >= max_count)
- locale_names = (char **) xrealloc (locale_names,
- (max_count *= 2)
- * sizeof (char *));
- locale_names[locale_count++] = strdup (dirent->d_name);
- }
- closedir (dir);
- }
-
- for (cnt = 0; cnt < locale_count; ++cnt)
- if (strncmp (str, locale_names[cnt], len) == 0
- && locale_names[cnt][len] == '\0')
- break;
-
- if (cnt >= locale_count)
- return NULL;
-
- /* Now search for this specific locale file. */
- asprintf (&fname, "%s/%s/%s", LOCALE_PATH, locale_names[cnt],
- category[cat_no].name);
-
- fd = open (fname, O_RDONLY);
- if (fd < 0)
- {
- free (fname);
- return NULL;
- }
-
- exist = fstat (fd, &st);
- close (fd);
-
- if (exist < 0)
- {
- free (fname);
- return NULL;
- }
-
- return fname;
-}
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
diff --git a/locale/messages.c b/locale/messages.c
deleted file mode 100644
index 842e5ef5b2..0000000000
--- a/locale/messages.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <langinfo.h>
-#include <libintl.h>
-#include <locale.h>
-#include <stdio.h>
-#include <regex.h>
-
-#include "localedef.h"
-
-/* These are defined in locfile-parse.c. */
-extern struct cat_item LC_MESSAGES_desc[];
-extern char *LC_MESSAGES_values[];
-
-void
-messages_check(void)
-{
- int item_no;
-
- /* First general check for existence. */
- for (item_no = 0; item_no < category[LC_MESSAGES].number; ++item_no)
- if (LC_MESSAGES_values[item_no] == NULL)
- {
- int errcode;
-
- errcode = LC_MESSAGES_desc[item_no].status == std ? 5 : 0;
-
- error (errcode, 0, gettext ("item `%s' of category `%s' undefined"),
- LC_MESSAGES_desc[item_no].name, "LC_MESSAGES");
- }
- else
- {
- /* Some fields need special tests. */
- if (LC_MESSAGES_desc[item_no].item_id == YESEXPR
- || LC_MESSAGES_desc[item_no].item_id == NOEXPR)
- /* The expression has to be a POSIX extended regular expression. */
- {
- regex_t re;
- int result;
-
- result = regcomp (&re, LC_MESSAGES_values[item_no], REG_EXTENDED);
-
- if (result != 0)
- {
- char errbuf[BUFSIZ];
-
- (void) regerror (result, &re, errbuf, BUFSIZ);
- error (0, 0, gettext ("no correct regular expression for "
- "item `%s' in category `%s': %s"),
- LC_MESSAGES_desc[item_no].name, "LC_MESSAGES", errbuf);
- }
- }
- }
-}
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
diff --git a/locale/monetary.c b/locale/monetary.c
deleted file mode 100644
index 2683eb2bf0..0000000000
--- a/locale/monetary.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <langinfo.h>
-#include <libintl.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "localedef.h"
-#include "token.h"
-
-
-/* The content iof the field int_curr_symbol has to be taken from
- ISO-4217. We test for correct values. */
-#define DEFINE_INT_CURR(str) str,
-static const char *const valid_int_curr[] =
- {
-# include "iso-4217.def"
- };
-#define NVALID_INT_CURR ((sizeof (valid_int_curr) \
- / sizeof (valid_int_curr[0])))
-#undef DEFINE_INT_CURR
-
-
-/* These are defined in locfile-parse.c. */
-extern struct cat_item LC_MONETARY_desc[];
-extern char *LC_MONETARY_values[];
-
-static int _curr_strcmp(const char *s1, const char **s2);
-
-
-
-void
-monetary_check(void)
-{
- int item_no, val;
-
- for (item_no = 0; LC_MONETARY_desc[item_no].item_id != 0; ++item_no)
- /* Test whether the entry has been defined. Byte values are simply
- stored. */
- if (LC_MONETARY_values[item_no] == NULL)
- {
- int errcode;
-
- errcode = LC_MONETARY_desc[item_no].status = std ? 5 : 0;
-
- error (errcode, 0, gettext ("item `%s' of category `%s' undefined"),
- LC_MONETARY_desc[item_no].name, "LC_MONETARY");
- }
- else
- switch (LC_MONETARY_desc[item_no].item_id)
- {
- case INT_CURR_SYMBOL:
- if (strlen (LC_MONETARY_values[item_no]) != 4)
- error (0, 0,
- gettext ("item `%s' of category `%s' has wrong length"),
- LC_MONETARY_desc[item_no].name, "LC_MONETARY");
- else if (bsearch (LC_MONETARY_values[item_no], valid_int_curr,
- NVALID_INT_CURR, sizeof (char *),
- (comparison_fn_t) _curr_strcmp) == NULL)
- error (0, 0, gettext ("item `%s' does not correspond to any "
- "valid name in ISO-4217"),
- LC_MONETARY_desc[item_no].name);
- break;
- case P_CS_PRECEDES:
- case P_SEP_BY_SPACE:
- case N_CS_PRECEDES:
- case N_SEP_BY_SPACE:
- case P_SIGN_POSN:
- case N_SIGN_POSN:
- val = (int) *(char *) LC_MONETARY_values[item_no];
- if (val < LC_MONETARY_desc[item_no].min
- || val > LC_MONETARY_desc[item_no].max)
- error (0, 0, gettext ("value for item `%s' in category `%s' "
- "must be in range %d...%d"),
- LC_MONETARY_desc[item_no].name, "LC_MONETARY",
- LC_MONETARY_desc[item_no].min,
- LC_MONETARY_desc[item_no].max);
- break;
- case MON_DECIMAL_POINT:
- /* The decimal point must not be empty. This is not said
- explicitly in POSIX but ANSI C (ISO/IEC 9899) says in
- 4.4.2.1 it has to be != "". */
- if (LC_MONETARY_values[item_no][0] == '\0')
- error (0, 0,
- gettext ("item `%s' in category `%s' must not be empty"),
- LC_MONETARY_desc[item_no].name, "LC_MONETARY");
- break;
- case CURRENCY_SYMBOL:
- case MON_THOUSANDS_SEP:
- case MON_GROUPING:
- case POSITIVE_SIGN:
- case NEGATIVE_SIGN:
- case INT_FRAC_DIGITS:
- case FRAC_DIGITS:
- /* Everything is ok for these values. */
- break;
- default:
- error (5, 0, gettext ("Internal error in %s, line %u"),
- __FUNCTION__, __LINE__);
- /* NOTREACHED */
- }
-
-}
-
-
-static int
-_curr_strcmp(const char *s1, const char **s2)
-{
- return strcmp (s1, *s2);
-}
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
diff --git a/locale/numeric.c b/locale/numeric.c
deleted file mode 100644
index 93f4bc481e..0000000000
--- a/locale/numeric.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <langinfo.h>
-#include <libintl.h>
-#include <locale.h>
-
-#include "localedef.h"
-
-/* These are defined in locfile-parse.c. */
-extern struct cat_item LC_NUMERIC_desc[];
-extern char *LC_NUMERIC_values[];
-
-void
-numeric_check(void)
-{
- int item_no;
-
- /* First general check for existence. */
- for (item_no = 0; item_no < category[LC_NUMERIC].number; ++item_no)
- if (LC_NUMERIC_values[item_no] == NULL)
- {
- int errcode;
-
- errcode = LC_NUMERIC_desc[item_no].status = std ? 5 : 0;
-
- error (errcode, 0, gettext ("item `%s' of category `%s' undefined"),
- LC_NUMERIC_desc[item_no].name, "LC_NUMERIC");
- }
- else
- {
- if (LC_NUMERIC_desc[item_no].item_id == DECIMAL_POINT
- && LC_NUMERIC_values[item_no][0] == '\0')
- /* The decimal point must not be empty. This is not said
- explicitly in POSIX but ANSI C (ISO/IEC 9899) says in
- 4.4.2.1 it has to be != "". */
- error (0, 0,
- gettext ("item `%s' in category `%s' must not be empty"),
- LC_NUMERIC_desc[item_no].name, "LC_NUMERIC");
- }
-}
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
diff --git a/locale/programs/charmap-kw.gperf b/locale/programs/charmap-kw.gperf
new file mode 100644
index 0000000000..8e00103882
--- /dev/null
+++ b/locale/programs/charmap-kw.gperf
@@ -0,0 +1,40 @@
+%{
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <string.h>
+
+#include "locfile-token.h"
+%}
+struct keyword_t ;
+%%
+code_set_name, tok_code_set_name, 1
+mb_cur_max, tok_mb_cur_max, 1
+mb_cur_min, tok_mb_cur_min, 1
+escape_char, tok_escape_char, 1
+comment_char, tok_comment_char, 1
+g0esc, tok_g0esc, 1
+g1esc, tok_g1esc, 1
+g2esc, tok_g2esc, 1
+g3esc, tok_g3esc, 1
+CHARMAP, tok_charmap, 0
+END, tok_end, 0
+WIDTH, tok_width, 0
+WIDTH_VARIABLE, tok_width_variable, 0
+WIDTH_DEFAULT, tok_width_default, 0
diff --git a/locale/programs/charmap-kw.h b/locale/programs/charmap-kw.h
new file mode 100644
index 0000000000..93326d0382
--- /dev/null
+++ b/locale/programs/charmap-kw.h
@@ -0,0 +1,117 @@
+/* C code produced by gperf version 2.5 (GNU C++ version) */
+/* Command-line: gperf -acCgopt -k1,2,5,$ -N charmap_hash programs/charmap-kw.gperf */
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <string.h>
+
+#include "locfile-token.h"
+struct keyword_t ;
+
+#define TOTAL_KEYWORDS 14
+#define MIN_WORD_LENGTH 3
+#define MAX_WORD_LENGTH 14
+#define MIN_HASH_VALUE 3
+#define MAX_HASH_VALUE 25
+/* maximum key range = 23, duplicates = 0 */
+
+#ifdef __GNUC__
+inline
+#endif
+static unsigned int
+hash (register const char *str, register int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 14, 10,
+ 15, 4, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 0, 0, 0,
+ 26, 26, 0, 0, 26, 26, 26, 0, 0, 26,
+ 0, 26, 26, 26, 5, 26, 26, 0, 26, 26,
+ 26, 26, 26, 26, 26, 0, 26, 26, 0, 0,
+ 26, 0, 26, 0, 26, 26, 26, 26, 26, 0,
+ 15, 0, 0, 26, 0, 0, 26, 0, 26, 26,
+ 0, 26, 26, 26, 26, 26, 26, 26,
+ };
+ register int hval = len;
+
+ switch (hval)
+ {
+ default:
+ case 5:
+ hval += asso_values[(int) str[4]];
+ case 4:
+ case 3:
+ case 2:
+ hval += asso_values[(int) str[1]];
+ case 1:
+ hval += asso_values[(int) str[0]];
+ break;
+ }
+ return hval + asso_values[(int) str[len - 1]];
+}
+
+#ifdef __GNUC__
+inline
+#endif
+const struct keyword_t *
+charmap_hash (register const char *str, register int len)
+{
+ static const struct keyword_t wordlist[] =
+ {
+ {"",}, {"",}, {"",},
+ {"END", tok_end, 0},
+ {"",},
+ {"WIDTH", tok_width, 0},
+ {"",},
+ {"CHARMAP", tok_charmap, 0},
+ {"",},
+ {"g3esc", tok_g3esc, 1},
+ {"mb_cur_max", tok_mb_cur_max, 1},
+ {"escape_char", tok_escape_char, 1},
+ {"comment_char", tok_comment_char, 1},
+ {"code_set_name", tok_code_set_name, 1},
+ {"WIDTH_VARIABLE", tok_width_variable, 0},
+ {"g1esc", tok_g1esc, 1},
+ {"",}, {"",},
+ {"WIDTH_DEFAULT", tok_width_default, 0},
+ {"g0esc", tok_g0esc, 1},
+ {"g2esc", tok_g2esc, 1},
+ {"",}, {"",}, {"",}, {"",},
+ {"mb_cur_min", tok_mb_cur_min, 1},
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*s == *str && !strncmp (str + 1, s + 1, len - 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/locale/programs/charmap.c b/locale/programs/charmap.c
new file mode 100644
index 0000000000..2b71821ec0
--- /dev/null
+++ b/locale/programs/charmap.c
@@ -0,0 +1,593 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <libintl.h>
+#include <obstack.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "error.h"
+#include "linereader.h"
+#include "charset.h"
+
+
+/* Uncomment following line for production version. */
+/* define NDEBUG 1 */
+#include <assert.h>
+
+
+/* Define the lookup function. */
+#include "charmap-kw.h"
+
+
+void *xmalloc (size_t __n);
+
+/* Prototypes for local functions. */
+static struct charset_t *parse_charmap (const char *filename);
+
+
+
+struct charset_t *
+charmap_read (const char *filename)
+{
+ const char *pathnfile;
+ struct charset_t *result = NULL;
+
+ if (filename != NULL)
+ {
+ if (euidaccess (filename, R_OK) >= 0)
+ pathnfile = filename;
+ else
+ {
+ char *cp = xmalloc (strlen (filename) + sizeof CHARMAP_PATH + 1);
+ stpcpy (stpcpy (stpcpy (cp, CHARMAP_PATH), "/"), filename);
+
+ pathnfile = (const char *) cp;
+ }
+
+ result = parse_charmap (pathnfile);
+
+ if (result == NULL)
+ error (0, errno, _("character map file `%s' not found"), filename);
+ }
+
+ if (result == NULL)
+ {
+ pathnfile = CHARMAP_PATH "/" DEFAULT_CHARMAP;
+
+ result = parse_charmap (pathnfile);
+
+ if (result == NULL)
+ error (4, errno, _("default character map file `%s' not found"),
+ DEFAULT_CHARMAP);
+ }
+
+ return result;
+}
+
+
+static struct charset_t *
+parse_charmap (const char *filename)
+{
+ struct linereader *cmfile;
+ struct charset_t *result;
+ int state;
+ enum token_t expected_tok = tok_error;
+ const char *expected_str = NULL;
+ char *from_name = NULL;
+ char *to_name = NULL;
+
+ /* Determine path. */
+ cmfile = lr_open (filename, charmap_hash);
+ if (cmfile == NULL)
+ {
+ if (strchr (filename, '/') == NULL)
+ {
+ /* Look in the systems charmap directory. */
+ char *buf = xmalloc (strlen (filename) + 1 + sizeof (CHARMAP_PATH));
+
+ stpcpy (stpcpy (stpcpy (buf, CHARMAP_PATH), "/"), filename);
+ cmfile = lr_open (buf, charmap_hash);
+
+ if (cmfile == NULL)
+ free (buf);
+ }
+
+ if (cmfile == NULL)
+ return NULL;
+ }
+
+ /* Allocate room for result. */
+ result = (struct charset_t *) xmalloc (sizeof (struct charset_t));
+ memset (result, '\0', sizeof (struct charset_t));
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+ obstack_init (&result->mem_pool);
+
+ if (init_hash (&result->char_table, 256))
+ {
+ free (result);
+ return NULL;
+ }
+
+ /* We use a state machine to describe the charmap description file
+ format. */
+ state = 1;
+ while (1)
+ {
+ /* What's on? */
+ struct token *now = lr_token (cmfile, NULL);
+ enum token_t nowtok = now->tok;
+ struct token *arg;
+
+ if (nowtok == tok_eof)
+ break;
+
+ switch (state)
+ {
+ case 1:
+ /* The beginning. We expect the special declarations, EOL or
+ `CHARMAP'. */
+ if (nowtok == tok_eol)
+ /* Ignore empty lines. */
+ continue;
+
+ if (nowtok == tok_charmap)
+ {
+ from_name = NULL;
+ to_name = NULL;
+
+ /* We have to set up the real work. Fill in some
+ default values. */
+ if (result->mb_cur_max == 0)
+ result->mb_cur_max = 1;
+ if (result->mb_cur_min == 0)
+ result->mb_cur_min = result->mb_cur_max;
+ if (result->mb_cur_min > result->mb_cur_max)
+ {
+ error (0, 0, _("\
+%s: <mb_cur_max> must be greater than <mb_cur_min>\n"),
+ cmfile->fname);
+
+ result->mb_cur_min = result->mb_cur_max;
+ }
+
+ lr_ignore_rest (cmfile, 1);
+
+ state = 2;
+ continue;
+ }
+
+ if (nowtok != tok_code_set_name && nowtok != tok_mb_cur_max
+ && nowtok != tok_mb_cur_min && nowtok != tok_escape_char
+ && nowtok != tok_comment_char && nowtok != tok_g0esc
+ && nowtok != tok_g1esc && nowtok != tok_g2esc
+ && nowtok != tok_g3esc)
+ {
+ lr_error (cmfile, _("syntax error in prolog: %s"),
+ _("illegal definition"));
+
+ lr_ignore_rest (cmfile, 0);
+ continue;
+ }
+
+ /* We know that we need an argument. */
+ arg = lr_token (cmfile, NULL);
+
+ switch (nowtok)
+ {
+ case tok_code_set_name:
+ if (arg->tok != tok_ident)
+ {
+ badarg:
+ lr_error (cmfile, _("syntax error in prolog: %s"),
+ _("bad argument"));
+
+ lr_ignore_rest (cmfile, 0);
+ continue;
+ }
+
+ result->code_set_name = obstack_copy0 (&result->mem_pool,
+ arg->val.str.start,
+ arg->val.str.len);
+
+ lr_ignore_rest (cmfile, 1);
+ continue;
+
+ case tok_mb_cur_max:
+ case tok_mb_cur_min:
+ if (arg->tok != tok_number)
+ goto badarg;
+
+ if (arg->val.num < 1 || arg->val.num > 4)
+ {
+ lr_error (cmfile,
+ _("value for <%s> must lie between 1 and 4"),
+ nowtok == tok_mb_cur_min ? "mb_cur_min"
+ : "mb_cur_max");
+
+ lr_ignore_rest (cmfile, 0);
+ continue;
+ }
+ if ((nowtok == tok_mb_cur_max && result->mb_cur_min != 0
+ && arg->val.num < result->mb_cur_min)
+ || (nowtok == tok_mb_cur_min && result->mb_cur_max != 0
+ && arg->val.num > result->mb_cur_max))
+ {
+ lr_error (cmfile, _("\
+value of <mb_cur_max> must be greater than the value of <mb_cur_min>"));
+
+ lr_ignore_rest (cmfile, 0);
+ continue;
+ }
+
+ if (nowtok == tok_mb_cur_max)
+ result->mb_cur_max = arg->val.num;
+ else
+ result->mb_cur_min = arg->val.num;
+
+ lr_ignore_rest (cmfile, 1);
+ continue;
+
+ case tok_escape_char:
+ case tok_comment_char:
+ if (arg->tok != tok_ident)
+ goto badarg;
+
+ if (arg->val.str.len != 1)
+ {
+ lr_error (cmfile, _("\
+argument to <%s> must be a single character"),
+ nowtok == tok_escape_char ? "escape_char"
+ : "comment_char");
+
+ lr_ignore_rest (cmfile, 0);
+ continue;
+ }
+
+ if (nowtok == tok_escape_char)
+ cmfile->escape_char = *arg->val.str.start;
+ else
+ cmfile->comment_char = *arg->val.str.start;
+
+ lr_ignore_rest (cmfile, 1);
+ continue;
+
+ case tok_g0esc:
+ case tok_g1esc:
+ case tok_g2esc:
+ case tok_g3esc:
+ lr_ignore_rest (cmfile, 0); /* XXX */
+ continue;
+
+ default:
+ /* Cannot happen. */
+ assert (! "Should not happen");
+ }
+ break;
+
+ case 2:
+ /* We have seen `CHARMAP' and now are in the body. Each line
+ must have the format "%s %s %s\n" or "%s...%s %s %s\n". */
+ if (nowtok == tok_eol)
+ /* Ignore empty lines. */
+ continue;
+
+ if (nowtok == tok_end)
+ {
+ expected_tok = tok_charmap;
+ expected_str = "CHARMAP";
+ state = 90;
+ continue;
+ }
+
+ if (nowtok != tok_bsymbol)
+ {
+ lr_error (cmfile, _("syntax error in %s definition: %s"),
+ "CHARMAP", _("no symbolic name given"));
+
+ lr_ignore_rest (cmfile, 0);
+ continue;
+ }
+
+ /* If the previous line was not completely correct free the
+ used memory. */
+ if (from_name != NULL)
+ obstack_free (&result->mem_pool, from_name);
+
+ from_name = (char *) obstack_copy0 (&result->mem_pool,
+ now->val.str.start,
+ now->val.str.len);
+ to_name = NULL;
+
+ state = 3;
+ continue;
+
+ case 3:
+ /* We have two possibilities: We can see an ellipsis or an
+ encoding value. */
+ if (nowtok == tok_ellipsis)
+ {
+ state = 4;
+ continue;
+ }
+ /* FALLTHROUGH */
+
+ case 5:
+ if (nowtok != tok_charcode && nowtok != tok_ucs2
+ && nowtok != tok_ucs4)
+ {
+ lr_error (cmfile, _("syntax error in %s definition: %s"),
+ "CHARMAP", _("illegal encoding given"));
+
+ lr_ignore_rest (cmfile, 0);
+
+ state = 2;
+ continue;
+ }
+
+ if (nowtok == tok_charcode)
+ /* Write char value in table. */
+ charset_new_char (cmfile, result, now->val.charcode.nbytes,
+ now->val.charcode.val, from_name, to_name);
+ else
+ /* Determine ISO 10646 value and write into table. */
+ charset_new_unicode (cmfile, result, now->val.charcode.nbytes,
+ now->val.charcode.val, from_name, to_name);
+
+ /* Ignore trailing comment silently. */
+ lr_ignore_rest (cmfile, 0);
+
+ from_name = NULL;
+ to_name = NULL;
+
+ state = 2;
+ continue;
+
+ case 4:
+ if (nowtok != tok_bsymbol)
+ {
+ lr_error (cmfile, _("syntax error in %s definition: %s"),
+ "CHARMAP",
+ _("no symbolic name given for end of range"));
+
+ lr_ignore_rest (cmfile, 0);
+ continue;
+ }
+
+ /* If the previous line was not completely correct free the
+ used memory. */
+ to_name = (char *) obstack_copy0 (&result->mem_pool,
+ cmfile->token.val.str.start,
+ cmfile->token.val.str.len);
+
+ state = 3;
+ continue;
+
+ case 90:
+ if (nowtok != expected_tok)
+ lr_error (cmfile, _("\
+`%1$s' definition does not end with `END %1$s'"), expected_str);
+
+ lr_ignore_rest (cmfile, nowtok == expected_tok);
+ state = 91;
+ continue;
+
+ case 91:
+ /* Waiting for WIDTH... */
+ if (nowtok == tok_width_default)
+ {
+ state = 92;
+ continue;
+ }
+
+ if (nowtok == tok_width)
+ {
+ lr_ignore_rest (cmfile, 1);
+ state = 93;
+ continue;
+ }
+
+ if (nowtok == tok_width_variable)
+ {
+ lr_ignore_rest (cmfile, 1);
+ state = 98;
+ continue;
+ }
+
+ lr_error (cmfile, _("\
+only WIDTH definitions are allowed to follow the CHARMAP definition"));
+
+ lr_ignore_rest (cmfile, 0);
+ continue;
+
+ case 92:
+ if (nowtok != tok_number)
+ lr_error (cmfile, _("value for %s must be an integer"),
+ "WIDTH_DEFAULT");
+ else
+ result->width_default = now->val.num;
+
+ lr_ignore_rest (cmfile, nowtok == tok_number);
+
+ state = 91;
+ continue;
+
+ case 93:
+ /* We now expect `END WIDTH' or lines of the format "%s %d\n" or
+ "%s...%s %d\n". */
+ if (nowtok == tok_eol)
+ /* ignore empty lines. */
+ continue;
+
+ if (nowtok == tok_end)
+ {
+ expected_tok = tok_width;
+ expected_str = "WIDTH";
+ state = 90;
+ continue;
+ }
+
+ if (nowtok != tok_bsymbol)
+ {
+ lr_error (cmfile, _("syntax error in %s definition: %s"),
+ "WIDTH", _("no symbolic name given"));
+
+ lr_ignore_rest (cmfile, 0);
+ continue;
+ }
+
+ if (from_name != NULL)
+ obstack_free (&result->mem_pool, from_name);
+
+ from_name = (char *) obstack_copy0 (&result->mem_pool,
+ now->val.str.start,
+ now->val.str.len);
+ to_name = NULL;
+
+ state = 94;
+ continue;
+
+ case 94:
+ if (nowtok == tok_ellipsis)
+ state = 95;
+
+ case 96:
+ if (nowtok != tok_number)
+ lr_error (cmfile, _("value for %s must be an integer"),
+ "WIDTH");
+ else
+ {
+ /* XXX Store width for chars. */
+ from_name = NULL;
+ }
+
+ lr_ignore_rest (cmfile, nowtok == tok_number);
+
+ state = 93;
+ continue;
+
+ case 95:
+ if (nowtok != tok_bsymbol)
+ {
+ lr_error (cmfile, _("syntax error in %s definition: %s"),
+ "WIDTH", _("no symbolic name given for end of range"));
+
+ lr_ignore_rest (cmfile, 0);
+
+ state = 93;
+ continue;
+ }
+
+ to_name = (char *) obstack_copy0 (&result->mem_pool,
+ now->val.str.start,
+ now->val.str.len);
+
+ lr_ignore_rest (cmfile, 1);
+
+ state = 96;
+ continue;
+
+ case 98:
+ /* We now expect `END WIDTH_VARIABLE' or lines of the format
+ "%s\n" or "%s...%s\n". */
+ if (nowtok == tok_eol)
+ /* ignore empty lines. */
+ continue;
+
+ if (nowtok == tok_end)
+ {
+ expected_tok = tok_width_variable;
+ expected_str = "WIDTH_VARIABLE";
+ state = 90;
+ continue;
+ }
+
+ if (nowtok != tok_bsymbol)
+ {
+ lr_error (cmfile, _("syntax error in %s definition: %s"),
+ "WIDTH_VARIABLE", _("no symbolic name given"));
+
+ lr_ignore_rest (cmfile, 0);
+
+ continue;
+ }
+
+ if (from_name != NULL)
+ obstack_free (&result->mem_pool, from_name);
+
+ from_name = (char *) obstack_copy0 (&result->mem_pool,
+ now->val.str.start,
+ now->val.str.len);
+ to_name = NULL;
+
+ state = 99;
+ continue;
+
+ case 99:
+ if (nowtok == tok_ellipsis)
+ state = 100;
+
+ /* Store info. */
+ from_name = NULL;
+
+ /* Warn */
+ state = 98;
+ continue;
+
+ case 100:
+ if (nowtok != tok_bsymbol)
+ lr_error (cmfile, _("syntax error in %s definition: %s"),
+ "WIDTH_VARIABLE",
+ _("no symbolic name given for end of range"));
+ else
+ {
+ to_name = (char *) obstack_copy0 (&result->mem_pool,
+ now->val.str.start,
+ now->val.str.len);
+ /* XXX Enter value into table. */
+ }
+
+ lr_ignore_rest (cmfile, nowtok == tok_bsymbol);
+
+ state = 98;
+ continue;
+
+ default:
+ error (5, 0, _("%s: error in state machine"), __FILE__);
+ /* NOTREACHED */
+ }
+ break;
+ }
+
+ if (state != 91)
+ error (0, 0, _("%s: premature end of file"), cmfile->fname);
+
+ lr_close (cmfile);
+
+ return result;
+}
diff --git a/locale/programs/charset.c b/locale/programs/charset.c
new file mode 100644
index 0000000000..2e2f63bd9a
--- /dev/null
+++ b/locale/programs/charset.c
@@ -0,0 +1,132 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <alloca.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "charset.h"
+
+
+static void
+insert_char (struct linereader *lr, struct charset_t *cs, int bytes,
+ unsigned int value, const char *from, const char *to);
+
+
+void
+charset_new_char (struct linereader *lr, struct charset_t *cs, int bytes,
+ unsigned int value, const char *from, const char *to)
+{
+ if (bytes < cs->mb_cur_min)
+ lr_error (lr, _("too few bytes in character encoding"));
+ else if (bytes > cs->mb_cur_max)
+ lr_error (lr, _("too many bytes in character encoding"));
+ else
+ insert_char (lr, cs, bytes, value, from, to);
+}
+
+
+void
+charset_new_unicode (struct linereader *lr, struct charset_t *cs, int bytes,
+ unsigned int value, const char *from, const char *to)
+{
+ /* For now: perhaps <Uxxxx> support will be removed again... */
+ insert_char (lr, cs, bytes, value, from, to);
+}
+
+
+unsigned int
+charset_find_value (const struct charset_t *cs, const char *name, size_t len)
+{
+ void *result;
+
+ if (find_entry ((hash_table *) &cs->char_table, name, len, &result) < 0)
+ return ILLEGAL_CHAR_VALUE;
+
+ return (unsigned int) result;
+}
+
+
+static void
+insert_char (struct linereader *lr, struct charset_t *cs, int bytes,
+ unsigned int value, const char *from, const char *to)
+{
+ const char *cp;
+ char *buf;
+ int prefix_len, len1, len2;
+ unsigned int from_nr, to_nr, cnt;
+
+ if (to == NULL)
+ {
+ if (insert_entry (&cs->char_table, from, strlen (from), (void *) value)
+ < 0)
+ lr_error (lr, _("duplicate character name `%s'"), from);
+
+ return;
+ }
+
+ /* We have a range: the names must have names with equal prefixes
+ and an equal number of digits, where the second number is greater
+ or equal than the first. */
+ len1 = strlen (from);
+ len2 = strlen (to);
+
+ if (len1 != len2)
+ {
+ illegal_range:
+ lr_error (lr, _("illegal names for character range"));
+ return;
+ }
+
+ cp = &from[len1 - 1];
+ while (isdigit (*cp) && cp >= from)
+ --cp;
+
+ prefix_len = (cp - from) + 1;
+
+ if (cp == &from[len1 - 1] || strncmp (from, to, prefix_len) != 0)
+ goto illegal_range;
+
+ from_nr = strtoul (&from[prefix_len], NULL, 10);
+ to_nr = strtoul (&to[prefix_len], NULL, 10);
+
+ if (from_nr > to_nr)
+ {
+ lr_error (lr, _("upper limit in range is not smaller then lower limit"));
+ return;
+ }
+
+ buf = alloca (len1 + 1);
+ memcpy (buf, from, prefix_len);
+
+ for (cnt = from_nr; cnt <= to_nr; ++cnt)
+ {
+ sprintf (&buf[prefix_len], "%0d", cnt);
+
+ if (insert_entry (&cs->char_table, buf, len1, (void *) cnt) < 0)
+ lr_error (lr, _("duplicate character name `%s'"), buf);
+ }
+}
diff --git a/locale/programs/charset.h b/locale/programs/charset.h
new file mode 100644
index 0000000000..222d468407
--- /dev/null
+++ b/locale/programs/charset.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef _CHARSET_H
+#define _CHARSET_H
+
+#include <obstack.h>
+
+#include "simple-hash.h"
+#include "linereader.h"
+
+
+struct charset_t
+{
+ const char *code_set_name;
+ int mb_cur_min;
+ int mb_cur_max;
+ int width_default;
+
+ struct obstack mem_pool;
+ hash_table char_table;
+};
+
+
+/* We need one value to mark the error case. Let's use 0xffffffff.
+ I.e., it is placed in the last page of ISO 10646. For now only the
+ first is used and we have plenty of room. */
+#define ILLEGAL_CHAR_VALUE 0xffffffffu
+
+
+/* Prototypes for charmap handling functions. */
+struct charset_t *charmap_read (const char *filename);
+
+/* Prototypes for funciton to insert new character. */
+void charset_new_char (struct linereader *lr, struct charset_t *cs, int bytes,
+ unsigned int value, const char *from, const char *to);
+
+void charset_new_unicode (struct linereader *lr, struct charset_t *cs,
+ int bytes, unsigned int value, const char *from,
+ const char *to);
+
+unsigned int charset_find_value (const struct charset_t *__cs,
+ const char *__name, size_t __len);
+
+#endif /* charset.h */
diff --git a/locale/programs/config.h b/locale/programs/config.h
new file mode 100644
index 0000000000..64054657cb
--- /dev/null
+++ b/locale/programs/config.h
@@ -0,0 +1,33 @@
+#ifndef _LD_CONFIG_H
+#define _LD_CONFIG_H
+
+/* Use the internal textdomain used for libc messages. */
+#define PACKAGE _libc_intl_domainname
+#ifndef VERSION
+/* Get libc version number. */
+#include "../../version.h"
+#endif
+
+#define DEFAULT_CHARMAP "POSIX"
+
+#ifndef PARAMS
+# if __STDC__
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif
+#endif
+
+
+
+#define HAVE_VPRINTF 1
+
+
+typedef int wint_t;
+typedef unsigned short int u16_t;
+
+
+
+int euidaccess (__const char *__name, int __type);
+
+#endif
diff --git a/locale/ctypedump.c b/locale/programs/ctypedump.c
index e00f3e0f11..2a6753495e 100644
--- a/locale/ctypedump.c
+++ b/locale/programs/ctypedump.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
@@ -21,7 +21,7 @@ Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <netinet/in.h> /* Just for htons() */
-#include "localedef.h"
+/*#include "localedef.h"*/
#include "localeinfo.h"
@@ -31,10 +31,10 @@ Cambridge, MA 02139, USA. */
#define SWAP32(v) \
- ((u32) (((((u32) (v)) & 0x000000ff) << 24) \
- | ((((u32) (v)) & 0x0000ff00) << 8) \
- | ((((u32) (v)) & 0x00ff0000) >> 8) \
- | ((((u32) (v)) & 0xff000000) >> 24)))
+ ((u32_t) (((((u32_t) (v)) & 0x000000ff) << 24) \
+ | ((((u32_t) (v)) & 0x0000ff00) << 8) \
+ | ((((u32_t) (v)) & 0x00ff0000) >> 8) \
+ | ((((u32_t) (v)) & 0xff000000) >> 24)))
@@ -53,13 +53,13 @@ print_int_in_char (unsigned int val)
printf ("\"\\%03o\\%03o\\%03o\\%03o\"", p[0], p[1], p[2], p[3]);
}
-
+
int
ctype_output (void)
{
int ch;
int result = 0;
- const char *locname = (getenv ("LC_ALL") ?: getenv ("LC_CTYPE") ?:
+ const char *locname = (getenv ("LC_ALL") ?: getenv ("LC_CTYPE") ?:
getenv ("LANG") ?: "POSIX");
puts ("#include <endian.h>\n");
diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c
new file mode 100644
index 0000000000..0f3bcbca33
--- /dev/null
+++ b/locale/programs/ld-collate.c
@@ -0,0 +1,1549 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <endian.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <obstack.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wcstr.h>
+
+#include "localeinfo.h"
+#include "locales.h"
+#include "simple-hash.h"
+#include "stringtrans.h"
+
+/* Uncomment the following line in the production version. */
+/* define NDEBUG 1 */
+#include <assert.h>
+
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define SWAPU32(w) \
+ (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24))
+
+
+/* What kind of symbols get defined? */
+enum coll_symbol
+{
+ undefined,
+ ellipsis,
+ character,
+ element,
+ symbol
+};
+
+
+typedef struct patch_t
+{
+ const char *fname;
+ size_t lineno;
+ const char *token;
+ union
+ {
+ unsigned int *pos;
+ size_t idx;
+ } where;
+ struct patch_t *next;
+} patch_t;
+
+
+typedef struct element_t
+{
+ const wchar_t *name;
+ unsigned int this_weight;
+
+ struct element_t *next;
+
+ unsigned int *ordering;
+ size_t ordering_len;
+} element_t;
+
+
+/* The real definition of the struct for the LC_CTYPE locale. */
+struct locale_collate_t
+{
+ /* Collate symbol table. Simple mapping to number. */
+ hash_table symbols;
+
+ /* The collation elements. */
+ hash_table elements;
+ struct obstack element_mem;
+
+ /* The result table. */
+ hash_table result;
+
+ /* Sorting rules given in order_start line. */
+ int nrules;
+ int nrules_max;
+ enum coll_sort_rule *rules;
+
+ /* Used while recognizing symbol composed of multiple tokens
+ (collating-element). */
+ const char *combine_token;
+ size_t combine_token_len;
+
+ /* How many sorting order specifications so far. */
+ unsigned int order_cnt;
+
+ /* Was lastline ellipsis? */
+ int was_ellipsis;
+ /* Value of last entry if was character. */
+ wchar_t last_char;
+ /* Current element. */
+ element_t *current_element;
+ /* What kind of symbol is current element. */
+ enum coll_symbol kind;
+
+ /* While collecting the weigths we need some temporary space. */
+ unsigned int current_order;
+ int *weight_cnt;
+ int weight_idx;
+ unsigned int *weight;
+ int nweight;
+ int nweight_max;
+
+ /* Patch lists. */
+ patch_t *current_patch;
+ patch_t *all_patches;
+
+ /* Room for the UNDEFINED information. */
+ element_t undefined;
+ unsigned int undefined_len;
+};
+
+
+/* Be verbose? Defined in localedef.c. */
+extern int verbose;
+
+
+void *xmalloc (size_t __n);
+void *xrealloc (void *__p, size_t __n);
+
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+
+void
+collate_startup (struct linereader *lr, struct localedef_t *locale,
+ struct charset_t *charset)
+{
+ struct locale_collate_t *collate;
+
+ /* It is important that we always use UCS4 encoding for strings now. */
+ encoding_method = ENC_UCS4;
+
+ /* Allocate the needed room. */
+ locale->categories[LC_COLLATE].collate = collate =
+ (struct locale_collate_t *) xmalloc (sizeof (struct locale_collate_t));
+
+ /* Allocate hash table for collating elements. */
+ if (init_hash (&collate->elements, 512))
+ error (4, 0, _("memory exhausted"));
+ collate->combine_token = NULL;
+ obstack_init (&collate->element_mem);
+
+ /* Allocate hash table for collating elements. */
+ if (init_hash (&collate->symbols, 64))
+ error (4, 0, _("memory exhausted"));
+
+ /* Allocate hash table for result. */
+ if (init_hash (&collate->result, 512))
+ error (4, 0, _("memory exhausted"));
+
+ collate->nrules = 0;
+ collate->nrules_max = 10;
+ collate->rules
+ = (enum coll_sort_rule *) xmalloc (collate->nrules_max
+ * sizeof (enum coll_sort_rule));
+
+ collate->order_cnt = 1; /* The smallest weight is 2. */
+
+ collate->was_ellipsis = 0;
+ collate->last_char = L'\0'; /* 0 because leading ellipsis is allowed. */
+
+ collate->all_patches = NULL;
+
+ /* This tells us no UNDEFINED entry was found until now. */
+ collate->undefined.this_weight = 0;
+
+ lr->translate_strings = 0;
+}
+
+
+void
+collate_finish (struct localedef_t *locale, struct charset_t *charset)
+{
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+ patch_t *patch;
+ size_t cnt;
+
+ /* Patch the constructed table so that forward references are
+ correctly filled. */
+ for (patch = collate->all_patches; patch != NULL; patch = patch->next)
+ {
+ wchar_t wch;
+ size_t toklen = strlen (patch->token);
+ void *ptmp;
+ unsigned int value = 0;
+
+ wch = charset_find_value (charset, patch->token, toklen);
+ if (wch != ILLEGAL_CHAR_VALUE)
+ {
+ element_t *runp;
+
+ if (find_entry (&collate->result, &wch, sizeof (wchar_t),
+ (void *) &runp) < 0)
+ runp = NULL;
+ for (; runp != NULL; runp = runp->next)
+ if (runp->name[0] == wch && runp->name[1] == L'\0')
+ break;
+
+ value = runp == NULL ? 0 : runp->this_weight;
+ }
+ else if (find_entry (&collate->elements, patch->token, toklen, &ptmp)
+ >= 0)
+ {
+ value = ((element_t *) ptmp)->this_weight;
+ }
+ else if (find_entry (&collate->symbols, patch->token, toklen, &ptmp)
+ >= 0)
+ {
+ value = (unsigned int) ptmp;
+ }
+ else
+ value = 0;
+
+ if (value == 0)
+ error_with_loc (0, 0, patch->fname, patch->lineno,
+ _("no weight defined for symbol `%s'"), patch->token);
+ else
+ *patch->where.pos = value;
+ }
+
+ /* If no definition for UNDEFINED is given, all characters in the
+ given charset must be specified. */
+ if (collate->undefined.ordering == NULL)
+ {
+ /**************************************************************\
+ |* XXX We should test whether really an unspecified character *|
+ |* exists before giving the message. *|
+ \**************************************************************/
+ u32_t weight;
+
+ error (0, 0, _("no definition of `UNDEFINED'"));
+
+ collate->undefined.ordering_len = collate->nrules;
+ weight = ++collate->order_cnt;
+
+ for (cnt = 0; cnt < collate->nrules; ++cnt)
+ {
+ u32_t one = 1;
+ obstack_grow (&collate->element_mem, &one, sizeof (one));
+ }
+
+ for (cnt = 0; cnt < collate->nrules; ++cnt)
+ obstack_grow (&collate->element_mem, &weight, sizeof (weight));
+
+ collate->undefined.ordering = obstack_finish (&collate->element_mem);
+ }
+
+ collate->undefined_len = 2; /* For the name: 1 x wchar_t + L'\0'. */
+ for (cnt = 0; cnt < collate->nrules; ++cnt)
+ collate->undefined_len += 1 + collate->undefined.ordering[cnt];
+
+ /* Collating symbols are not used anymore. */
+ (void) delete_hash (&collate->symbols);
+}
+
+
+
+void
+collate_output (struct localedef_t *locale, const char *output_path)
+{
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+ u32_t table_size, table_best, level_best, sum_best;
+ void *last;
+ element_t *pelem;
+ wchar_t *name;
+ size_t len;
+ const size_t nelems = _NL_ITEM_INDEX (_NL_NUM_LC_COLLATE);
+ struct iovec iov[2 + nelems];
+ struct locale_file data;
+ u32_t idx[nelems];
+ struct obstack non_simple;
+ size_t cnt, entry_size;
+ u32_t undefined_offset = UINT_MAX;
+ u32_t *table, *extra, *table2, *extra2;
+ size_t extra_len;
+
+ sum_best = UINT_MAX;
+ table_best = 0xffff;
+ level_best = 0xffff;
+
+ /* Compute table size. */
+ fputs (_("\
+Computing table size for collation information might take a while..."),
+ stderr);
+ for (table_size = 256; table_size < sum_best; ++table_size)
+ {
+ size_t hits[table_size];
+ unsigned int worst = 1;
+ size_t cnt;
+
+ last = NULL;
+
+ for (cnt = 0; cnt < 256; ++cnt)
+ hits[cnt] = 1;
+ memset (&hits[256], '\0', sizeof (hits) - 256 * sizeof (size_t));
+
+ while (iterate_table (&collate->result, &last, (const void **) &name,
+ &len, (void **) &pelem) >= 0)
+ if (pelem->ordering != NULL && pelem->name[0] > 0xff)
+ if (++hits[(unsigned int) pelem->name[0] % table_size] > worst)
+ {
+ worst = hits[(unsigned int) pelem->name[0] % table_size];
+ if (table_size * worst > sum_best)
+ break;
+ }
+
+ if (table_size * worst < sum_best)
+ {
+ sum_best = table_size * worst;
+ table_best = table_size;
+ level_best = worst;
+ }
+ }
+ assert (table_best != 0xffff || level_best != 0xffff);
+ fputs (_(" done\n"), stderr);
+
+ obstack_init (&non_simple);
+
+ data.magic = LIMAGIC (LC_COLLATE);
+ data.n = nelems;
+ iov[0].iov_base = (void *) &data;
+ iov[0].iov_len = sizeof (data);
+
+ iov[1].iov_base = (void *) idx;
+ iov[1].iov_len = sizeof (idx);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_NRULES)].iov_base = &collate->nrules;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_NRULES)].iov_len = sizeof (u32_t);
+
+ table = (u32_t *) alloca (collate->nrules * sizeof (u32_t));
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_RULES)].iov_base = table;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_RULES)].iov_len
+ = collate->nrules * sizeof (u32_t);
+ /* Another trick here. Describing the collation method needs only a
+ few bits (3, to be exact). But the binary file should be
+ accessible by maschines with both endianesses and so we store both
+ information in the same word. */
+ for (cnt = 0; cnt < collate->nrules; ++cnt)
+ table[cnt] = collate->rules[cnt] | SWAPU32 (collate->rules[cnt]);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_HASH_SIZE)].iov_base = &table_best;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_HASH_SIZE)].iov_len = sizeof (u32_t);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_HASH_LAYERS)].iov_base = &level_best;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_HASH_LAYERS)].iov_len = sizeof (u32_t);
+
+ entry_size = 1 + MAX (collate->nrules, 2);
+
+ table = (u32_t *) alloca (table_best * level_best * entry_size
+ * sizeof (table[0]));
+ memset (table, '\0', table_best * level_best * entry_size
+ * sizeof (table[0]));
+
+
+ /* Macros for inserting in output table. */
+#define ADD_VALUE(expr) \
+ do { \
+ u32_t to_write = (u32_t) expr; \
+ obstack_grow (&non_simple, &to_write, sizeof (to_write)); \
+ } while (0)
+
+#define ADD_ELEMENT(pelem, len) \
+ do { \
+ size_t cnt, idx; \
+ \
+ ADD_VALUE (len); \
+ \
+ wlen = wcslen (pelem->name); \
+ obstack_grow (&non_simple, pelem->name, (wlen + 1) * sizeof (u32_t)); \
+ \
+ idx = collate->nrules; \
+ for (cnt = 0; cnt < collate->nrules; ++cnt) \
+ { \
+ size_t disp; \
+ \
+ ADD_VALUE (pelem->ordering[cnt]); \
+ for (disp = 0; disp < pelem->ordering[cnt]; ++disp) \
+ ADD_VALUE (pelem->ordering[idx++]); \
+ } \
+ } while (0)
+
+#define ADD_FORWARD(pelem) \
+ do { \
+ /* We leave a reference in the main table and put all \
+ information in the table for the extended entries. */ \
+ element_t *runp; \
+ element_t *has_simple = NULL; \
+ size_t wlen; \
+ \
+ table[(level * table_best + slot) * entry_size + 1] \
+ = FORWARD_CHAR; \
+ table[(level * table_best + slot) * entry_size + 2] \
+ = obstack_object_size (&non_simple) / sizeof (u32_t); \
+ \
+ /* Here we have to construct the non-simple table entry. First \
+ compute the total length of this entry. */ \
+ for (runp = (pelem); runp != NULL; runp = runp->next) \
+ if (runp->ordering != NULL) \
+ { \
+ u32_t value; \
+ size_t cnt; \
+ \
+ value = 1 + wcslen (runp->name) + 1; \
+ \
+ for (cnt = 0; cnt < collate->nrules; ++cnt) \
+ /* We have to take care for entries without ordering \
+ information. While reading them they get inserted in the \
+ table and later not removed when something goes wrong with \
+ reading its weights. */ \
+ { \
+ value += 1 + runp->ordering[cnt]; \
+ \
+ if (runp->name[1] == L'\0') \
+ has_simple = runp; \
+ } \
+ \
+ ADD_ELEMENT (runp, value); \
+ } \
+ \
+ if (has_simple == NULL) \
+ { \
+ size_t idx, cnt; \
+ \
+ ADD_VALUE (collate->undefined_len + 1); \
+ \
+ /* Add the name. */ \
+ ADD_VALUE ((pelem)->name[0]); \
+ ADD_VALUE (0); \
+ \
+ idx = collate->nrules; \
+ for (cnt = 0; cnt < collate->nrules; ++cnt) \
+ { \
+ size_t disp; \
+ \
+ ADD_VALUE (collate->undefined.ordering[cnt]); \
+ for (disp = 0; disp < collate->undefined.ordering[cnt]; ++disp) \
+ { \
+ if (collate->undefined.ordering[idx] == ELLIPSIS_CHAR) \
+ ADD_VALUE ((pelem)->name[0]); \
+ else \
+ ADD_VALUE (collate->undefined.ordering[idx++]); \
+ ++idx; \
+ } \
+ } \
+ } \
+ } while (0)
+
+
+
+ /* Fill the table now. First we look for all the characters which
+ fit into one single byte. This speeds up the 8-bit string
+ functions. */
+ last = NULL;
+ while (iterate_table (&collate->result, &last, (const void **) &name,
+ &len, (void **) &pelem) >= 0)
+ if (pelem->name[0] <= 0xff)
+ {
+ /* We have a single byte name. Now we must distinguish
+ between entries in simple form (i.e., only one value per
+ weight and no collation element starting with the same
+ character) and those which are not. */
+ size_t slot = ((size_t) pelem->name[0]);
+ const size_t level = 0;
+
+ table[slot * entry_size] = pelem->name[0];
+
+ if (pelem->name[1] == L'\0' && pelem->next == NULL
+ && pelem->ordering_len == collate->nrules)
+ {
+ /* Yes, we have a simple one. Lucky us. */
+ size_t cnt;
+
+ for (cnt = 0; cnt < collate->nrules; ++cnt)
+ table[slot * entry_size + 1 + cnt]
+ = pelem->ordering[collate->nrules + cnt];
+ }
+ else
+ ADD_FORWARD (pelem);
+ }
+
+ /* Now check for missing single byte entries. If one exist we fill
+ with the UNDEFINED entry. */
+ for (cnt = 0; cnt < 256; ++cnt)
+ /* The first weight is never 0 for existing entries. */
+ if (table[cnt * entry_size + 1] == 0)
+ {
+ /* We have to fill in the information from the UNDEFINED
+ entry. */
+ table[cnt * entry_size] = (u32_t) cnt;
+
+ if (collate->undefined.ordering_len == collate->nrules)
+ {
+ size_t inner;
+
+ for (inner = 0; inner < collate->nrules; ++inner)
+ if (collate->undefined.ordering[collate->nrules + inner]
+ == ELLIPSIS_CHAR)
+ table[cnt * entry_size + 1 + inner] = cnt;
+ else
+ table[cnt * entry_size + 1 + inner]
+ = collate->undefined.ordering[collate->nrules + inner];
+ }
+ else
+ {
+ if (undefined_offset != UINT_MAX)
+ {
+ table[cnt * entry_size + 1] = FORWARD_CHAR;
+ table[cnt * entry_size + 2] = undefined_offset;
+ }
+ else
+ {
+ const size_t slot = cnt;
+ const size_t level = 0;
+
+ ADD_FORWARD (&collate->undefined);
+ undefined_offset = table[cnt * entry_size + 2];
+ }
+ }
+ }
+
+ /* Now we are ready for inserting the whole rest. */
+ last = NULL;
+ while (iterate_table (&collate->result, &last, (const void **) &name,
+ &len, (void **) &pelem) >= 0)
+ if (pelem->name[0] > 0xff)
+ {
+ /* Find the position. */
+ size_t slot = ((size_t) pelem->name[0]) % table_best;
+ size_t level = 0;
+
+ while (table[(level * table_best + slot) * entry_size + 1] != 0)
+ ++level;
+ assert (level < level_best);
+
+ if (pelem->name[1] == L'\0' && pelem->next == NULL
+ && pelem->ordering_len == collate->nrules)
+ {
+ /* Again a simple entry. */
+ size_t inner;
+
+ for (inner = 0; inner < collate->nrules; ++inner)
+ table[(level * table_best + slot) * entry_size + 1 + inner]
+ = pelem->ordering[collate->nrules + inner];
+ }
+ else
+ ADD_FORWARD (pelem);
+ }
+
+ /* Add the UNDEFINED entry. */
+ {
+ /* Here we have to construct the non-simple table entry. */
+ size_t idx, cnt;
+
+ undefined_offset = obstack_object_size (&non_simple);
+
+ idx = collate->nrules;
+ for (cnt = 0; cnt < collate->nrules; ++cnt)
+ {
+ size_t disp;
+
+ ADD_VALUE (collate->undefined.ordering[cnt]);
+ for (disp = 0; disp < collate->undefined.ordering[cnt]; ++disp)
+ ADD_VALUE (collate->undefined.ordering[idx++]);
+ }
+ }
+
+ /* Finish the extra block. */
+ extra_len = obstack_object_size (&non_simple);
+ extra = (u32_t *) obstack_finish (&non_simple);
+ assert ((extra_len % sizeof (u32_t)) == 0);
+
+ /* Now we have to build the two array for the other byte ordering. */
+ table2 = (u32_t *) alloca (table_best * level_best * entry_size
+ * sizeof (table[0]));
+ extra2 = (u32_t *) alloca (extra_len);
+
+ for (cnt = 0; cnt < table_best * level_best * entry_size; ++cnt)
+ table2[cnt] = SWAPU32 (table[cnt]);
+
+ for (cnt = 0; cnt < extra_len / sizeof (u32_t); ++cnt)
+ extra2[cnt] = SWAPU32 (extra2[cnt]);
+
+ /* Store table adresses and lengths. */
+#if __BYTE_ORDER == __BIG_ENDIAN
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_TABLE_EB)].iov_base = table;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_TABLE_EB)].iov_len
+ = table_best * level_best * entry_size * sizeof (table[0]);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_TABLE_EL)].iov_base = table2;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_TABLE_EL)].iov_len
+ = table_best * level_best * entry_size * sizeof (table[0]);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_EXTRA_EB)].iov_base = extra;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_EXTRA_EB)].iov_len = extra_len;
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_EXTRA_EL)].iov_base = extra2;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_EXTRA_EL)].iov_len = extra_len;
+#else
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_TABLE_EB)].iov_base = table2;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_TABLE_EB)].iov_len
+ = table_best * level_best * entry_size * sizeof (table[0]);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_TABLE_EL)].iov_base = table;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_TABLE_EL)].iov_len
+ = table_best * level_best * entry_size * sizeof (table[0]);
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_EXTRA_EB)].iov_base = extra2;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_EXTRA_EB)].iov_len = extra_len;
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_EXTRA_EL)].iov_base = extra;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_EXTRA_EL)].iov_len = extra_len;
+#endif
+
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_UNDEFINED)].iov_base = &undefined_offset;
+ iov[2 + _NL_ITEM_INDEX (_NL_COLLATE_UNDEFINED)].iov_len = sizeof (u32_t);
+
+ /* Update idx array. */
+ idx[0] = iov[0].iov_len + iov[1].iov_len;
+ for (cnt = 1; cnt < nelems; ++cnt)
+ idx[cnt] = idx[cnt - 1] + iov[1 + cnt].iov_len;
+
+ write_locale_data (output_path, "LC_COLLATE", 2 + nelems, iov);
+}
+
+
+void
+collate_element_to (struct linereader *lr, struct localedef_t *locale,
+ struct token *code, struct charset_t *charset)
+{
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+ unsigned int value;
+ void *not_used;
+
+ if (collate->combine_token != NULL)
+ {
+ free ((void *) collate->combine_token);
+ collate->combine_token = NULL;
+ }
+
+ value = charset_find_value (charset, code->val.str.start, code->val.str.len);
+ if (value != ILLEGAL_CHAR_VALUE)
+ {
+ lr_error (lr, _("symbol for multicharacter collating element "
+ "`%.*s' duplicates symbolic name in charset"),
+ code->val.str.len, code->val.str.start);
+ return;
+ }
+
+ if (find_entry (&collate->elements, code->val.str.start, code->val.str.len,
+ &not_used) >= 0)
+ {
+ lr_error (lr, _("symbol for multicharacter collating element "
+ "`%.*s' duplicates other element definition"),
+ code->val.str.len, code->val.str.start);
+ return;
+ }
+
+ if (find_entry (&collate->elements, code->val.str.start, code->val.str.len,
+ &not_used) >= 0)
+ {
+ lr_error (lr, _("symbol for multicharacter collating element "
+ "`%.*s' duplicates symbol definition"),
+ code->val.str.len, code->val.str.start);
+ return;
+ }
+
+ collate->combine_token = code->val.str.start;
+ collate->combine_token_len = code->val.str.len;
+}
+
+
+void
+collate_element_from (struct linereader *lr, struct localedef_t *locale,
+ struct token *code, struct charset_t *charset)
+{
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+ element_t *elemp, *runp;
+
+ /* CODE is a string. */
+ elemp = (element_t *) obstack_alloc (&collate->element_mem,
+ sizeof (element_t));
+
+ /* We have to translate the string. It may contain <...> character
+ names. */
+ elemp->name = (wchar_t *) translate_string (code->val.str.start, charset);
+ elemp->this_weight = 0;
+ elemp->ordering = NULL;
+ elemp->ordering_len = 0;
+
+ free (code->val.str.start);
+
+ if (elemp->name == NULL)
+ {
+ /* At least one character in the string is not defined. We simply
+ do nothing. */
+ if (verbose)
+ lr_error (lr, _("\
+`from' string in collation element declaration contains unknown character"));
+ return;
+ }
+
+ if (elemp->name[0] == L'\0' || elemp->name[1] == L'\0')
+ {
+ lr_error (lr, _("illegal colltion element"));
+ return;
+ }
+
+ /* The entries in the linked lists of RESULT are sorting in
+ descending order. The order is important for the `strcoll' and
+ `wcscoll' functions. */
+ if (find_entry (&collate->result, elemp->name, sizeof (wchar_t),
+ (void *) &runp) >= 0)
+ {
+ /* We already have an entry with this key. Check whether it is
+ identical. */
+ element_t *prevp = NULL;
+ int cmpres;
+
+ do
+ {
+ cmpres = wcscmp (elemp->name, runp->name);
+ if (cmpres <= 0)
+ break;
+ prevp = runp;
+ }
+ while ((runp = runp->next) != NULL);
+
+ if (cmpres == 0)
+ lr_error (lr, _("duplicate collating element definition"));
+ else
+ {
+ elemp->next = runp;
+ if (prevp == NULL)
+ {
+ if (set_entry (&collate->result, elemp->name, sizeof (wchar_t),
+ elemp) < 0)
+ error (EXIT_FAILURE, 0,
+ _("\
+error while inserting collation element into hash table"));
+ }
+ else
+ prevp->next = elemp;
+ }
+ }
+ else
+ {
+ elemp->next = NULL;
+ if (insert_entry (&collate->result, elemp->name, sizeof (wchar_t), elemp)
+ < 0)
+ error (EXIT_FAILURE, errno, _("error while inserting to hash table"));
+ }
+
+ if (insert_entry (&collate->elements, collate->combine_token,
+ collate->combine_token_len, (void *) elemp) < 0)
+ lr_error (lr, _("cannot insert new collating symbol definition: %s"),
+ strerror (errno));
+}
+
+
+void
+collate_symbol (struct linereader *lr, struct localedef_t *locale,
+ struct token *code, struct charset_t *charset)
+{
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+ wchar_t value;
+ void *not_used;
+
+ value = charset_find_value (charset, code->val.str.start, code->val.str.len);
+ if (value != ILLEGAL_CHAR_VALUE)
+ {
+ lr_error (lr, _("symbol for multicharacter collating element "
+ "`%.*s' duplicates symbolic name in charset"),
+ code->val.str.len, code->val.str.start);
+ return;
+ }
+
+ if (find_entry (&collate->elements, code->val.str.start, code->val.str.len,
+ &not_used) >= 0)
+ {
+ lr_error (lr, _("symbol for multicharacter collating element "
+ "`%.*s' duplicates element definition"),
+ code->val.str.len, code->val.str.start);
+ return;
+ }
+
+ if (find_entry (&collate->symbols, code->val.str.start, code->val.str.len,
+ &not_used) >= 0)
+ {
+ lr_error (lr, _("symbol for multicharacter collating element "
+ "`%.*s' duplicates other symbol definition"),
+ code->val.str.len, code->val.str.start);
+ return;
+ }
+
+ if (insert_entry (&collate->symbols, code->val.str.start, code->val.str.len,
+ (void *) 0) < 0)
+ lr_error (lr, _("cannot insert new collating symbol definition: %s"),
+ strerror (errno));
+}
+
+
+void
+collate_new_order (struct linereader *lr, struct localedef_t *locale,
+ enum coll_sort_rule sort_rule)
+{
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+
+ if (collate->nrules >= collate->nrules_max)
+ {
+ collate->nrules_max *= 2;
+ collate->rules
+ = (enum coll_sort_rule *) xrealloc (collate->rules,
+ collate->nrules_max
+ * sizeof (enum coll_sort_rule));
+ }
+
+ collate->rules[collate->nrules++] = sort_rule;
+}
+
+
+void
+collate_build_arrays (struct linereader *lr, struct localedef_t *locale)
+{
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+
+ collate->rules
+ = (enum coll_sort_rule *) xrealloc (collate->rules,
+ collate->nrules
+ * sizeof (enum coll_sort_rule));
+
+ /* Allocate arrays for temporary weights. */
+ collate->weight_cnt = (int *) xmalloc (collate->nrules * sizeof (int));
+
+ /* Choose arbitrary start value for table size. */
+ collate->nweight_max = 5 * collate->nrules;
+ collate->weight = (int *) xmalloc (collate->nweight_max * sizeof (int));
+}
+
+
+int
+collate_order_elem (struct linereader *lr, struct localedef_t *locale,
+ struct token *code, struct charset_t *charset)
+{
+ const wchar_t zero = L'\0';
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+ int result = 0;
+ wchar_t value;
+ void *tmp;
+ int i;
+
+ switch (code->tok)
+ {
+ case tok_bsymbol:
+ /* We have a string to find in one of the three hashing tables. */
+ value = charset_find_value (charset, code->val.str.start,
+ code->val.str.len);
+ if (value != ILLEGAL_CHAR_VALUE)
+ {
+ element_t *lastp, *firstp;
+
+ collate->kind = character;
+
+ if (find_entry (&collate->result, &value, sizeof (wchar_t),
+ (void *) &firstp) < 0)
+ firstp = lastp = NULL;
+ else
+ {
+ /* The entry for the simple character is always found at
+ the end. */
+ lastp = firstp;
+ while (lastp->next != NULL)
+ lastp = lastp->next;
+
+ if (lastp->name[0] == value && lastp->name[1] == L'\0')
+ {
+ lr_error (lr, _("duplicate definition for character `%.*s'"),
+ code->val.str.len, code->val.str.start);
+ lr_ignore_rest (lr, 0);
+ result = -1;
+ break;
+ }
+ }
+
+ collate->current_element
+ = (element_t *) obstack_alloc (&collate->element_mem,
+ sizeof (element_t));
+
+ obstack_grow (&collate->element_mem, &value, sizeof (value));
+ obstack_grow (&collate->element_mem, &zero, sizeof (zero));
+
+ collate->current_element->name =
+ (const wchar_t *) obstack_finish (&collate->element_mem);
+
+ collate->current_element->this_weight = ++collate->order_cnt;
+
+ collate->current_element->next = NULL;
+
+ if (firstp == NULL)
+ {
+ if (insert_entry (&collate->result, &value, sizeof (wchar_t),
+ (void *) collate->current_element) < 0)
+ {
+ lr_error (lr, _("cannot insert collation element `%.*s'"),
+ code->val.str.len, code->val.str.start);
+ exit (4);
+ }
+ }
+ else
+ lastp->next = collate->current_element;
+ }
+ else if (find_entry (&collate->elements, code->val.str.start,
+ code->val.str.len, &tmp) >= 0)
+ {
+ collate->current_element = (element_t *) tmp;
+
+ if (collate->current_element->this_weight != 0)
+ {
+ lr_error (lr, _("\
+collation element `%.*s' appears more than once: ignore line"),
+ code->val.str.len, code->val.str.start);
+ lr_ignore_rest (lr, 0);
+ result = -1;
+ break;
+ }
+
+ collate->kind = element;
+ collate->current_element->this_weight = ++collate->order_cnt;
+ }
+ else if (find_entry (&collate->symbols, code->val.str.start,
+ code->val.str.len, &tmp) >= 0)
+ {
+ unsigned int order = ++collate->order_cnt;
+
+ if ((unsigned int) tmp != 0)
+ {
+ lr_error (lr, _("\
+collation symbol `.*s' appears more than once: ignore line"),
+ code->val.str.len, code->val.str.start);
+ lr_ignore_rest (lr, 0);
+ result = -1;
+ break;
+ }
+
+ collate->kind = symbol;
+
+ if (set_entry (&collate->symbols, code->val.str.start,
+ code->val.str.len, (void *) order) < 0)
+ {
+ lr_error (lr, _("cannot process order specification"));
+ exit (4);
+ }
+ }
+ else
+ {
+ if (verbose)
+ lr_error (lr, _("unknown symbol `%.*s': line ignored"),
+ code->val.str.len, code->val.str.start);
+ lr_ignore_rest (lr, 0);
+
+ result = -1;
+ }
+ break;
+
+ case tok_undefined:
+ collate->kind = undefined;
+ collate->current_element = &collate->undefined;
+ break;
+
+ case tok_ellipsis:
+ if (collate->was_ellipsis)
+ {
+ lr_error (lr, _("\
+two lines in a row containing `...' are not allowed"));
+ result = -1;
+ }
+ else if (collate->kind != character)
+ {
+ /* An ellipsis requires the previous line to be an
+ character definition. */
+ lr_error (lr, _("\
+line before ellipsis does not contain definition for character constant"));
+ lr_ignore_rest (lr, 0);
+ result = -1;
+ }
+ else
+ collate->kind = ellipsis;
+ break;
+
+ default:
+ assert (! "illegal token in `collate_order_elem'");
+ }
+
+ /* Now it's time to handle the ellipsis in the previous line. We do
+ this only when the last line contained an definition for an
+ character, the current line also defines an character, the
+ character code for the later is bigger than the former. */
+ if (collate->was_ellipsis)
+ {
+ if (collate->kind != character)
+ {
+ lr_error (lr, _("\
+line after ellipsis must contain character definition"));
+ lr_ignore_rest (lr, 0);
+ result = -1;
+ }
+ else if (collate->last_char > value)
+ {
+ lr_error (lr, _("end point of ellipsis range is bigger then start"));
+ lr_ignore_rest (lr, 0);
+ result = -1;
+ }
+ else
+ {
+ /* We can fill the arrays with the information we need. */
+ wchar_t name[2];
+ unsigned int *data;
+ size_t *ptr;
+ size_t cnt;
+
+ name[0] = collate->last_char + 1;
+ name[1] = L'\0';
+
+ data = (unsigned int *) alloca ((collate->nrules + collate->nweight)
+ * sizeof (unsigned int));
+ ptr = (size_t *) alloca (collate->nrules * sizeof (size_t));
+
+ if (data == NULL || ptr == NULL)
+ error (4, 0, _("memory exhausted"));
+
+ /* Prepare data. Because the characters covered by an
+ ellipsis all have equal values we prepare the data once
+ and only change the variable number (if there are any).
+ PTR[...] will point to the entries which will have to be
+ fixed during the output loop. */
+ for (cnt = 0; cnt < collate->nrules; ++cnt)
+ {
+ data[cnt] = collate->weight_cnt[cnt];
+ ptr[cnt] = (cnt == 0
+ ? collate->nweight
+ : ptr[cnt - 1] + collate->weight_cnt[cnt - 1]);
+ }
+
+ for (cnt = 0; cnt < collate->nweight; ++cnt)
+ data[collate->nrules + cnt] = collate->weight[cnt];
+
+ for (cnt = 0; cnt < collate->nrules; ++cnt)
+ if (data[ptr[cnt]] != ELLIPSIS_CHAR)
+ ptr[cnt] = 0;
+
+ while (name[0] <= value)
+ {
+ element_t *pelem;
+
+ pelem = (element_t *) obstack_alloc (&collate->element_mem,
+ sizeof (element_t));
+ if (pelem == NULL)
+ error (4, 0, _("memory exhausted"));
+
+ pelem->name
+ = (const wchar_t *) obstack_copy (&collate->element_mem,
+ name, 2 * sizeof (wchar_t));
+ pelem->this_weight = ++collate->order_cnt;
+
+ pelem->ordering_len = collate->nweight;
+ pelem->ordering
+ = (unsigned int *) obstack_copy (&collate->element_mem, data,
+ (collate->nrules
+ * pelem->ordering_len)
+ * sizeof (unsigned int));
+
+ /* `...' weights need to be adjusted. */
+ for (cnt = 0; cnt < collate->nrules; ++cnt)
+ if (ptr[cnt] != 0)
+ pelem->ordering[ptr[cnt]] = pelem->this_weight;
+
+ /* Insert new entry into result table. */
+ if (find_entry (&collate->result, name, sizeof (wchar_t),
+ (void *) &pelem->next) >= 0)
+ {
+ if (set_entry (&collate->result, name, sizeof (wchar_t),
+ (void *) pelem->next) < 0)
+ error (4, 0, _("cannot insert into result table"));
+ }
+ else
+ if (insert_entry (&collate->result, name, sizeof (wchar_t),
+ (void *) pelem->next) < 0)
+ error (4, 0, _("cannot insert into result table"));
+
+ /* Increment counter. */
+ ++name[0];
+ }
+ }
+ }
+
+ /* Reset counters for weights. */
+ collate->weight_idx = 0;
+ collate->nweight = 0;
+ for (i = 0; i < collate->nrules; ++i)
+ collate->weight_cnt[i] = 0;
+ collate->current_patch = NULL;
+
+ return result;
+}
+
+
+int
+collate_weight_bsymbol (struct linereader *lr, struct localedef_t *locale,
+ struct token *code, struct charset_t *charset)
+{
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+ unsigned int here_weight;
+ wchar_t value;
+ void *tmp;
+
+ assert (code->tok == tok_bsymbol);
+
+ value = charset_find_value (charset, code->val.str.start, code->val.str.len);
+ if (value != ILLEGAL_CHAR_VALUE)
+ {
+ element_t *runp;
+
+ if (find_entry (&collate->result, &value, sizeof (wchar_t),
+ (void *)&runp) < 0)
+ runp = NULL;
+
+ while (runp != NULL
+ && (runp->name[0] != value || runp->name[1] != L'\0'))
+ runp = runp->next;
+
+ here_weight = runp == NULL ? 0 : runp->this_weight;
+ }
+ else if (find_entry (&collate->elements, code->val.str.start,
+ code->val.str.len, &tmp) >= 0)
+ {
+ element_t *runp = (element_t *) tmp;
+
+ here_weight = runp->this_weight;
+ }
+ else if (find_entry (&collate->symbols, code->val.str.start,
+ code->val.str.len, &tmp) >= 0)
+ {
+ here_weight = (unsigned int) tmp;
+ }
+ else
+ {
+ if (verbose)
+ lr_error (lr, _("unknown symbol `%.*s': line ignored"),
+ code->val.str.len, code->val.str.start);
+ lr_ignore_rest (lr, 0);
+ return -1;
+ }
+
+ /* When we currently work on a collation symbol we do not expect any
+ weight. */
+ if (collate->kind == symbol)
+ {
+ lr_error (lr, _("\
+specification of sorting weight for collation symbol does not make sense"));
+ lr_ignore_rest (lr, 0);
+ return -1;
+ }
+
+ /* Add to the current collection of weights. */
+ if (collate->nweight >= collate->nweight_max)
+ {
+ collate->nweight_max *= 2;
+ collate->weight = (unsigned int *) xrealloc (collate->weight,
+ collate->nweight_max);
+ }
+
+ /* If the weight is currently not known, we remember to patch the
+ resulting tables. */
+ if (here_weight == 0)
+ {
+ patch_t *newp;
+
+ newp = (patch_t *) obstack_alloc (&collate->element_mem,
+ sizeof (patch_t));
+ newp->fname = lr->fname;
+ newp->lineno = lr->lineno;
+ newp->token = (const char *) obstack_copy0 (&collate->element_mem,
+ code->val.str.start,
+ code->val.str.len);
+ newp->where.idx = collate->nweight++;
+ newp->next = collate->current_patch;
+ collate->current_patch = newp;
+ }
+ else
+ collate->weight[collate->nweight++] = here_weight;
+ ++collate->weight_cnt[collate->weight_idx];
+
+ return 0;
+}
+
+
+int
+collate_next_weight (struct linereader *lr, struct localedef_t *locale)
+{
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+
+ if (collate->kind == symbol)
+ {
+ lr_error (lr, _("\
+specification of sorting weight for collation symbol does not make sense"));
+ lr_ignore_rest (lr, 0);
+ return -1;
+ }
+
+ ++collate->weight_idx;
+ if (collate->weight_idx >= collate->nrules)
+ {
+ lr_error (lr, _("too many weights"));
+ lr_ignore_rest (lr, 0);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+collate_simple_weight (struct linereader *lr, struct localedef_t *locale,
+ struct token *code, struct charset_t *charset)
+{
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+ unsigned int value = 0;
+
+ /* There current tokens can be `IGNORE', `...', or a string. */
+ switch (code->tok)
+ {
+ case tok_ignore:
+ /* This token is allowed in all situations. */
+ value = IGNORE_CHAR;
+ break;
+
+ case tok_ellipsis:
+ /* The ellipsis is only allowed for the `...' or `UNDEFINED'
+ entry. */
+ if (collate->kind != ellipsis && collate->kind != undefined)
+ {
+ lr_error (lr, _("\
+`...' must only be used in `...' and `UNDEFINED' entries"));
+ lr_ignore_rest (lr, 0);
+ return -1;
+ }
+ value = ELLIPSIS_CHAR;
+ break;
+
+ case tok_string:
+ /* This can become difficult. We have to get the weights which
+ correspind the the single wide chars in the string. But some
+ of the `chars' might not be real characters, but collation
+ elements or symbols. And so the string decoder might have
+ signaled errors. The string at this point is not translated.
+ I.e., all <...> sequences are still there. */
+ {
+ char *runp = code->val.str.start;
+ void *tmp;
+
+ while (*runp != '\0')
+ {
+ char *startp = (char *) runp;
+ char *putp = (char *) runp;
+ wchar_t wch;
+
+ /* Lookup weight for char and store it. */
+ if (*runp == '<')
+ {
+ while (*++runp != '\0' && *runp != '>')
+ {
+ if (*runp == lr->escape_char)
+ if (*++runp == '\0')
+ {
+ lr_error (lr, _("unterminated weight name"));
+ lr_ignore_rest (lr, 0);
+ return -1;
+ }
+ *putp++ = *runp;
+ }
+ if (*runp == '>')
+ ++runp;
+
+ if (putp == startp)
+ {
+ lr_error (lr, _("empty weight name: line ignored"));
+ lr_ignore_rest (lr, 0);
+ return -1;
+ }
+
+ wch = charset_find_value (charset, startp, putp - startp);
+ if (wch != ILLEGAL_CHAR_VALUE)
+ {
+ element_t *pelem;
+
+ if (find_entry (&collate->result, &wch, sizeof (wchar_t),
+ (void *)&pelem) < 0)
+ pelem = NULL;
+
+ while (pelem != NULL
+ && (pelem->name[0] != wch
+ || pelem->name[1] != L'\0'))
+ pelem = pelem->next;
+
+ value = pelem == NULL ? 0 : pelem->this_weight;
+ }
+ else if (find_entry (&collate->elements, startp, putp - startp,
+ &tmp) >= 0)
+ {
+ element_t *pelem = (element_t *) tmp;
+
+ value = pelem->this_weight;
+ }
+ else if (find_entry (&collate->symbols, startp, putp - startp,
+ &tmp) >= 0)
+ {
+ value = (unsigned int) tmp;
+ }
+ else
+ {
+ if (verbose)
+ lr_error (lr, _("unknown symbol `%.*s': line ignored"),
+ putp - startp, startp);
+ lr_ignore_rest (lr, 0);
+ return -1;
+ }
+ }
+ else
+ {
+ element_t *wp;
+ wchar_t wch;
+
+ if (*runp == lr->escape_char)
+ {
+ static char digits[] = "0123456789abcdef";
+ char *dp;
+ int base;
+
+ ++runp;
+ if (tolower (*runp) == 'x')
+ {
+ ++runp;
+ base = 16;
+ }
+ else if (tolower (*runp) == 'd')
+ {
+ ++runp;
+ base = 10;
+ }
+ else
+ base = 8;
+
+ dp = strchr (digits, tolower (*runp));
+ if (dp == NULL || (dp - digits) >= base)
+ {
+ illegal_char:
+ lr_error (lr, _("\
+illegal character constant in string"));
+ lr_ignore_rest (lr, 0);
+ return -1;
+ }
+ wch = dp - digits;
+ ++runp;
+
+ dp = strchr (digits, tolower (*runp));
+ if (dp == NULL || (dp - digits) >= base)
+ goto illegal_char;
+ wch *= base;
+ wch += dp - digits;
+ ++runp;
+
+ if (base != 16)
+ {
+ dp = strchr (digits, tolower (*runp));
+ if (dp != NULL && (dp - digits < base))
+ {
+ wch *= base;
+ wch += dp - digits;
+ ++runp;
+ }
+ }
+ }
+ else
+ wch = (wchar_t) *runp++;
+
+ /* Lookup the weight for WCH. */
+ if (find_entry (&collate->result, &wch, sizeof (wch),
+ (void *)&wp) < 0)
+ wp = NULL;
+
+ while (wp != NULL
+ && (wp->name[0] != wch || wp->name[1] != L'\0'))
+ wp = wp->next;
+
+ value = wp == NULL ? 0 : wp->this_weight;
+
+ /* To get the correct name for the error message. */
+ putp = runp;
+
+ /**************************************************\
+ |* I know here is something wrong. Characters in *|
+ |* the string which are not in the <...> form *|
+ |* cannot be declared forward for now!!! *|
+ \**************************************************/
+ }
+
+ /* Store in weight array. */
+ if (collate->nweight >= collate->nweight_max)
+ {
+ collate->nweight_max *= 2;
+ collate->weight
+ = (unsigned int *) xrealloc (collate->weight,
+ collate->nweight_max);
+ }
+
+ if (value == 0)
+ {
+ patch_t *newp;
+
+ newp = (patch_t *) obstack_alloc (&collate->element_mem,
+ sizeof (patch_t));
+ newp->fname = lr->fname;
+ newp->lineno = lr->lineno;
+ newp->token
+ = (const char *) obstack_copy0 (&collate->element_mem,
+ startp, putp - startp);
+ newp->where.idx = collate->nweight++;
+ newp->next = collate->current_patch;
+ collate->current_patch = newp;
+ }
+ else
+ collate->weight[collate->nweight++] = value;
+ ++collate->weight_cnt[collate->weight_idx];
+ }
+ }
+ return 0;
+
+ default:
+ assert (! "should not happen");
+ }
+
+
+ if (collate->nweight >= collate->nweight_max)
+ {
+ collate->nweight_max *= 2;
+ collate->weight = (unsigned int *) xrealloc (collate->weight,
+ collate->nweight_max);
+ }
+
+ collate->weight[collate->nweight++] = value;
+ ++collate->weight_cnt[collate->weight_idx];
+
+ return 0;
+}
+
+
+void
+collate_end_weight (struct linereader *lr, struct localedef_t *locale)
+{
+ struct locale_collate_t *collate = locale->categories[LC_COLLATE].collate;
+ element_t *pelem = collate->current_element;
+
+ if (collate->kind == symbol)
+ {
+ /* We don't have to do anything. */
+ collate->was_ellipsis = 0;
+ return;
+ }
+
+ if (collate->kind == ellipsis)
+ {
+ /* Before the next line is processed the ellipsis is handled. */
+ collate->was_ellipsis = 1;
+ return;
+ }
+
+ assert (collate->kind == character || collate->kind == element
+ || collate->kind == undefined);
+
+ /* Fill in the missing weights. */
+ while (++collate->weight_idx < collate->nrules)
+ {
+ collate->weight[collate->nweight++] = pelem->this_weight;
+ ++collate->weight_cnt[collate->weight_idx];
+ }
+
+ /* Now we know how many ordering weights the current
+ character/element has. Allocate room in the element structure
+ and copy information. */
+ pelem->ordering_len = collate->nweight;
+
+ /* First we write an array with the number of values for each
+ weight. */
+ obstack_grow (&collate->element_mem, collate->weight_cnt,
+ collate->nrules * sizeof (unsigned int));
+
+ /* Now the weights itselves. */
+ obstack_grow (&collate->element_mem, collate->weight,
+ collate->nweight * sizeof (unsigned int));
+
+ /* Get result. */
+ pelem->ordering = obstack_finish (&collate->element_mem);
+
+ /* Now we handle the "patches". */
+ while (collate->current_patch != NULL)
+ {
+ patch_t *this_patch;
+
+ this_patch = collate->current_patch;
+
+ this_patch->where.pos = &pelem->ordering[collate->nrules
+ + this_patch->where.idx];
+
+ collate->current_patch = this_patch->next;
+ this_patch->next = collate->all_patches;
+ collate->all_patches = this_patch;
+ }
+
+ /* Set information for next round. */
+ collate->was_ellipsis = 0;
+ if (collate->kind != undefined)
+ collate->last_char = pelem->name[0];
+}
diff --git a/locale/programs/ld-ctype.c b/locale/programs/ld-ctype.c
new file mode 100644
index 0000000000..c1cc8e53b8
--- /dev/null
+++ b/locale/programs/ld-ctype.c
@@ -0,0 +1,1310 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <endian.h>
+#include <limits.h>
+#include <string.h>
+
+#include "locales.h"
+#include "localeinfo.h"
+#include "langinfo.h"
+#include "locfile-token.h"
+#include "stringtrans.h"
+
+/* Uncomment the following line in the production version. */
+/* define NDEBUG 1 */
+#include <assert.h>
+
+
+void *xmalloc (size_t __n);
+void *xcalloc (size_t __n, size_t __s);
+void *xrealloc (void *__ptr, size_t __n);
+
+
+/* The bit used for representing a special class. */
+#define BITPOS(class) ((class) - tok_upper)
+#define BIT(class) (1 << BITPOS (class))
+
+#define ELEM(ctype, collection, idx, value) \
+ *find_idx (ctype, &ctype->collection idx, &ctype->collection##_max idx, \
+ &ctype->collection##_act idx, value)
+
+#define SWAPU32(w) \
+ (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24))
+
+#define SWAPU16(w) \
+ ((((w) >> 8) & 0xff) | (((w) & 0xff) << 8))
+
+
+/* To be compatible with former implementations we for now restrict
+ the number of bits for character classes to 16. When compatibility
+ is not necessary anymore increase the number to 32. */
+#define char_class_t u16_t
+#define CHAR_CLASS_TRANS SWAPU16
+#define char_class32_t u32_t
+#define CHAR_CLASS32_TRANS SWAPU32
+
+
+/* The real definition of the struct for the LC_CTYPE locale. */
+struct locale_ctype_t
+{
+ unsigned int *charnames;
+ size_t charnames_max;
+ size_t charnames_act;
+
+ /* We will allow up to 8 * sizeof(u32_t) - 1 character classes. */
+#define MAX_NR_CHARCLASS (8 * sizeof (u32_t) - 1)
+ int nr_charclass;
+ const char *classnames[MAX_NR_CHARCLASS];
+ unsigned long int current_class_mask;
+ unsigned int last_class_char;
+ u32_t *class_collection;
+ size_t class_collection_max;
+ size_t class_collection_act;
+ unsigned long int class_done;
+
+ /* If the following number ever turns out to be too small simply
+ increase it. But I doubt it will. --drepper@gnu */
+#define MAX_NR_CHARMAP 16
+ const char *mapnames[MAX_NR_CHARMAP];
+ u32_t *map_collection[MAX_NR_CHARMAP];
+ unsigned int map_collection_max[MAX_NR_CHARMAP];
+ unsigned int map_collection_act[MAX_NR_CHARMAP];
+ size_t map_collection_nr;
+ size_t last_map_idx;
+ unsigned int from_map_char;
+ int toupper_done;
+ int tolower_done;
+
+ /* The arrays for the binary representation. */
+ u32_t plane_size;
+ u32_t plane_cnt;
+ char_class_t *ctype_b;
+ char_class32_t *ctype32_b;
+ u32_t *names_el;
+ u32_t *names_eb;
+ u32_t **map_eb;
+ u32_t **map_el;
+ u32_t *class_name_ptr;
+ u32_t *map_name_ptr;
+};
+
+
+/* Prototypes for local functions. */
+static void ctype_class_newP (struct linereader *lr,
+ struct locale_ctype_t *ctype, const char *name);
+static void ctype_map_newP (struct linereader *lr,
+ struct locale_ctype_t *ctype,
+ const char *name, struct charset_t *charset);
+static u32_t *find_idx (struct locale_ctype_t *ctype, u32_t **table,
+ size_t *max, size_t *act, unsigned int idx);
+static void set_class_defaults (struct locale_ctype_t *ctype,
+ struct charset_t *charset);
+static void allocate_arrays (struct locale_ctype_t *ctype);
+
+
+void
+ctype_startup (struct linereader *lr, struct localedef_t *locale,
+ struct charset_t *charset)
+{
+ unsigned int cnt;
+ struct locale_ctype_t *ctype;
+
+ /* It is important that we always use UCS1 encoding for strings now. */
+ encoding_method = ENC_UCS1;
+
+ /* Allocate the needed room. */
+ locale->categories[LC_CTYPE].ctype = ctype =
+ (struct locale_ctype_t *) xmalloc (sizeof (struct locale_ctype_t));
+
+ /* We have no names seen yet. */
+ ctype->charnames_max = charset->mb_cur_max == 1 ? 256 : 512;
+ ctype->charnames =
+ (unsigned int *) xmalloc (ctype->charnames_max * sizeof (unsigned int));
+ for (cnt = 0; cnt < 256; ++cnt)
+ ctype->charnames[cnt] = cnt;
+ ctype->charnames_act = 256;
+
+ /* Fill character class information. */
+ ctype->nr_charclass = 0;
+ ctype->current_class_mask = 0;
+ ctype->last_class_char = ILLEGAL_CHAR_VALUE;
+ /* The order of the following instructions determines the bit
+ positions! */
+ ctype_class_newP (lr, ctype, "upper");
+ ctype_class_newP (lr, ctype, "lower");
+ ctype_class_newP (lr, ctype, "alpha");
+ ctype_class_newP (lr, ctype, "digit");
+ ctype_class_newP (lr, ctype, "xdigit");
+ ctype_class_newP (lr, ctype, "space");
+ ctype_class_newP (lr, ctype, "print");
+ ctype_class_newP (lr, ctype, "graph");
+ ctype_class_newP (lr, ctype, "blank");
+ ctype_class_newP (lr, ctype, "cntrl");
+ ctype_class_newP (lr, ctype, "punct");
+ ctype_class_newP (lr, ctype, "alnum");
+
+ ctype->class_collection_max = charset->mb_cur_max == 1 ? 256 : 512;
+ ctype->class_collection = (u32_t *) xmalloc (sizeof (unsigned long int)
+ * ctype->class_collection_max);
+ memset (ctype->class_collection, '\0',
+ sizeof (unsigned long int) * ctype->class_collection_max);
+ ctype->class_collection_act = 256;
+
+ /* Fill character map information. */
+ ctype->map_collection_nr = 0;
+ ctype->last_map_idx = MAX_NR_CHARMAP;
+ ctype->from_map_char = ILLEGAL_CHAR_VALUE;
+ ctype_map_newP (lr, ctype, "toupper", charset);
+ ctype_map_newP (lr, ctype, "tolower", charset);
+
+ /* Fill first 256 entries in `toupper' and `tolower' arrays. */
+ for (cnt = 0; cnt < 256; ++cnt)
+ {
+ ctype->map_collection[0][cnt] = cnt;
+ ctype->map_collection[1][cnt] = cnt;
+ }
+}
+
+
+void
+ctype_finish (struct localedef_t *locale, struct charset_t *charset)
+{
+ /* See POSIX.2, table 2-6 for the meaning of the following table. */
+#define NCLASS 12
+ static const struct
+ {
+ const char *name;
+ const char allow[NCLASS];
+ }
+ valid_table[NCLASS] =
+ {
+ /* The order is important. See token.h for more information.
+ M = Always, D = Default, - = Permitted, X = Mutually exclusive */
+ { "upper", "--MX-XDDXXX-" },
+ { "lower", "--MX-XDDXXX-" },
+ { "alpha", "---X-XDDXXX-" },
+ { "digit", "XXX--XDDXXX-" },
+ { "xdigit", "-----XDDXXX-" },
+ { "space", "XXXXX------X" },
+ { "print", "---------X--" },
+ { "graph", "---------X--" },
+ { "blank", "XXXXXM-----X" },
+ { "cntrl", "XXXXX-XX--XX" },
+ { "punct", "XXXXX-DD-X-X" },
+ { "alnum", "-----XDDXXX-" }
+ };
+ size_t cnt;
+ int cls1, cls2;
+ unsigned int space_value;
+ struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
+
+ /* Set default value for classes not specified. */
+ set_class_defaults (ctype, charset);
+
+ /* Check according to table. */
+ for (cnt = 0; cnt < ctype->class_collection_max; ++cnt)
+ {
+ unsigned long int tmp;
+
+ tmp = ctype->class_collection[cnt];
+ if (tmp == 0)
+ continue;
+
+ for (cls1 = 0; cls1 < NCLASS; ++cls1)
+ if ((tmp & (1 << cls1)) != 0)
+ for (cls2 = 0; cls2 < NCLASS; ++cls2)
+ if (valid_table[cls1].allow[cls2] != '-')
+ {
+ int eq = (tmp & (1 << cls2)) != 0;
+ switch (valid_table[cls1].allow[cls2])
+ {
+ case 'M':
+ if (!eq)
+ {
+ char buf[17];
+ char *cp = buf;
+ unsigned int value;
+
+ value = ctype->charnames[cnt];
+
+ if ((value & 0xff000000) != 0)
+ cp += sprintf (cp, "\\%o", (value >> 24) & 0xff);
+ if ((value & 0xffff0000) != 0)
+ cp += sprintf (cp, "\\%o", (value >> 16) & 0xff);
+ if ((value & 0xffffff00) != 0)
+ cp += sprintf (cp, "\\%o", (value >> 8) & 0xff);
+ sprintf (cp, "\\%o", value & 0xff);
+
+ error (0, 0, _("\
+character %s'%s' in class `%s' must be in class `%s'"), value > 256 ? "L" : "",
+ cp, valid_table[cls1].name,
+ valid_table[cls2].name);
+ }
+ break;
+
+ case 'X':
+ if (eq)
+ {
+ char buf[17];
+ char *cp = buf;
+ unsigned int value;
+
+ value = ctype->charnames[cnt];
+
+ if ((value & 0xff000000) != 0)
+ cp += sprintf (cp, "\\%o", value >> 24);
+ if ((value & 0xffff0000) != 0)
+ cp += sprintf (cp, "\\%o", (value >> 16) & 0xff);
+ if ((value & 0xffffff00) != 0)
+ cp += sprintf (cp, "\\%o", (value >> 8) & 0xff);
+ sprintf (cp, "\\%o", value & 0xff);
+
+ error (0, 0, _("\
+character %s'%s' in class `%s' must not be in class `%s'"),
+ value > 256 ? "L" : "", cp,
+ valid_table[cls1].name, valid_table[cls2].name);
+ }
+ break;
+
+ case 'D':
+ ctype->class_collection[cnt] |= 1 << cls2;
+ break;
+
+ default:
+ error (5, 0, _("internal error in %s, line %u"),
+ __FUNCTION__, __LINE__);
+ }
+ }
+ }
+
+ /* ... and now test <SP> as a special case. */
+ space_value = charset_find_value (charset, "SP", 2);
+ if (space_value == ILLEGAL_CHAR_VALUE)
+ error (0, 0, _("character <SP> not defined in character map"));
+ else if ((cnt = BITPOS (tok_space),
+ (ELEM (ctype, class_collection, , space_value)
+ & BIT (tok_space)) == 0)
+ || (cnt = BITPOS (tok_blank),
+ (ELEM (ctype, class_collection, , space_value)
+ & BIT (tok_blank)) == 0))
+ error (0, 0, _("<SP> character not in class `%s'"),
+ valid_table[cnt].name);
+ else if ((cnt = BITPOS (tok_punct),
+ (ELEM (ctype, class_collection, , space_value)
+ & BIT (tok_punct)) != 0)
+ || (cnt = BITPOS (tok_graph),
+ (ELEM (ctype, class_collection, , space_value)
+ & BIT (tok_graph))
+ != 0))
+ error (0, 0, _("<SP> character must not be in class `%s'"),
+ valid_table[cnt].name);
+ else
+ ELEM (ctype, class_collection, , space_value) |= BIT (tok_print);
+}
+
+
+void
+ctype_output (struct localedef_t *locale, const char *output_path)
+{
+ struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
+ const size_t nelems = (_NL_ITEM_INDEX (_NL_NUM_LC_CTYPE)
+ + 2 * (ctype->map_collection_nr - 2));
+ struct iovec iov[2 + nelems + (ctype->nr_charclass + 1)
+ + (ctype->map_collection_nr + 1)];
+ struct locale_file data;
+ u32_t idx[nelems];
+ size_t elem, cnt, offset;
+
+
+ if ((locale->binary & (1 << LC_CTYPE)) != 0)
+ {
+ iov[0].iov_base = ctype;
+ iov[0].iov_len = locale->len[LC_CTYPE];
+
+ write_locale_data (output_path, "LC_CTYPE", 1, iov);
+
+ return;
+ }
+
+
+ /* Now prepare the output: Find the sizes of the table we can use. */
+ allocate_arrays (ctype);
+
+ data.magic = LIMAGIC (LC_CTYPE);
+ data.n = nelems;
+ iov[0].iov_base = (void *) &data;
+ iov[0].iov_len = sizeof (data);
+
+ iov[1].iov_base = (void *) idx;
+ iov[1].iov_len = sizeof (idx);
+
+ idx[0] = iov[0].iov_len + iov[1].iov_len;
+ offset = 0;
+
+ for (elem = 0; elem < nelems; ++elem)
+ {
+ if (elem < _NL_ITEM_INDEX (_NL_NUM_LC_CTYPE))
+ switch (elem)
+ {
+#define CTYPE_DATA(name, base, len) \
+ case _NL_ITEM_INDEX (name): \
+ iov[2 + elem].iov_base = base; \
+ iov[2 + elem].iov_len = len; \
+ break
+
+ CTYPE_DATA (_NL_CTYPE_CLASS,
+ ctype->ctype_b,
+ (256 + 128) * sizeof (char_class_t));
+
+ CTYPE_DATA (_NL_CTYPE_TOUPPER_EB,
+ ctype->map_eb[0],
+ (ctype->plane_size * ctype->plane_cnt + 128)
+ * sizeof (u32_t));
+ CTYPE_DATA (_NL_CTYPE_TOLOWER_EB,
+ ctype->map_eb[1],
+ (ctype->plane_size * ctype->plane_cnt + 128)
+ * sizeof (u32_t));
+
+ CTYPE_DATA (_NL_CTYPE_TOUPPER_EL,
+ ctype->map_el[0],
+ (ctype->plane_size * ctype->plane_cnt + 128)
+ * sizeof (u32_t));
+ CTYPE_DATA (_NL_CTYPE_TOLOWER_EL,
+ ctype->map_el[1],
+ (ctype->plane_size * ctype->plane_cnt + 128)
+ * sizeof (u32_t));
+
+ CTYPE_DATA (_NL_CTYPE_CLASS32,
+ ctype->ctype32_b,
+ (ctype->plane_size * ctype->plane_cnt
+ * sizeof (char_class32_t)));
+
+ CTYPE_DATA (_NL_CTYPE_NAMES_EB,
+ ctype->names_eb,
+ ctype->plane_size * ctype->plane_cnt * sizeof (u32_t));
+ CTYPE_DATA (_NL_CTYPE_NAMES_EL,
+ ctype->names_el,
+ ctype->plane_size * ctype->plane_cnt * sizeof (u32_t));
+
+ CTYPE_DATA (_NL_CTYPE_HASH_SIZE,
+ &ctype->plane_size, sizeof (u32_t));
+ CTYPE_DATA (_NL_CTYPE_HASH_LAYERS,
+ &ctype->plane_cnt, sizeof (u32_t));
+
+ CTYPE_DATA (_NL_CTYPE_CLASS_NAMES,
+ ctype->class_name_ptr,
+ ctype->nr_charclass * sizeof (u32_t));
+ CTYPE_DATA (_NL_CTYPE_MAP_NAMES,
+ ctype->map_name_ptr,
+ ctype->map_collection_nr * sizeof (u32_t));
+
+ CTYPE_DATA (_NL_CTYPE_WIDTH,
+ NULL, 0); /* Not yet implemented. */
+
+ default:
+ assert (! "unknown CTYPE element");
+ }
+ else
+ {
+ /* Handle extra maps. */
+ size_t nr = (elem - _NL_ITEM_INDEX (_NL_NUM_LC_CTYPE)) >> 1;
+
+ if (((elem - _NL_ITEM_INDEX (_NL_NUM_LC_CTYPE)) & 1) == 0)
+ iov[2 + elem].iov_base = ctype->map_eb[nr];
+ else
+ iov[2 + elem].iov_base = ctype->map_el[nr];
+
+ iov[2 + elem].iov_len = ((ctype->plane_size * ctype->plane_cnt + 128)
+ * sizeof (u32_t));
+ }
+
+ if (elem + 1 < nelems)
+ idx[elem + 1] = idx[elem] + iov[2 + elem].iov_len;
+ }
+
+ offset = idx[elem - 1] + iov[2 + elem - 1].iov_len;
+
+ /* The class name array. */
+ for (cnt = 0; cnt < ctype->nr_charclass; ++cnt, ++elem)
+ {
+ iov[2 + elem].iov_base = (void *) ctype->classnames[cnt];
+ iov[2 + elem].iov_len = strlen (ctype->classnames[cnt]) + 1;
+
+ ctype->class_name_ptr[cnt] = offset;
+ offset += iov[2 + elem].iov_len;
+ }
+ iov[2 + elem].iov_base = (void *) "";
+ iov[2 + elem].iov_len = 1;
+ ++elem;
+
+ /* The map name array. */
+ for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt, ++elem)
+ {
+ iov[2 + elem].iov_base = (void *) ctype->mapnames[cnt];
+ iov[2 + elem].iov_len = strlen (ctype->mapnames[cnt]) + 1;
+
+ ctype->map_name_ptr[cnt] = offset;
+ offset += iov[2 + elem].iov_len;
+ }
+ iov[2 + elem].iov_base = (void *) "";
+ iov[2 + elem].iov_len = 1;
+ ++elem;
+
+ assert (elem == nelems + ctype->nr_charclass + ctype->map_collection_nr + 2);
+
+ write_locale_data (output_path, "LC_CTYPE", 2 + elem, iov);
+}
+
+
+/* Character class handling. */
+void
+ctype_class_new (struct linereader *lr, struct localedef_t *locale,
+ enum token_t tok, struct token *code,
+ struct charset_t *charset)
+{
+ ctype_class_newP (lr, locale->categories[LC_CTYPE].ctype,
+ code->val.str.start);
+}
+
+
+int
+ctype_is_charclass (struct linereader *lr, struct localedef_t *locale,
+ const char *name)
+{
+ int cnt;
+
+ for (cnt = 0; cnt < locale->categories[LC_CTYPE].ctype->nr_charclass; ++cnt)
+ if (strcmp (name, locale->categories[LC_CTYPE].ctype->classnames[cnt])
+ == 0)
+ return 1;
+
+ return 0;
+}
+
+
+void
+ctype_class_start (struct linereader *lr, struct localedef_t *locale,
+ enum token_t tok, const char *str,
+ struct charset_t *charset)
+{
+ struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
+ int cnt;
+
+ switch (tok)
+ {
+ case tok_upper:
+ str = "upper";
+ break;
+ case tok_lower:
+ str = "lower";
+ break;
+ case tok_alpha:
+ str = "alpha";
+ break;
+ case tok_digit:
+ str = "digit";
+ break;
+ case tok_xdigit:
+ str = "xdigit";
+ break;
+ case tok_space:
+ str = "space";
+ break;
+ case tok_print:
+ str = "print";
+ break;
+ case tok_graph:
+ str = "graph";
+ break;
+ case tok_blank:
+ str = "blank";
+ break;
+ case tok_cntrl:
+ str = "cntrl";
+ break;
+ case tok_punct:
+ str = "punct";
+ break;
+ case tok_alnum:
+ str = "alnum";
+ break;
+ case tok_ident:
+ break;
+ default:
+ assert (! "illegal token as class name: should not happen");
+ }
+
+ for (cnt = 0; cnt < ctype->nr_charclass; ++cnt)
+ if (strcmp (str, ctype->classnames[cnt]) == 0)
+ break;
+
+ if (cnt >= ctype->nr_charclass)
+ assert (! "unknown class in class definition: should not happen");
+
+ ctype->class_done |= BIT (tok);
+
+ ctype->current_class_mask = 1 << cnt;
+ ctype->last_class_char = ILLEGAL_CHAR_VALUE;
+}
+
+
+void
+ctype_class_from (struct linereader *lr, struct localedef_t *locale,
+ struct token *code, struct charset_t *charset)
+{
+ struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
+ unsigned int value;
+
+ value = charset_find_value (charset, code->val.str.start, code->val.str.len);
+
+ ctype->last_class_char = value;
+
+ if (value == ILLEGAL_CHAR_VALUE)
+ /* In the LC_CTYPE category it is no error when a character is
+ not found. This has to be ignored silently. */
+ return;
+
+ *find_idx (ctype, &ctype->class_collection, &ctype->class_collection_max,
+ &ctype->class_collection_act, value)
+ |= ctype->current_class_mask;
+}
+
+
+void
+ctype_class_to (struct linereader *lr, struct localedef_t *locale,
+ struct token *code, struct charset_t *charset)
+{
+ struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
+ unsigned int value, cnt;
+
+ value = charset_find_value (charset, code->val.str.start, code->val.str.len);
+
+ assert (value >= ctype->last_class_char);
+
+ for (cnt = ctype->last_class_char + 1; cnt <= value; ++cnt)
+ *find_idx (ctype, &ctype->class_collection, &ctype->class_collection_max,
+ &ctype->class_collection_act, cnt)
+ |= ctype->current_class_mask;
+
+ ctype->last_class_char = ILLEGAL_CHAR_VALUE;
+}
+
+
+void
+ctype_class_end (struct linereader *lr, struct localedef_t *locale)
+{
+ struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
+
+ /* We have no special actions to perform here. */
+ ctype->current_class_mask = 0;
+ ctype->last_class_char = ILLEGAL_CHAR_VALUE;
+}
+
+
+/* Character map handling. */
+void
+ctype_map_new (struct linereader *lr, struct localedef_t *locale,
+ enum token_t tok, struct token *code,
+ struct charset_t *charset)
+{
+ ctype_map_newP (lr, locale->categories[LC_CTYPE].ctype,
+ code->val.str.start, charset);
+}
+
+
+int
+ctype_is_charmap (struct linereader *lr, struct localedef_t *locale,
+ const char *name)
+{
+ struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
+ size_t cnt;
+
+ for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt)
+ if (strcmp (name, ctype->mapnames[cnt]) == 0)
+ return 1;
+
+ return 0;
+}
+
+
+void
+ctype_map_start (struct linereader *lr, struct localedef_t *locale,
+ enum token_t tok, const char *name, struct charset_t *charset)
+{
+ struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
+ size_t cnt;
+
+ switch (tok)
+ {
+ case tok_toupper:
+ ctype->toupper_done = 1;
+ name = "toupper";
+ break;
+ case tok_tolower:
+ ctype->tolower_done = 1;
+ name = "tolower";
+ break;
+ case tok_ident:
+ break;
+ default:
+ assert (! "unknown token in category `LC_CTYPE' should not happen");
+ }
+
+ for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt)
+ if (strcmp (name, ctype->mapnames[cnt]) == 0)
+ break;
+
+ if (cnt == ctype->map_collection_nr)
+ assert (! "unknown token in category `LC_CTYPE' should not happen");
+
+ ctype->last_map_idx = cnt;
+ ctype->from_map_char = ILLEGAL_CHAR_VALUE;
+}
+
+
+void
+ctype_map_from (struct linereader *lr, struct localedef_t *locale,
+ struct token *code, struct charset_t *charset)
+{
+ struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
+ unsigned int value;
+
+ value = charset_find_value (charset, code->val.str.start, code->val.str.len);
+
+ if (value == ILLEGAL_CHAR_VALUE)
+ /* In the LC_CTYPE category it is no error when a character is
+ not found. This has to be ignored silently. */
+ return;
+
+ assert (ctype->last_map_idx < ctype->map_collection_nr);
+
+ ctype->from_map_char = value;
+}
+
+
+void
+ctype_map_to (struct linereader *lr, struct localedef_t *locale,
+ struct token *code, struct charset_t *charset)
+{
+ struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
+ unsigned int value;
+
+ value = charset_find_value (charset, code->val.str.start, code->val.str.len);
+
+ if (ctype->from_map_char == ILLEGAL_CHAR_VALUE
+ || value == ILLEGAL_CHAR_VALUE)
+ {
+ /* In the LC_CTYPE category it is no error when a character is
+ not found. This has to be ignored silently. */
+ ctype->from_map_char = ILLEGAL_CHAR_VALUE;
+ return;
+ }
+
+ *find_idx (ctype, &ctype->map_collection[ctype->last_map_idx],
+ &ctype->map_collection_max[ctype->last_map_idx],
+ &ctype->map_collection_act[ctype->last_map_idx],
+ ctype->from_map_char) = value;
+
+ ctype->from_map_char = ILLEGAL_CHAR_VALUE;
+}
+
+
+void
+ctype_map_end (struct linereader *lr, struct localedef_t *locale)
+{
+ struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
+
+ ctype->last_map_idx = MAX_NR_CHARMAP;
+ ctype->from_map_char = ILLEGAL_CHAR_VALUE;
+}
+
+
+/* Local functions. */
+static void
+ctype_class_newP (struct linereader *lr, struct locale_ctype_t *ctype,
+ const char *name)
+{
+ int cnt;
+
+ for (cnt = 0; cnt < ctype->nr_charclass; ++cnt)
+ if (strcmp (ctype->classnames[cnt], name) == 0)
+ break;
+
+ if (cnt < ctype->nr_charclass)
+ {
+ lr_error (lr, _("character class `%s' already defined"));
+ return;
+ }
+
+ if (ctype->nr_charclass == MAX_NR_CHARCLASS)
+ /* Exit code 2 is prescribed in P1003.2b. */
+ error (2, 0, _("\
+implementation limit: no more than %d character classes allowed"),
+ MAX_NR_CHARCLASS);
+
+ ctype->classnames[ctype->nr_charclass++] = name;
+}
+
+
+static void
+ctype_map_newP (struct linereader *lr, struct locale_ctype_t *ctype,
+ const char *name, struct charset_t *charset)
+{
+ size_t max_chars = 0;
+ int cnt;
+
+ for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt)
+ {
+ if (strcmp (ctype->mapnames[cnt], name) == 0)
+ break;
+
+ if (max_chars < ctype->map_collection_max[cnt])
+ max_chars = ctype->map_collection_max[cnt];
+ }
+
+ if (cnt < ctype->map_collection_nr)
+ {
+ lr_error (lr, _("character map `%s' already defined"));
+ return;
+ }
+
+ if (ctype->map_collection_nr == MAX_NR_CHARMAP)
+ /* Exit code 2 is prescribed in P1003.2b. */
+ error (2, 0, _("\
+implementation limit: no more than %d character maps allowed"),
+ MAX_NR_CHARMAP);
+
+ ctype->mapnames[cnt] = name;
+
+ if (max_chars == 0)
+ ctype->map_collection_max[cnt] = charset->mb_cur_max == 1 ? 256
+ : 512;
+ else
+ ctype->map_collection_max[cnt] = max_chars;
+
+ ctype->map_collection[cnt] =
+ (u32_t *) xmalloc (sizeof (u32_t) * ctype->map_collection_max[cnt]);
+ memset (ctype->map_collection[cnt], '\0',
+ sizeof (u32_t) * ctype->map_collection_max[cnt]);
+ ctype->map_collection_act[cnt] = 256;
+
+ ++ctype->map_collection_nr;
+}
+
+
+static u32_t *
+find_idx (struct locale_ctype_t *ctype, u32_t **table, size_t *max,
+ size_t *act, unsigned int idx)
+{
+ size_t cnt;
+
+ if (idx < 256)
+ return &(*table)[idx];
+
+ for (cnt = 256; cnt < ctype->charnames_act; ++cnt)
+ if (ctype->charnames[cnt] == idx)
+ break;
+
+ /* We have to distinguish two cases: the names is found or not. */
+ if (cnt == ctype->charnames_act)
+ {
+ /* Extend the name array. */
+ if (ctype->charnames_act == ctype->charnames_max)
+ {
+ ctype->charnames_max *= 2;
+ ctype->charnames = (unsigned int *)
+ xrealloc (ctype->charnames,
+ sizeof (unsigned int) * ctype->charnames_max);
+ }
+ ctype->charnames[ctype->charnames_act++] = idx;
+ }
+
+ if (cnt >= *act)
+ {
+ if (cnt >= *max)
+ {
+ size_t old_max = *max;
+ do
+ *max *= 2;
+ while (*max <= cnt);
+
+ *table =
+ (u32_t *) xrealloc (*table, *max * sizeof (unsigned long int));
+ memset (&(*table)[old_max], '\0', (*max - old_max) * sizeof (u32_t));
+ }
+
+ (*table)[cnt] = 0;
+ *act = cnt;
+ }
+
+ return &(*table)[cnt];
+}
+
+
+static void
+set_class_defaults (struct locale_ctype_t *ctype, struct charset_t *charset)
+{
+ /* These function defines the default values for the classes and conversions
+ according to POSIX.2 2.5.2.1.
+ It may seem that the order of these if-blocks is arbitrary but it is NOT.
+ Don't move them unless you know what you do! */
+
+ void set_default (int bit, int from, int to)
+ {
+ char tmp[2];
+ int ch;
+ /* Define string. */
+ strcpy (tmp, "?");
+
+ for (ch = from; ch <= to; ++ch)
+ {
+ unsigned int value;
+ tmp[0] = ch;
+
+ value = charset_find_value (charset, tmp, 1);
+ if (value == ILLEGAL_CHAR_VALUE)
+ {
+ error (0, 0, _("\
+character `%s' not defined while needed as default value"),
+ tmp);
+ continue;
+ }
+ else
+ ELEM (ctype, class_collection, , value) |= bit;
+ }
+ }
+
+ /* Set default values if keyword was not present. */
+ if ((ctype->class_done & BIT (tok_upper)) == 0)
+ /* "If this keyword [lower] is not specified, the lowercase letters
+ `A' through `Z', ..., shall automatically belong to this class,
+ with implementation defined character values." [P1003.2, 2.5.2.1] */
+ set_default (BIT (tok_upper), 'A', 'Z');
+
+ if ((ctype->class_done & BIT (tok_lower)) == 0)
+ /* "If this keyword [lower] is not specified, the lowercase letters
+ `a' through `z', ..., shall automatically belong to this class,
+ with implementation defined character values." [P1003.2, 2.5.2.1] */
+ set_default (BIT (tok_lower), 'a', 'z');
+
+ if ((ctype->class_done & BIT (tok_alpha)) == 0)
+ {
+ /* Table 2-6 in P1003.2 says that characters in class `upper' or
+ class `lower' *must* be in class `alpha'. */
+ unsigned long int mask = BIT (tok_upper) | BIT (tok_lower);
+ size_t cnt;
+
+ for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
+ if ((ctype->class_collection[cnt] & mask) != 0)
+ ctype->class_collection[cnt] |= BIT (tok_alpha);
+ }
+
+ if ((ctype->class_done & BIT (tok_digit)) == 0)
+ /* "If this keyword [digit] is not specified, the digits `0' through
+ `9', ..., shall automatically belong to this class, with
+ implementation-defined character values." [P1003.2, 2.5.2.1] */
+ set_default (BIT (tok_digit), '0', '9');
+
+ /* "Only characters specified for the `alpha' and `digit' keyword
+ shall be specified. Characters specified for the keyword `alpha'
+ and `digit' are automatically included in this class. */
+ {
+ unsigned long int mask = BIT (tok_alpha) | BIT (tok_digit);
+ size_t cnt;
+
+ for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
+ if ((ctype->class_collection[cnt] & mask) != 0)
+ ctype->class_collection[cnt] |= BIT (tok_alnum);
+ }
+
+ if ((ctype->class_done & BIT (tok_space)) == 0)
+ /* "If this keyword [space] is not specified, the characters <space>,
+ <form-feed>, <newline>, <carriage-return>, <tab>, and
+ <vertical-tab>, ..., shall automatically belong to this class,
+ with implementation-defined character values." [P1003.2, 2.5.2.1] */
+ {
+ unsigned int value;
+
+ value = charset_find_value (charset, "space", 5);
+ if (value == ILLEGAL_CHAR_VALUE)
+ error (0, 0, _("\
+character `%s' not defined while needed as default value"),
+ "<space>");
+ else
+ ELEM (ctype, class_collection, , value) |= BIT (tok_space);
+
+ value = charset_find_value (charset, "form-feed", 9);
+ if (value == ILLEGAL_CHAR_VALUE)
+ error (0, 0, _("\
+character `%s' not defined while needed as default value"),
+ "<form-feed>");
+ else
+ ELEM (ctype, class_collection, , value) |= BIT (tok_space);
+
+ value = charset_find_value (charset, "newline", 7);
+ if (value == ILLEGAL_CHAR_VALUE)
+ error (0, 0, _("\
+character `%s' not defined while needed as default value"),
+ "<newline>");
+ else
+ ELEM (ctype, class_collection, , value) |= BIT (tok_space);
+
+ value = charset_find_value (charset, "carriage-return", 15);
+ if (value == ILLEGAL_CHAR_VALUE)
+ error (0, 0, _("\
+character `%s' not defined while needed as default value"),
+ "<carriage-return>");
+ else
+ ELEM (ctype, class_collection, , value) |= BIT (tok_space);
+
+ value = charset_find_value (charset, "tab", 3);
+ if (value == ILLEGAL_CHAR_VALUE)
+ error (0, 0, _("\
+character `%s' not defined while needed as default value"),
+ "<tab>");
+ else
+ ELEM (ctype, class_collection, , value) |= BIT (tok_space);
+
+ value = charset_find_value (charset, "vertical-tab", 12);
+ if (value == ILLEGAL_CHAR_VALUE)
+ error (0, 0, _("\
+character `%s' not defined while needed as default value"),
+ "<vertical-tab>");
+ else
+ ELEM (ctype, class_collection, , value) |= BIT (tok_space);
+ }
+
+ if ((ctype->class_done & BIT (tok_xdigit)) == 0)
+ /* "If this keyword is not specified, the digits `0' to `9', the
+ uppercase letters `A' through `F', and the lowercase letters `a'
+ through `f', ..., shell automatically belong to this class, with
+ implementation defined character values." [P1003.2, 2.5.2.1] */
+ {
+ set_default (BIT (tok_xdigit), '0', '9');
+ set_default (BIT (tok_xdigit), 'A', 'F');
+ set_default (BIT (tok_xdigit), 'a', 'f');
+ }
+
+ if ((ctype->class_done & BIT (tok_blank)) == 0)
+ /* "If this keyword [blank] is unspecified, the characters <space> and
+ <tab> shall belong to this character class." [P1003.2, 2.5.2.1] */
+ {
+ unsigned int value;
+
+ value = charset_find_value (charset, "space", 5);
+ if (value == ILLEGAL_CHAR_VALUE)
+ error (0, 0, _("\
+character `%s' not defined while needed as default value"),
+ "<space>");
+ else
+ ELEM (ctype, class_collection, , value) |= BIT (tok_blank);
+
+ value = charset_find_value (charset, "tab", 3);
+ if (value == ILLEGAL_CHAR_VALUE)
+ error (0, 0, _("\
+character `%s' not defined while needed as default value"),
+ "<tab>");
+ else
+ ELEM (ctype, class_collection, , value) |= BIT (tok_blank);
+ }
+
+ if ((ctype->class_done & BIT (tok_graph)) == 0)
+ /* "If this keyword [graph] is not specified, characters specified for
+ the keywords `upper', `lower', `alpha', `digit', `xdigit' and `punct',
+ shall belong to this character class." [P1003.2, 2.5.2.1] */
+ {
+ unsigned long int mask = BIT (tok_upper) | BIT (tok_lower) |
+ BIT (tok_alpha) | BIT (tok_digit) | BIT (tok_xdigit) | BIT (tok_punct);
+ size_t cnt;
+
+ for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
+ if ((ctype->class_collection[cnt] & mask) != 0)
+ ctype->class_collection[cnt] |= BIT (tok_graph);
+ }
+
+ if ((ctype->class_done & BIT (tok_print)) == 0)
+ /* "If this keyword [print] is not provided, characters specified for
+ the keywords `upper', `lower', `alpha', `digit', `xdigit', `punct',
+ and the <space> character shall belong to this character class."
+ [P1003.2, 2.5.2.1] */
+ {
+ unsigned long int mask = BIT (tok_upper) | BIT (tok_lower) |
+ BIT (tok_alpha) | BIT (tok_digit) | BIT (tok_xdigit) | BIT (tok_punct);
+ size_t cnt;
+ int space;
+
+ for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
+ if ((ctype->class_collection[cnt] & mask) != 0)
+ ctype->class_collection[cnt] |= BIT (tok_print);
+
+ space = charset_find_value (charset, "space", 5);
+ if (space == ILLEGAL_CHAR_VALUE)
+ error (0, 0, _("\
+character `%s' not defined while needed as default value"),
+ "<space>");
+ else
+ ELEM (ctype, class_collection, , space) |= BIT (tok_print);
+ }
+
+ if (ctype->toupper_done == 0)
+ /* "If this keyword [toupper] is not spcified, the lowercase letters
+ `a' through `z', and their corresponding uppercase letters `A' to
+ `Z', ..., shall automatically be included, with implementation-
+ defined character values." [P1003.2, 2.5.2.1] */
+ {
+ char tmp[4];
+ int ch;
+
+ strcpy (tmp, "<?>");
+
+ for (ch = 'a'; ch <= 'z'; ++ch)
+ {
+ unsigned int value_from, value_to;
+
+ tmp[1] = (char) ch;
+
+ value_from = charset_find_value (charset, &tmp[1], 1);
+ if (value_from == ILLEGAL_CHAR_VALUE)
+ {
+ error (0, 0, _("\
+character `%c' not defined while needed as default value"),
+ tmp);
+ continue;
+ }
+
+ /* This conversion is implementation defined. */
+ tmp[1] = (char) (ch + ('A' - 'a'));
+ value_to = charset_find_value (charset, &tmp[1], 1);
+ if (value_to == -1)
+ {
+ error (0, 0, _("\
+character `%s' not defined while needed as default value"),
+ tmp);
+ continue;
+ }
+
+ /* The index [0] is determined by the order of the
+ `ctype_map_newP' calls in `ctype_startup'. */
+ ELEM (ctype, map_collection, [0], value_from) = value_to;
+ }
+ }
+
+ if (ctype->tolower_done == 0)
+ /* "If this keyword [tolower] is not specified, the mapping shall be
+ the reverse mapping of the one specified to `toupper'." [P1003.2] */
+ {
+ size_t cnt;
+
+ for (cnt = 0; cnt < ctype->map_collection_act[0]; ++cnt)
+ if (ctype->map_collection[0][cnt] != 0)
+ ELEM (ctype, map_collection, [1],
+ ctype->map_collection[0][cnt])
+ = ctype->charnames[cnt];
+ }
+}
+
+
+static void
+allocate_arrays (struct locale_ctype_t *ctype)
+{
+ size_t idx;
+
+ /* First we have to decide how we organize the arrays. It is easy for
+ a one-byte character set. But multi-byte character set cannot be
+ stored flat because they might be sparsly used. So we determine an
+ optimal hashing function for the used characters.
+
+ We use a very trivial hashing function to store the sparse table.
+ CH % TABSIZE is used as an index. To solve multiple hits we have
+ N planes. This gurantees a fixed search time for a character [N
+ / 2]. In the following code we determine the minmum value for
+ TABSIZE * N, where TABSIZE >= 256. */
+ size_t min_total = UINT_MAX;
+ size_t act_size = 256;
+
+ fputs (_("\
+Computing table size for character classes might take a while..."),
+ stderr);
+
+ while (act_size < min_total)
+ {
+ size_t cnt[act_size];
+ size_t act_planes = 1;
+
+ memset (cnt, '\0', sizeof cnt);
+
+ for (idx = 0; idx < 256; ++idx)
+ cnt[idx] = 1;
+
+ for (idx = 0; idx < ctype->charnames_act; ++idx)
+ if (ctype->charnames[idx] >= 256)
+ {
+ size_t nr = ctype->charnames[idx] % act_size;
+
+ if (++cnt[nr] > act_planes)
+ {
+ act_planes = cnt[nr];
+ if (act_size * act_planes >= min_total)
+ break;
+ }
+ }
+
+ if (act_size * act_planes < min_total)
+ {
+ min_total = act_size * act_planes;
+ ctype->plane_size = act_size;
+ ctype->plane_cnt = act_planes;
+ }
+
+ ++act_size;
+ }
+
+ fprintf (stderr, _(" done\n"));
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define NAMES_B1 ctype->names_el
+# define NAMES_B2 ctype->names_eb
+#else
+# define NAMES_B1 ctype->names_eb
+# define NAMES_B2 ctype->names_el
+#endif
+
+ ctype->names_eb = (u32_t *) xcalloc (ctype->plane_size * ctype->plane_cnt,
+ sizeof (u32_t));
+ ctype->names_el = (u32_t *) xcalloc (ctype->plane_size * ctype->plane_cnt,
+ sizeof (u32_t));
+
+ for (idx = 1; idx < 256; ++idx)
+ NAMES_B1[idx] = idx;
+
+ /* Trick: change the 0th entry's name to 1 to mark the cell occupied. */
+ NAMES_B1[0] = 1;
+
+ for (idx = 256; idx < ctype->charnames_act; ++idx)
+ {
+ size_t nr = (ctype->charnames[idx] % ctype->plane_size);
+ size_t depth = 0;
+
+ while (NAMES_B1[nr + depth * ctype->plane_size])
+ ++depth;
+ assert (depth < ctype->plane_cnt);
+
+ NAMES_B1[nr + depth * ctype->plane_size] = ctype->charnames[idx];
+
+ /* Now for faster access remember the index in the NAMES_B array. */
+ ctype->charnames[idx] = nr + depth * ctype->plane_size;
+ }
+ NAMES_B1[0] = 0;
+
+ for (idx = 0; idx < ctype->plane_size * ctype->plane_cnt; ++idx)
+ NAMES_B2[idx] = SWAPU32 (NAMES_B1[idx]);
+
+
+ /* You wonder about this amount of memory? This is only because some
+ users do not manage to address the array with unsigned values or
+ data types with range >= 256. '\200' would result in the array
+ index -128. To help these poor people we duplicate the entries for
+ 128 up to 255 below the entry for \0. */
+ ctype->ctype_b = (char_class_t *) xcalloc (256 + 128,
+ sizeof (char_class_t));
+ ctype->ctype32_b = (char_class32_t *) xcalloc (ctype->plane_size
+ * ctype->plane_cnt,
+ sizeof (char_class32_t));
+
+ /* Fill in the character class information. */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define TRANS(w) CHAR_CLASS_TRANS (w)
+# define TRANS32(w) CHAR_CLASS32_TRANS (w)
+#else
+# define TRANS(w) (w)
+# define TRANS32(w) (w)
+#endif
+
+ for (idx = 0; idx < ctype->class_collection_act; ++idx)
+ if (ctype->charnames[idx] < 256)
+ ctype->ctype_b[128 + ctype->charnames[idx]]
+ = TRANS (ctype->class_collection[idx]);
+
+ /* Mirror first 128 entries. */
+ for (idx = 0; idx < 128; ++idx)
+ ctype->ctype_b[idx] = ctype->ctype_b[256 + idx];
+
+ /* The 32 bit array contains all characters. */
+ for (idx = 0; idx < ctype->class_collection_act; ++idx)
+ ctype->ctype32_b[ctype->charnames[idx]]
+ = TRANS32 (ctype->class_collection[idx]);
+
+ /* Room for table of mappings. */
+ ctype->map_eb = (u32_t **) xmalloc (ctype->map_collection_nr
+ * sizeof (u32_t *));
+ ctype->map_el = (u32_t **) xmalloc (ctype->map_collection_nr
+ * sizeof (u32_t *));
+
+ /* Fill in all mappings. */
+ for (idx = 0; idx < ctype->map_collection_nr; ++idx)
+ {
+ unsigned int idx2;
+
+ /* Allocate table. */
+ ctype->map_eb[idx] = (u32_t *) xmalloc ((ctype->plane_size
+ * ctype->plane_cnt + 128)
+ * sizeof (u32_t));
+ ctype->map_el[idx] = (u32_t *) xmalloc ((ctype->plane_size
+ * ctype->plane_cnt + 128)
+ * sizeof (u32_t));
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define MAP_B1 ctype->map_el
+# define MAP_B2 ctype->map_eb
+#else
+# define MAP_B1 ctype->map_eb
+# define MAP_B2 ctype->map_el
+#endif
+
+ /* Copy default value (identity mapping). */
+ memcpy (&MAP_B1[idx][128], NAMES_B1,
+ ctype->plane_size * ctype->plane_cnt * sizeof (u32_t));
+
+ /* Copy values from collection. */
+ for (idx2 = 0; idx2 < ctype->map_collection_act[idx]; ++idx2)
+ if (ctype->map_collection[idx][idx2] != 0)
+ MAP_B1[idx][128 + ctype->charnames[idx2]] =
+ ctype->map_collection[idx][idx2];
+
+ /* Mirror first 128 entries. */
+ for (idx2 = 0; idx2 < 128; ++idx2)
+ MAP_B1[idx][idx2] = MAP_B1[idx][256 + idx2];
+
+
+ /* And now the other byte order. */
+ for (idx2 = 0; idx2 < ctype->plane_size * ctype->plane_cnt + 128; ++idx2)
+ MAP_B2[idx][idx2] = SWAPU32 (MAP_B1[idx][idx2]);
+ }
+
+ /* Extra array for class and map names. */
+ ctype->class_name_ptr = (u32_t *) xmalloc (ctype->nr_charclass
+ * sizeof (u32_t));
+ ctype->map_name_ptr = (u32_t *) xmalloc (ctype->map_collection_nr
+ * sizeof (u32_t));
+}
diff --git a/locale/programs/ld-messages.c b/locale/programs/ld-messages.c
new file mode 100644
index 0000000000..ebd5054b02
--- /dev/null
+++ b/locale/programs/ld-messages.c
@@ -0,0 +1,237 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <alloca.h>
+#include <langinfo.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#ifdef HAVE_REGEX
+# include <regex.h>
+#else
+# include <rx.h>
+#endif
+
+/* Undefine following line in production version. */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+#include "locales.h"
+#include "stringtrans.h"
+#include "localeinfo.h"
+
+
+void *xmalloc (size_t __n);
+
+
+/* The real definition of the struct for the LC_MESSAGES locale. */
+struct locale_messages_t
+{
+ const char *yesexpr;
+ const char *noexpr;
+ const char *yesstr;
+ const char *nostr;
+};
+
+
+void
+messages_startup (struct linereader *lr, struct localedef_t *locale,
+ struct charset_t *charset)
+{
+ struct locale_messages_t *messages;
+
+ /* It is important that we always use UCS1 encoding for strings now. */
+ encoding_method = ENC_UCS1;
+
+ locale->categories[LC_MESSAGES].messages = messages =
+ (struct locale_messages_t *) xmalloc (sizeof (struct locale_messages_t));
+
+ memset (messages, '\0', sizeof (struct locale_messages_t));
+}
+
+
+void
+messages_finish (struct localedef_t *locale)
+{
+ struct locale_messages_t *messages
+ = locale->categories[LC_MESSAGES].messages;
+
+ /* The fields YESSTR and NOSTR are optional. */
+ if (messages->yesexpr == NULL)
+ error (0, 0, _("field `%s' in category `%s' undefined"),
+ "yesexpr", "LC_MESSAGES");
+ else
+ {
+ int result;
+ regex_t re;
+
+ /* Test whether it are correct regular expressions. */
+ result = regcomp (&re, messages->yesexpr, REG_EXTENDED);
+ if (result != 0)
+ {
+ char errbuf[BUFSIZ];
+
+ (void) regerror (result, &re, errbuf, BUFSIZ);
+ error (0, 0, _("\
+no correct regular expression for field `%s' in category `%s': %s"),
+ "yesexpr", "LC_MESSAGES", errbuf);
+ }
+ }
+
+ if (messages->noexpr == NULL)
+ error (0, 0, _("field `%s' in category `%s' undefined"),
+ "noexpr", "LC_MESSAGES");
+ else
+ {
+ int result;
+ regex_t re;
+
+ /* Test whether it are correct regular expressions. */
+ result = regcomp (&re, messages->noexpr, REG_EXTENDED);
+ if (result != 0)
+ {
+ char errbuf[BUFSIZ];
+
+ (void) regerror (result, &re, errbuf, BUFSIZ);
+ error (0, 0, _("\
+no correct regular expression for field `%s' in category `%s': %s"),
+ "noexpr", "LC_MESSAGES", errbuf);
+ }
+ }
+}
+
+
+void
+messages_output (struct localedef_t *locale, const char *output_path)
+{
+ struct locale_messages_t *messages
+ = locale->categories[LC_MESSAGES].messages;
+ struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES)];
+ struct locale_file data;
+ u32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES)];
+ size_t cnt = 0;
+
+ if ((locale->binary & (1 << LC_MESSAGES)) != 0)
+ {
+ iov[0].iov_base = messages;
+ iov[0].iov_len = locale->len[LC_MESSAGES];
+
+ write_locale_data (output_path, "LC_MESSAGES", 1, iov);
+
+ return;
+ }
+
+ data.magic = LIMAGIC (LC_MESSAGES);
+ data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES);
+ iov[cnt].iov_base = (void *) &data;
+ iov[cnt].iov_len = sizeof (data);
+ ++cnt;
+
+ iov[cnt].iov_base = (void *) idx;
+ iov[cnt].iov_len = sizeof (idx);
+ ++cnt;
+
+ idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
+ iov[cnt].iov_base = (void *) (messages->yesexpr ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) (messages->noexpr ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) (messages->yesstr ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) (messages->nostr ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+
+ assert (cnt + 1 == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES));
+
+ write_locale_data (output_path, "LC_MESSAGES",
+ 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES), iov);
+}
+
+
+void
+messages_add (struct linereader *lr, struct localedef_t *locale,
+ enum token_t tok, struct token *code,
+ struct charset_t *charset)
+{
+ struct locale_messages_t *messages
+ = locale->categories[LC_MESSAGES].messages;
+
+ switch (tok)
+ {
+ case tok_yesexpr:
+ if (code->val.str.start == NULL)
+ {
+ lr_error (lr, _("unknown character in field `%s' of category `%s'"),
+ "yesexpr", "LC_MESSAGES");
+ messages->yesexpr = "";
+ }
+ else
+ messages->yesexpr = code->val.str.start;
+ break;
+
+ case tok_noexpr:
+ if (code->val.str.start == NULL)
+ {
+ lr_error (lr, _("unknown character in field `%s' of category `%s'"),
+ "noexpr", "LC_MESSAGES");
+ messages->noexpr = "";
+ }
+ else
+ messages->noexpr = code->val.str.start;
+ break;
+
+ case tok_yesstr:
+ if (code->val.str.start == NULL)
+ {
+ lr_error (lr, _("unknown character in field `%s' of category `%s'"),
+ "yesstr", "LC_MESSAGES");
+ messages->yesstr = "";
+ }
+ else
+ messages->yesstr = code->val.str.start;
+ break;
+
+ case tok_nostr:
+ if (code->val.str.start == NULL)
+ {
+ lr_error (lr, _("unknown character in field `%s' of category `%s'"),
+ "nostr", "LC_MESSAGES");
+ messages->nostr = "";
+ }
+ else
+ messages->nostr = code->val.str.start;
+ break;
+
+ default:
+ assert (! "unknown token in category `LC_MESSAGES': should not happen");
+ }
+}
diff --git a/locale/programs/ld-monetary.c b/locale/programs/ld-monetary.c
new file mode 100644
index 0000000000..18e27866fb
--- /dev/null
+++ b/locale/programs/ld-monetary.c
@@ -0,0 +1,385 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <langinfo.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* Undefine following line in production version. */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+#include "locales.h"
+#include "localeinfo.h"
+#include "stringtrans.h"
+
+void *xmalloc (size_t __n);
+void *xrealloc (void *__ptr, size_t __n);
+
+
+/* The real definition of the struct for the LC_NUMERIC locale. */
+struct locale_monetary_t
+{
+ const char *int_curr_symbol;
+ const char *currency_symbol;
+ const char *mon_decimal_point;
+ const char *mon_thousands_sep;
+ char *mon_grouping;
+ size_t mon_grouping_max;
+ size_t mon_grouping_act;
+ const char *positive_sign;
+ const char *negative_sign;
+ signed char int_frac_digits;
+ signed char frac_digits;
+ signed char p_cs_precedes;
+ signed char p_sep_by_space;
+ signed char n_cs_precedes;
+ signed char n_sep_by_space;
+ signed char p_sign_posn;
+ signed char n_sign_posn;
+};
+
+
+/* The content iof the field int_curr_symbol has to be taken from
+ ISO-4217. We test for correct values. */
+#define DEFINE_INT_CURR(str) str,
+static const char *const valid_int_curr[] =
+ {
+# include "../iso-4217.def"
+ };
+#define NR_VALID_INT_CURR ((sizeof (valid_int_curr) \
+ / sizeof (valid_int_curr[0])))
+#undef DEFINE_INT_CURR
+
+
+/* Prototypes for local functions. */
+static int curr_strcmp(const char *s1, const char **s2);
+
+
+void
+monetary_startup (struct linereader *lr, struct localedef_t *locale,
+ struct charset_t *charset)
+{
+ struct locale_monetary_t *monetary;
+
+ /* It is important that we always use UCS1 encoding for strings now. */
+ encoding_method = ENC_UCS1;
+
+ locale->categories[LC_MONETARY].monetary = monetary =
+ (struct locale_monetary_t *) xmalloc (sizeof (struct locale_monetary_t));
+
+ memset (monetary, '\0', sizeof (struct locale_monetary_t));
+
+ monetary->mon_grouping_max = 80;
+ monetary->mon_grouping =
+ (char *) xmalloc (monetary->mon_grouping_max);
+ monetary->mon_grouping_act = 0;
+
+ monetary->int_frac_digits = -2;
+ monetary->frac_digits = -2;
+ monetary->p_cs_precedes = -2;
+ monetary->p_sep_by_space = -2;
+ monetary->n_cs_precedes = -2;
+ monetary->n_sep_by_space = -2;
+ monetary->p_sign_posn = -2;
+ monetary->n_sign_posn = -2;
+}
+
+
+void
+monetary_finish (struct localedef_t *locale)
+{
+ struct locale_monetary_t *monetary
+ = locale->categories[LC_MONETARY].monetary;
+
+#define TEST_ELEM(cat) \
+ if (monetary->cat == NULL) \
+ error (0, 0, _("field `%s' in category `%s' not defined"), \
+ #cat, "LC_MONETARY")
+
+ TEST_ELEM (int_curr_symbol);
+ TEST_ELEM (currency_symbol);
+ TEST_ELEM (mon_decimal_point);
+ TEST_ELEM (mon_thousands_sep);
+ TEST_ELEM (positive_sign);
+ TEST_ELEM (negative_sign);
+
+ /* The international currency symbol must come from ISO 4217. */
+ if (monetary->int_curr_symbol != NULL)
+ {
+ if (strlen (monetary->int_curr_symbol) != 4)
+ error (0, 0, _("\
+value of field `int_curr_symbol' in category `LC_MONETARY' has wrong length"));
+ else if (bsearch (monetary->int_curr_symbol, valid_int_curr,
+ NR_VALID_INT_CURR, sizeof (const char *),
+ (comparison_fn_t) curr_strcmp) == NULL)
+ error (0, 0, _("\
+value of field `int_curr_symbol' in category `LC_MONETARY' does \
+not correspond to a valid name in ISO 4217"));
+ }
+
+ /* The decimal point must not be empty. This is not said explicitly
+ in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
+ != "". */
+ if (monetary->mon_decimal_point[0] == '\0')
+ {
+ error (0, 0, _("\
+value for field `%s' in category `%s' must not be the empty string"),
+ "mon_decimal_point", "LC_MONETARY");
+ }
+
+ if (monetary->mon_grouping_act == 0)
+ error (0, 0, _("field `%s' in category `%s' not defined"),
+ "mon_grouping", "LC_MONETARY");
+
+#undef TEST_ELEM
+#define TEST_ELEM(cat, min, max) \
+ if (monetary->cat == -2) \
+ error (0, 0, _("field `%s' in category `%s' not defined"), \
+ #cat, "LC_MONETARY"); \
+ else if (monetary->cat < min || monetary->cat > max) \
+ error (0, 0, _("\
+value for field `%s' in category `%s' must be in range %d...%d"), \
+ #cat, "LC_MONETARY", min, max)
+
+ TEST_ELEM (int_frac_digits, -128, 127); /* No range check. */
+ TEST_ELEM (frac_digits, -128, 127); /* No range check. */
+ TEST_ELEM (p_cs_precedes, -1, 1);
+ TEST_ELEM (p_sep_by_space, -1, 2);
+ TEST_ELEM (n_cs_precedes, -1, 1);
+ TEST_ELEM (n_sep_by_space, -1, 2);
+ TEST_ELEM (p_sign_posn, -1, 4);
+ TEST_ELEM (n_sign_posn, -1, 4);
+}
+
+
+void
+monetary_output (struct localedef_t *locale, const char *output_path)
+{
+ struct locale_monetary_t *monetary
+ = locale->categories[LC_MONETARY].monetary;
+ struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
+ struct locale_file data;
+ u32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
+ size_t cnt = 0;
+
+ if ((locale->binary & (1 << LC_MONETARY)) != 0)
+ {
+ iov[0].iov_base = monetary;
+ iov[0].iov_len = locale->len[LC_MONETARY];
+
+ write_locale_data (output_path, "LC_MONETARY", 1, iov);
+
+ return;
+ }
+
+ data.magic = LIMAGIC (LC_MONETARY);
+ data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
+ iov[cnt].iov_base = (void *) &data;
+ iov[cnt].iov_len = sizeof (data);
+ ++cnt;
+
+ iov[cnt].iov_base = (void *) idx;
+ iov[cnt].iov_len = sizeof (idx);
+ ++cnt;
+
+ idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
+ iov[cnt].iov_base = (void *) (monetary->int_curr_symbol ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) (monetary->currency_symbol ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) (monetary->mon_decimal_point ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) (monetary->mon_thousands_sep ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = alloca (monetary->mon_grouping_act + 1);
+ iov[cnt].iov_len = monetary->mon_grouping_act + 1;
+ memcpy (iov[cnt].iov_base, monetary->mon_grouping,
+ monetary->mon_grouping_act);
+ ((char *) iov[cnt].iov_base)[monetary->mon_grouping_act] = '\0';
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) (monetary->positive_sign ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) (monetary->negative_sign ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
+ iov[cnt].iov_len = 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) &monetary->frac_digits;
+ iov[cnt].iov_len = 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) &monetary->p_cs_precedes;
+ iov[cnt].iov_len = 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) &monetary->p_sep_by_space;
+ iov[cnt].iov_len = 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) &monetary->n_cs_precedes;
+ iov[cnt].iov_len = 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) &monetary->n_sep_by_space;
+ iov[cnt].iov_len = 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) &monetary->p_sign_posn;
+ iov[cnt].iov_len = 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) &monetary->n_sign_posn;
+ iov[cnt].iov_len = 1;
+
+ assert (cnt + 1 == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
+
+ write_locale_data (output_path, "LC_MONETARY",
+ 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
+}
+
+
+void
+monetary_add (struct linereader *lr, struct localedef_t *locale,
+ enum token_t tok, struct token *code,
+ struct charset_t *charset)
+{
+ struct locale_monetary_t *monetary
+ = locale->categories[LC_MONETARY].monetary;
+
+ switch (tok)
+ {
+#define STR_ELEM(cat) \
+ case tok_##cat: \
+ if (monetary->cat != NULL) \
+ lr_error (lr, _("\
+field `%s' in category `%s' declared more than once"), \
+ #cat, "LC_MONETARY"); \
+ else if (code->val.str.start == NULL) \
+ { \
+ lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
+ #cat, "LC_MONETARY"); \
+ monetary->cat = ""; \
+ } \
+ else \
+ monetary->cat = code->val.str.start; \
+ break
+
+ STR_ELEM (int_curr_symbol);
+ STR_ELEM (currency_symbol);
+ STR_ELEM (mon_decimal_point);
+ STR_ELEM (mon_thousands_sep);
+ STR_ELEM (positive_sign);
+ STR_ELEM (negative_sign);
+
+#define INT_ELEM(cat) \
+ case tok_##cat: \
+ if (monetary->cat != -2) \
+ lr_error (lr, _("\
+field `%s' in category `%s' declared more than once"), \
+ #cat, "LC_MONETARY"); \
+ else \
+ monetary->cat = code->val.num; \
+ break
+
+ INT_ELEM (int_frac_digits);
+ INT_ELEM (frac_digits);
+ INT_ELEM (p_cs_precedes);
+ INT_ELEM (p_sep_by_space);
+ INT_ELEM (n_cs_precedes);
+ INT_ELEM (n_sep_by_space);
+ INT_ELEM (p_sign_posn);
+ INT_ELEM (n_sign_posn);
+
+ case tok_mon_grouping:
+ if (monetary->mon_grouping_act == monetary->mon_grouping_max)
+ {
+ monetary->mon_grouping_max *= 2;
+ monetary->mon_grouping =
+ (char *) xrealloc (monetary->mon_grouping,
+ monetary->mon_grouping_max);
+ }
+ if (monetary->mon_grouping[monetary->mon_grouping_act - 1]
+ == '\177')
+ lr_error (lr, _("\
+`-1' must be last entry in `%s' field in `%s' category"),
+ "mon_grouping", "LC_MONETARY");
+ else
+ {
+ if (code->tok == tok_minus1)
+ monetary->mon_grouping[monetary->mon_grouping_act++] = '\177';
+ else if (code->val.num == 0)
+ lr_error (lr, _("\
+values for field `%s' in category `%s' must not be zero"),
+ "mon_grouping", "LC_MONETARY");
+ else if (code->val.num > 126)
+ lr_error (lr, _("\
+values for field `%s' in category `%s' must be smaller than 127"),
+ "mon_grouping", "LC_MONETARY");
+ else
+ monetary->mon_grouping[monetary->mon_grouping_act++]
+ = code->val.num;
+ }
+ break;
+
+ default:
+ assert (! "unknown token in category `LC_MONETARY': should not happen");
+ }
+}
+
+
+static int
+curr_strcmp(const char *s1, const char **s2)
+{
+ return strcmp (s1, *s2);
+}
diff --git a/locale/programs/ld-numeric.c b/locale/programs/ld-numeric.c
new file mode 100644
index 0000000000..0b5fe2afe5
--- /dev/null
+++ b/locale/programs/ld-numeric.c
@@ -0,0 +1,208 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <langinfo.h>
+#include <string.h>
+
+/* Undefine following line in production version. */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+#include "locales.h"
+#include "localeinfo.h"
+#include "stringtrans.h"
+
+void *xmalloc (size_t __n);
+void *xrealloc (void *__ptr, size_t __n);
+
+
+/* The real definition of the struct for the LC_NUMERIC locale. */
+struct locale_numeric_t
+{
+ const char *decimal_point;
+ const char *thousands_sep;
+ char *grouping;
+ size_t grouping_max;
+ size_t grouping_act;
+};
+
+
+void
+numeric_startup (struct linereader *lr, struct localedef_t *locale,
+ struct charset_t *charset)
+{
+ struct locale_numeric_t *numeric;
+
+ /* It is important that we always use UCS1 encoding for strings now. */
+ encoding_method = ENC_UCS1;
+
+ locale->categories[LC_NUMERIC].numeric = numeric =
+ (struct locale_numeric_t *) xmalloc (sizeof (struct locale_numeric_t));
+
+ memset (numeric, '\0', sizeof (struct locale_numeric_t));
+
+ numeric->grouping_max = 80;
+ numeric->grouping = (char *) xmalloc (numeric->grouping_max);
+ numeric->grouping_act = 0;
+}
+
+
+void
+numeric_finish (struct localedef_t *locale)
+{
+ struct locale_numeric_t *numeric = locale->categories[LC_NUMERIC].numeric;
+
+#define TEST_ELEM(cat) \
+ if (numeric->cat == NULL) \
+ error (0, 0, _("field `%s' in category `%s' not defined"), \
+ #cat, "LC_NUMERIC")
+
+ TEST_ELEM (decimal_point);
+ TEST_ELEM (thousands_sep);
+
+ /* The decimal point must not be empty. This is not said explicitly
+ in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
+ != "". */
+ if (numeric->decimal_point[0] == '\0')
+ {
+ error (0, 0, _("\
+value for field `%s' in category `%s' must not be the empty string"),
+ "decimal_point", "LC_NUMERIC");
+ }
+
+ if (numeric->grouping_act == 0)
+ error (0, 0, _("field `%s' in category `%s' not defined"),
+ "grouping", "LC_NUMERIC");
+}
+
+
+void
+numeric_output (struct localedef_t *locale, const char *output_path)
+{
+ struct locale_numeric_t *numeric = locale->categories[LC_NUMERIC].numeric;
+ struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC)];
+ struct locale_file data;
+ u32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC)];
+ size_t cnt = 0;
+
+ if ((locale->binary & (1 << LC_NUMERIC)) != 0)
+ {
+ iov[0].iov_base = numeric;
+ iov[0].iov_len = locale->len[LC_NUMERIC];
+
+ write_locale_data (output_path, "LC_NUMERIC", 1, iov);
+
+ return;
+ }
+
+ data.magic = LIMAGIC (LC_NUMERIC);
+ data.n = _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC);
+ iov[cnt].iov_base = (void *) &data;
+ iov[cnt].iov_len = sizeof (data);
+ ++cnt;
+
+ iov[cnt].iov_base = (void *) idx;
+ iov[cnt].iov_len = sizeof (idx);
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) (numeric->decimal_point ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = (void *) (numeric->thousands_sep ?: "");
+ iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
+ ++cnt;
+
+ idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
+ iov[cnt].iov_base = alloca (numeric->grouping_act + 1);
+ iov[cnt].iov_len = numeric->grouping_act + 1;
+ memcpy (iov[cnt].iov_base, numeric->grouping, numeric->grouping_act);
+ ((char *) iov[cnt].iov_base)[numeric->grouping_act] = '\0';
+
+ assert (cnt + 1 == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC));
+
+ write_locale_data (output_path, "LC_NUMERIC",
+ 2 + _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC), iov);
+}
+
+
+void
+numeric_add (struct linereader *lr, struct localedef_t *locale,
+ enum token_t tok, struct token *code,
+ struct charset_t *charset)
+{
+ struct locale_numeric_t *numeric = locale->categories[LC_NUMERIC].numeric;
+
+ switch (tok)
+ {
+#define STR_ELEM(cat) \
+ case tok_##cat: \
+ if (numeric->cat != NULL) \
+ lr_error (lr, _("\
+field `%s' in category `%s' declared more than once"), \
+ #cat, "LC_NUMERIC"); \
+ else if (code->val.str.start == NULL) \
+ { \
+ lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
+ #cat, "LC_NUMERIC"); \
+ numeric->cat = ""; \
+ } \
+ else \
+ numeric->cat = code->val.str.start; \
+ break
+
+ STR_ELEM (decimal_point);
+ STR_ELEM (thousands_sep);
+
+ case tok_grouping:
+ if (numeric->grouping_act == numeric->grouping_max)
+ {
+ numeric->grouping_max *= 2;
+ numeric->grouping = (char *) xrealloc (numeric->grouping,
+ numeric->grouping_max);
+ }
+ if (numeric->grouping_act > 0
+ && (numeric->grouping[numeric->grouping_act - 1] == '\177'))
+ {
+ lr_error (lr, _("\
+`-1' must be last entry in `%s' field in `%s' category"),
+ "grouping", "LC_NUMERIC");
+ --numeric->grouping_act;
+ }
+
+ if (code->tok == tok_minus1)
+ numeric->grouping[numeric->grouping_act++] = '\177';
+ else if (code->val.num > 126)
+ lr_error (lr, _("\
+values for field `%s' in category `%s' must be smaller than 127"),
+ "grouping", "LC_NUMERIC");
+ else
+ numeric->grouping[numeric->grouping_act++] = code->val.num;
+ break;
+
+ default:
+ assert (! "unknown token in category `LC_NUMERIC': should not happen");
+ }
+}
diff --git a/locale/programs/ld-time.c b/locale/programs/ld-time.c
new file mode 100644
index 0000000000..2587faccdc
--- /dev/null
+++ b/locale/programs/ld-time.c
@@ -0,0 +1,310 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <langinfo.h>
+#include <string.h>
+
+/* Undefine following line in production version. */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+#include "locales.h"
+#include "localeinfo.h"
+#include "stringtrans.h"
+
+
+void *xmalloc (size_t __n);
+
+
+/* The real definition of the struct for the LC_TIME locale. */
+struct locale_time_t
+{
+ const char *abday[7];
+ size_t cur_num_abday;
+ const char *day[7];
+ size_t cur_num_day;
+ const char *abmon[12];
+ size_t cur_num_abmon;
+ const char *mon[12];
+ size_t cur_num_mon;
+ const char *am_pm[2];
+ size_t cur_num_am_pm;
+ 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;
+ const char *era_d_t_fmt;
+ const char *era_t_fmt;
+ const char *era_d_fmt;
+ const char *alt_digits[100];
+ size_t cur_num_alt_digits;
+};
+
+
+void
+time_startup (struct linereader *lr, struct localedef_t *locale,
+ struct charset_t *charset)
+{
+ struct locale_time_t *time;
+
+ /* It is important that we always use UCS1 encoding for strings now. */
+ encoding_method = ENC_UCS1;
+
+ locale->categories[LC_TIME].time = time =
+ (struct locale_time_t *) xmalloc (sizeof (struct locale_time_t));
+
+ memset (time, '\0', sizeof (struct locale_time_t));
+}
+
+
+void
+time_finish (struct localedef_t *locale)
+{
+ struct locale_time_t *time = locale->categories[LC_TIME].time;
+
+#define TESTARR_ELEM(cat, max) \
+ if (time->cur_num_##cat == 0) \
+ error (0, 0, _("field `%s' in category `%s' not defined"), \
+ #cat, "LC_TIME"); \
+ else if (time->cur_num_##cat != max) \
+ error (0, 0, _("field `%s' in category `%s' has not enough values"), \
+ #cat, "LC_TIME")
+
+ TESTARR_ELEM (abday, 7);
+ TESTARR_ELEM (day, 7);
+ TESTARR_ELEM (abmon, 12);
+ TESTARR_ELEM (mon, 12);
+ TESTARR_ELEM (am_pm, 2);
+
+#define TEST_ELEM(cat) \
+ if (time->cat == NULL) \
+ error (0, 0, _("field `%s' in category `%s' not defined"), \
+ #cat, "LC_TIME")
+
+ TEST_ELEM (d_t_fmt);
+ TEST_ELEM (d_fmt);
+ TEST_ELEM (t_fmt);
+ TEST_ELEM (t_fmt_ampm);
+}
+
+
+void
+time_output (struct localedef_t *locale, const char *output_path)
+{
+ struct locale_time_t *time = locale->categories[LC_TIME].time;
+ struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_TIME)
+ + time->cur_num_alt_digits];
+ struct locale_file data;
+ u32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_TIME)];
+ size_t cnt, last_idx, num;
+
+ if ((locale->binary & (1 << LC_TIME)) != 0)
+ {
+ iov[0].iov_base = time;
+ iov[0].iov_len = locale->len[LC_TIME];
+
+ write_locale_data (output_path, "LC_TIME", 1, iov);
+
+ return;
+ }
+
+ data.magic = LIMAGIC (LC_TIME);
+ data.n = _NL_ITEM_INDEX (_NL_NUM_LC_TIME);
+ iov[0].iov_base = (void *) &data;
+ iov[0].iov_len = sizeof (data);
+
+ iov[1].iov_base = (void *) idx;
+ iov[1].iov_len = sizeof (idx);
+
+ idx[0] = iov[0].iov_len + iov[1].iov_len;
+
+ /* The ab'days. */
+ for (cnt = 0; cnt <= _NL_ITEM_INDEX (ABDAY_7); ++cnt)
+ {
+ iov[2 + cnt].iov_base =
+ (void *) (time->abday[cnt - _NL_ITEM_INDEX (ABDAY_1)] ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ }
+
+ /* The days. */
+ for (; cnt <= _NL_ITEM_INDEX (DAY_7); ++cnt)
+ {
+ iov[2 + cnt].iov_base =
+ (void *) (time->day[cnt - _NL_ITEM_INDEX (DAY_1)] ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ }
+
+ /* The ab'mons. */
+ for (; cnt <= _NL_ITEM_INDEX (ABMON_12); ++cnt)
+ {
+ iov[2 + cnt].iov_base =
+ (void *) (time->abmon[cnt - _NL_ITEM_INDEX (ABMON_1)] ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ }
+
+ /* The mons. */
+ for (; cnt <= _NL_ITEM_INDEX (MON_12); ++cnt)
+ {
+ iov[2 + cnt].iov_base =
+ (void *) (time->mon[cnt - _NL_ITEM_INDEX (MON_1)] ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ }
+
+ /* AM/PM. */
+ for (; cnt <= _NL_ITEM_INDEX (PM_STR); ++cnt)
+ {
+ iov[2 + cnt].iov_base =
+ (void *) (time->am_pm[cnt - _NL_ITEM_INDEX (AM_STR)] ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ }
+
+ iov[2 + cnt].iov_base = (void *) (time->d_t_fmt ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ ++cnt;
+
+ iov[2 + cnt].iov_base = (void *) (time->d_fmt ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ ++cnt;
+
+ iov[2 + cnt].iov_base = (void *) (time->t_fmt ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ ++cnt;
+
+ iov[2 + cnt].iov_base = (void *) (time->t_fmt_ampm ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ ++cnt;
+
+ iov[2 + cnt].iov_base = (void *) (time->era ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ ++cnt;
+
+ iov[2 + cnt].iov_base = (void *) (time->era_year ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ ++cnt;
+
+ iov[2 + cnt].iov_base = (void *) (time->era_d_fmt ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + cnt] = idx[cnt] + iov[2 + cnt].iov_len;
+ last_idx = ++cnt;
+
+ idx[1 + last_idx] = idx[last_idx];
+ for (num = 0; num < time->cur_num_alt_digits; ++num, ++cnt)
+ {
+ iov[2 + cnt].iov_base = (void *) (time->alt_digits[num] ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + last_idx] += iov[2 + cnt].iov_len;
+ }
+ ++last_idx;
+
+ iov[2 + cnt].iov_base = (void *) (time->era_d_t_fmt ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ idx[1 + last_idx] = idx[last_idx] + iov[2 + cnt].iov_len;
+ ++cnt;
+
+ iov[2 + cnt].iov_base = (void *) (time->era_d_fmt ?: "");
+ iov[2 + cnt].iov_len = strlen (iov[2 + cnt].iov_base) + 1;
+ ++cnt;
+
+ assert (cnt == (_NL_ITEM_INDEX (_NL_NUM_LC_TIME) - 1
+ + time->cur_num_alt_digits));
+
+ write_locale_data (output_path, "LC_TIME", 2 + cnt, iov);
+}
+
+
+void
+time_add (struct linereader *lr, struct localedef_t *locale,
+ enum token_t tok, struct token *code,
+ struct charset_t *charset)
+{
+ struct locale_time_t *time = locale->categories[LC_TIME].time;
+
+ switch (tok)
+ {
+#define STRARR_ELEM(cat, max) \
+ case tok_##cat: \
+ if (time->cur_num_##cat >= max) \
+ lr_error (lr, _(" \
+too many values for field `%s' in category `LC_TIME'"), \
+ #cat, "LC_TIME"); \
+ else if (code->val.str.start == NULL) \
+ { \
+ lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
+ #cat, "LC_TIME"); \
+ time->cat[time->cur_num_##cat++] = ""; \
+ } \
+ else \
+ time->cat[time->cur_num_##cat++] \
+ = code->val.str.start; \
+ break
+
+ STRARR_ELEM (abday, 7);
+ STRARR_ELEM (day, 7);
+ STRARR_ELEM (abmon, 12);
+ STRARR_ELEM (mon, 12);
+ STRARR_ELEM (am_pm, 2);
+ STRARR_ELEM (alt_digits, 100);
+
+#define STR_ELEM(cat) \
+ case tok_##cat: \
+ if (time->cat != NULL) \
+ lr_error (lr, _("\
+field `%s' in category `%s' declared more than once"), \
+ #cat, "LC_TIME"); \
+ else if (code->val.str.start == NULL) \
+ { \
+ lr_error (lr, _("unknown character in field `%s' of category `%s'"),\
+ #cat, "LC_TIME"); \
+ time->cat = ""; \
+ } \
+ else \
+ time->cat = code->val.str.start; \
+ break
+
+ STR_ELEM (d_t_fmt);
+ STR_ELEM (d_fmt);
+ STR_ELEM (t_fmt);
+ STR_ELEM (t_fmt_ampm);
+ STR_ELEM (era);
+ STR_ELEM (era_year);
+ STR_ELEM (era_d_t_fmt);
+ STR_ELEM (era_d_fmt);
+ STR_ELEM (era_t_fmt);
+
+ default:
+ assert (! "unknown token in category `LC_TIME': should not happen");
+ }
+}
diff --git a/locale/programs/linereader.c b/locale/programs/linereader.c
new file mode 100644
index 0000000000..e4a1305712
--- /dev/null
+++ b/locale/programs/linereader.c
@@ -0,0 +1,579 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "linereader.h"
+#include "charset.h"
+#include "stringtrans.h"
+
+
+void *xmalloc (size_t __n);
+void *xrealloc (void *__p, size_t __n);
+char *xstrdup (const char *__str);
+
+
+static struct token *get_toplvl_escape (struct linereader *lr);
+static struct token *get_symname (struct linereader *lr);
+static struct token *get_ident (struct linereader *lr);
+static struct token *get_string (struct linereader *lr,
+ const struct charset_t *charset);
+
+
+struct linereader *
+lr_open (const char *fname, kw_hash_fct_t hf)
+{
+ FILE *fp;
+ struct linereader *result;
+ int n;
+
+ if (fname == NULL || strcmp (fname, "-") == 0
+ || strcmp (fname, "/dev/stdin") == 0)
+ fp = stdin;
+ else
+ {
+ fp = fopen (fname, "r");
+ if (fp == NULL)
+ return NULL;
+ }
+
+ result = (struct linereader *) xmalloc (sizeof (*result));
+
+ result->fp = fp;
+ result->fname = xstrdup (fname);
+ result->buf = NULL;
+ result->bufsize = 0;
+ result->lineno = 1;
+ result->idx = 0;
+ result->comment_char = '#';
+ result->escape_char = '\\';
+ result->translate_strings = 1;
+
+ n = getdelim (&result->buf, &result->bufsize, '\n', result->fp);
+ if (n < 0)
+ {
+ int save = errno;
+ fclose (result->fp);
+ free (result);
+ errno = save;
+ return NULL;
+ }
+
+ if (n > 1 && result->buf[n - 2] == '\\' && result->buf[n - 1] == '\n')
+ n -= 2;
+
+ result->buf[n] = '\0';
+ result->bufact = n;
+ result->hash_fct = hf;
+
+ return result;
+}
+
+
+int
+lr_eof (struct linereader *lr)
+{
+ return lr->bufact = 0;
+}
+
+
+void
+lr_close (struct linereader *lr)
+{
+ fclose (lr->fp);
+ free (lr->buf);
+ free (lr);
+}
+
+
+int
+lr_next (struct linereader *lr)
+{
+ int n;
+
+ n = getdelim (&lr->buf, &lr->bufsize, '\n', lr->fp);
+ if (n < 0)
+ return -1;
+
+ ++lr->lineno;
+
+ if (n > 1 && lr->buf[n - 2] == lr->escape_char && lr->buf[n - 1] == '\n')
+ {
+ /* An escaped newline character is substituted with a single <SP>. */
+ --n;
+ lr->buf[n - 1] = ' ';
+ }
+
+ lr->buf[n] = '\0';
+ lr->bufact = n;
+ lr->idx = 0;
+
+ return 0;
+}
+
+
+/* Defined in error.c. */
+/* This variable is incremented each time `error' is called. */
+extern unsigned int error_message_count;
+
+/* The calling program should define program_name and set it to the
+ name of the executing program. */
+extern char *program_name;
+
+
+struct token *
+lr_token (struct linereader *lr, const struct charset_t *charset)
+{
+ int ch;
+
+ while (1)
+ {
+ do
+ {
+ ch = lr_getc (lr);
+
+ if (ch == '\n')
+ {
+ lr->token.tok = tok_eol;
+ return &lr->token;
+ }
+ }
+ while (isspace (ch));
+
+ if (ch == EOF)
+ {
+ lr->token.tok = tok_eof;
+ return &lr->token;
+ };
+
+ if (ch != lr->comment_char)
+ break;
+
+ /* Ignore rest of line. */
+ lr_ignore_rest (lr, 0);
+ lr->token.tok = tok_eol;
+ return &lr->token;
+ }
+
+ /* Match escape sequences. */
+ if (ch == lr->escape_char)
+ return get_toplvl_escape (lr);
+
+ /* Match ellipsis. */
+ if (ch == '.' && strncmp (&lr->buf[lr->idx], "..", 2) == 0)
+ {
+ lr_getc (lr);
+ lr_getc (lr);
+ lr->token.tok = tok_ellipsis;
+ return &lr->token;
+ }
+
+ switch (ch)
+ {
+ case '<':
+ return get_symname (lr);
+
+ case '0' ... '9':
+ lr->token.tok = tok_number;
+ lr->token.val.num = ch - '0';
+
+ while (isdigit (ch = lr_getc (lr)))
+ {
+ lr->token.val.num *= 10;
+ lr->token.val.num += ch - '0';
+ }
+ if (isalpha (ch))
+ lr_error (lr, _("garbage at end of digit"));
+ lr_ungetn (lr, 1);
+
+ return &lr->token;
+
+ case ';':
+ lr->token.tok = tok_semicolon;
+ return &lr->token;
+
+ case ',':
+ lr->token.tok = tok_comma;
+ return &lr->token;
+
+ case '(':
+ lr->token.tok = tok_open_brace;
+ return &lr->token;
+
+ case ')':
+ lr->token.tok = tok_close_brace;
+ return &lr->token;
+
+ case '"':
+ return get_string (lr, charset);
+
+ case '-':
+ ch = lr_getc (lr);
+ if (ch == '1')
+ {
+ lr->token.tok = tok_minus1;
+ return &lr->token;
+ }
+ lr_ungetn (lr, 2);
+ break;
+ }
+
+ return get_ident (lr);
+}
+
+
+static struct token *
+get_toplvl_escape (struct linereader *lr)
+{
+ /* This is supposed to be a numeric value. We return the
+ numerical value and the number of bytes. */
+ size_t start_idx = lr->idx - 1;
+ unsigned int value = 0;
+ int nbytes = 0;
+ int ch;
+
+ do
+ {
+ unsigned int byte = 0;
+ unsigned int base = 8;
+
+ ch = lr_getc (lr);
+
+ if (ch == 'd')
+ {
+ base = 10;
+ ch = lr_getc (lr);
+ }
+ else if (ch == 'x')
+ {
+ base = 16;
+ ch = lr_getc (lr);
+ }
+
+ if ((base == 16 && !isxdigit (ch))
+ || (base != 16 && (ch < '0' || ch >= '0' + base)))
+ {
+ esc_error:
+ lr->token.val.str.start = &lr->buf[start_idx];
+
+ while (ch != EOF || !isspace (ch))
+ ch = lr_getc (lr);
+ lr->token.val.str.len = lr->idx - start_idx;
+
+ lr->token.tok = tok_error;
+ return &lr->token;
+ }
+
+ if (isdigit (ch))
+ byte = ch - '0';
+ else
+ byte = tolower (ch) - 'a' + 10;
+
+ ch = lr_getc (lr);
+ if ((base == 16 && !isxdigit (ch))
+ || (base != 16 && (ch < '0' || ch >= '0' + base)))
+ goto esc_error;
+
+ byte *= base;
+ if (isdigit (ch))
+ byte += ch - '0';
+ else
+ byte += tolower (ch) - 'a' + 10;
+
+ ch = lr_getc (lr);
+ if (base != 16 && isdigit (ch))
+ {
+ byte *= base;
+ base += ch - '0';
+
+ ch = lr_getc (lr);
+ }
+
+ value *= 256;
+ value += byte;
+
+ ++nbytes;
+ }
+ while (ch == lr->escape_char && nbytes < 4);
+
+ if (!isspace (ch))
+ lr_error (lr, _("garbage at end of character code specification"));
+
+ lr_ungetn (lr, 1);
+
+ lr->token.tok = tok_charcode;
+ lr->token.val.charcode.val = value;
+ lr->token.val.charcode.nbytes = nbytes;
+
+ return &lr->token;
+}
+
+
+#define ADDC(ch) \
+ do \
+ { \
+ if (bufact == bufmax) \
+ { \
+ bufmax *= 2; \
+ buf = xrealloc (buf, bufmax); \
+ } \
+ buf[bufact++] = (ch); \
+ } \
+ while (0)
+
+
+static struct token *
+get_symname (struct linereader *lr)
+{
+ /* Symbol in brackets. We must distinguish three kinds:
+ 1. reserved words
+ 2. ISO 10646 position values
+ 3. all other. */
+ char *buf;
+ size_t bufact = 0;
+ size_t bufmax = 56;
+ const struct keyword_t *kw;
+ int ch;
+
+ buf = (char *) xmalloc (bufmax);
+
+ do
+ {
+ ch = lr_getc (lr);
+ if (ch == lr->escape_char)
+ {
+ int c2 = lr_getc (lr);
+ ADDC (c2);
+
+ if (c2 == '\n')
+ ch = '\n';
+ }
+ else
+ ADDC (ch);
+ }
+ while (ch != '>' && ch != '\n');
+
+ if (ch == '\n')
+ lr_error (lr, _("unterminated symbolic name"));
+
+ /* Test for ISO 10646 position value. */
+ if (buf[0] == 'U' && (bufact == 6 || bufact == 10))
+ {
+ char *cp = buf + 1;
+ while (cp < &buf[bufact - 1] && isxdigit (*cp))
+ ++cp;
+
+ if (cp == &buf[bufact - 1])
+ {
+ /* Yes, it is. */
+ lr->token.tok = bufact == 6 ? tok_ucs2 : tok_ucs4;
+ lr->token.val.charcode.val = strtoul (buf, NULL, 16);
+ lr->token.val.charcode.nbytes = lr->token.tok == tok_ucs2 ? 2 : 4;
+
+ return &lr->token;
+ }
+ }
+
+ /* It is a symbolic name. Test for reserved words. */
+ kw = lr->hash_fct (buf, bufact - 1);
+
+ if (kw != NULL && kw->symname_or_ident == 1)
+ {
+ lr->token.tok = kw->token;
+ free (buf);
+ }
+ else
+ {
+ lr->token.tok = tok_bsymbol;
+
+ buf[bufact] = '\0';
+ buf = xrealloc (buf, bufact + 1);
+
+ lr->token.val.str.start = buf;
+ lr->token.val.str.len = bufact - 1;
+ }
+
+ return &lr->token;
+}
+
+
+static struct token *
+get_ident (struct linereader *lr)
+{
+ char *buf;
+ size_t bufact;
+ size_t bufmax = 56;
+ const struct keyword_t *kw;
+ int ch;
+
+ buf = xmalloc (bufmax);
+ bufact = 0;
+
+ ADDC (lr->buf[lr->idx - 1]);
+
+ while (!isspace ((ch = lr_getc (lr))) && ch != '"' && ch != ';'
+ && ch != '<' && ch != ',')
+ /* XXX Handle escape sequences? */
+ ADDC (ch);
+
+ lr_ungetn (lr, 1);
+
+ kw = lr->hash_fct (buf, bufact);
+
+ if (kw != NULL && kw->symname_or_ident == 0)
+ {
+ lr->token.tok = kw->token;
+ free (buf);
+ }
+ else
+ {
+ lr->token.tok = tok_ident;
+
+ buf[bufact] = '\0';
+ buf = xrealloc (buf, bufact + 1);
+
+ lr->token.val.str.start = buf;
+ lr->token.val.str.len = bufact;
+ }
+
+ return &lr->token;
+}
+
+
+static struct token *
+get_string (struct linereader *lr, const struct charset_t *charset)
+{
+ int illegal_string = 0;
+ char *buf, *cp;
+ size_t bufact;
+ size_t bufmax = 56;
+ int ch;
+
+ buf = xmalloc (bufmax);
+ bufact = 0;
+
+ while ((ch = lr_getc (lr)) != '"' && ch != '\n' && ch != EOF)
+ if (ch != '<' || charset == NULL)
+ {
+ if (ch == lr->escape_char)
+ {
+ ch = lr_getc (lr);
+ if (ch == '\n' || ch == EOF)
+ break;
+ }
+ ADDC (ch);
+ }
+ else
+ {
+ /* We have to get the value of the symbol. */
+ unsigned int value;
+ size_t startidx = bufact;
+
+ if (!lr->translate_strings)
+ ADDC ('<');
+
+ while ((ch = lr_getc (lr)) != '>' && ch != '\n' && ch != EOF)
+ {
+ if (ch == lr->escape_char)
+ {
+ ch = lr_getc (lr);
+ if (ch == '\n' || ch == EOF)
+ break;
+ }
+ ADDC (ch);
+ }
+
+ if (ch == '\n' || ch == EOF)
+ lr_error (lr, _("unterminated string"));
+ else
+ if (!lr->translate_strings)
+ ADDC ('>');
+
+ if (lr->translate_strings)
+ {
+ value = charset_find_value (charset, &buf[startidx],
+ bufact - startidx);
+ if (value == ILLEGAL_CHAR_VALUE)
+ illegal_string = 1;
+ bufact = startidx;
+
+ if (bufmax - bufact < 8)
+ {
+ bufmax *= 2;
+ buf = (char *) xrealloc (buf, bufmax);
+ }
+
+ cp = &buf[bufact];
+ if (encode_char (value, &cp))
+ illegal_string = 1;
+
+ bufact = cp - buf;
+ }
+ }
+
+ /* Catch errors with trailing escape character. */
+ if (bufact > 0 && buf[bufact - 1] == lr->escape_char
+ && (bufact == 1 || buf[bufact - 2] != lr->escape_char))
+ {
+ lr_error (lr, _("illegal escape sequence at end of string"));
+ --bufact;
+ }
+ else if (ch == '\n' || ch == EOF)
+ lr_error (lr, _("unterminated string"));
+
+ /* Terminate string if necessary. */
+ if (lr->translate_strings)
+ {
+ cp = &buf[bufact];
+ if (encode_char (0, &cp))
+ illegal_string = 1;
+
+ bufact = cp - buf;
+ }
+ else
+ ADDC ('\0');
+
+ lr->token.tok = tok_string;
+
+ if (illegal_string)
+ {
+ free (buf);
+ lr->token.val.str.start = NULL;
+ lr->token.val.str.len = 0;
+ }
+ else
+ {
+ buf = xrealloc (buf, bufact + 1);
+
+ lr->token.val.str.start = buf;
+ lr->token.val.str.len = bufact;
+ }
+
+ return &lr->token;
+}
diff --git a/locale/programs/linereader.h b/locale/programs/linereader.h
new file mode 100644
index 0000000000..b78697e87d
--- /dev/null
+++ b/locale/programs/linereader.h
@@ -0,0 +1,158 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef _LINEREADER_H
+#define _LINEREADER_H 1
+
+#include <ctype.h>
+#include <libintl.h>
+#include <stdio.h>
+
+#include "error.h"
+#include "locfile-token.h"
+
+
+typedef const struct keyword_t *(*kw_hash_fct_t) (const char *, int);
+struct charset_t;
+
+
+struct token
+{
+ enum token_t tok;
+ union
+ {
+ struct
+ {
+ char *start;
+ size_t len;
+ } str;
+ unsigned long int num;
+ struct
+ {
+ unsigned int val;
+ int nbytes;
+ } charcode;
+ } val;
+};
+
+
+struct linereader
+{
+ FILE *fp;
+ const char *fname;
+ char *buf;
+ size_t bufsize;
+ size_t bufact;
+ size_t lineno;
+
+ size_t idx;
+
+ char comment_char;
+ char escape_char;
+
+ struct token token;
+
+ int translate_strings;
+
+ kw_hash_fct_t hash_fct;
+};
+
+
+/* Functions defined in linereader.c. */
+struct linereader *lr_open (const char *fname, kw_hash_fct_t hf);
+int lr_eof (struct linereader *lr);
+void lr_close (struct linereader *lr);
+int lr_next (struct linereader *lr);
+struct token *lr_token (struct linereader *lr,
+ const struct charset_t *charset);
+
+
+#define lr_error(lr, fmt, args...) \
+ error_at_line (0, 0, lr->fname, lr->lineno, fmt, ## args)
+
+
+
+static inline int
+lr_getc (struct linereader *lr)
+{
+ if (lr->idx == lr->bufact)
+ {
+ if (lr->bufact != 0)
+ if (lr_next (lr) < 0)
+ return EOF;
+
+ if (lr->bufact == 0)
+ return EOF;
+ }
+
+ return lr->buf[lr->idx] == '\32' ? EOF : lr->buf[lr->idx++];
+}
+
+
+static inline int
+lr_ungetc (struct linereader *lr, int ch)
+{
+ if (lr->idx == 0)
+ return -1;
+
+ lr->buf[--lr->idx] = ch;
+ return 0;
+}
+
+
+static inline int
+lr_ungetn (struct linereader *lr, int n)
+{
+ if (lr->idx < n)
+ return -1;
+
+ lr->idx -= n;
+ return 0;
+}
+
+
+static inline void
+lr_ignore_rest (struct linereader *lr, int verbose)
+{
+ if (verbose)
+ {
+ while (isspace (lr->buf[lr->idx]) && lr->buf[lr->idx] != '\n'
+ && lr->buf[lr->idx] != lr->comment_char)
+ if (lr->buf[lr->idx] == '\0')
+ {
+ if (lr_next (lr) < 0)
+ return;
+ }
+ else
+ ++lr->idx;
+
+ if (lr->buf[lr->idx] != '\n' &&lr->buf[lr->idx] != lr->comment_char)
+ lr_error (lr, _("trailing garbage at end of line"));
+ }
+
+ /* Ignore continued line. */
+ while (lr->bufact > 0 && lr->buf[lr->bufact - 1] != '\n')
+ if (lr_next (lr) < 0)
+ break;
+
+ lr->idx = lr->bufact;
+}
+
+
+#endif /* linereader.h */
diff --git a/locale/locale.c b/locale/programs/locale.c
index fd2e392e80..4e4ff83a37 100644
--- a/locale/locale.c
+++ b/locale/programs/locale.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
@@ -26,7 +26,8 @@ Cambridge, MA 02139, USA. */
#include <unistd.h>
#include <errno.h>
-#include "localedef.h"
+/*#include "localedef.h"*/
+#include "localeinfo.h"
/* If set dump C code describing the current locale. */
@@ -40,16 +41,16 @@ static int show_keyword_name;
/* Long options. */
static const struct option long_options[] =
- {
- { "all-locales", no_argument, NULL, 'a' },
- { "category-name", no_argument, &show_category_name, 1 },
- { "charmaps", no_argument, NULL, 'm' },
- { "dump", no_argument, &do_dump, 1 },
- { "help", no_argument, NULL, 'h' },
- { "keyword-name", no_argument, &show_keyword_name, 1 },
- { "version", no_argument, NULL, 'v' },
- { NULL, 0, NULL, 0 }
- };
+{
+ { "all-locales", no_argument, NULL, 'a' },
+ { "category-name", no_argument, &show_category_name, 1 },
+ { "charmaps", no_argument, NULL, 'm' },
+ { "dump", no_argument, &do_dump, 1 },
+ { "help", no_argument, NULL, 'h' },
+ { "keyword-name", no_argument, &show_keyword_name, 1 },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
+};
/* We don't have these constants defined because we don't use them. Give
@@ -63,7 +64,18 @@ static const struct option long_options[] =
#define CTYPE_TOLOWER_EB 0
#define CTYPE_TOUPPER_EL 0
#define CTYPE_TOLOWER_EL 0
-
+
+/* XXX Hack */
+struct cat_item
+{
+ int item_id;
+ const char *name;
+ enum { std, opt } status;
+ enum value_type value_type;
+ int min;
+ int max;
+};
+
/* We have all categories defined in `categories.def'. Now construct
the description and data structure used for all categories. */
@@ -73,7 +85,7 @@ static const struct option long_options[] =
NO_PAREN items \
};
-#include "categories.def"
+#include "locale/aux/categories.def"
#undef DEFINE_CATEGORY
static struct category category[] =
@@ -81,7 +93,7 @@ static struct category category[] =
#define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \
{ _NL_NUM_##category, name, NELEMS (category##_desc) - 1, \
category##_desc, NULL, NULL, NULL, out },
-#include "categories.def"
+#include "locale/aux/categories.def"
#undef DEFINE_CATEGORY
};
#define NCATEGORIES NELEMS (category)
@@ -404,7 +416,7 @@ show_info (const char *name)
return;
}
-
+
for (item_no = 0; item_no < category[cat_no].number; ++item_no)
if (strcmp (name, category[cat_no].item_desc[item_no].name) == 0)
{
@@ -530,10 +542,3 @@ dump_category (const char *name)
puts (" }\n};");
}
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c
new file mode 100644
index 0000000000..a98bac4301
--- /dev/null
+++ b/locale/programs/localedef.c
@@ -0,0 +1,461 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <libintl.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "error.h"
+#include "charset.h"
+#include "locfile.h"
+
+/* Undefine the following line in the production version. */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+
+/* List of locale definition files which are used in `copy' instructions. */
+struct copy_def_list_t
+{
+ struct copy_def_list_t *next;
+
+ const char *name;
+ int mask;
+
+ struct localedef_t *locale;
+
+ struct
+ {
+ void *data;
+ size_t len;
+ } binary[6];
+};
+
+
+/* List of copied locales. */
+struct copy_def_list_t *copy_list;
+
+/* If this is defined be POSIX conform. */
+int posix_conformance;
+
+/* Name of the running program. */
+const char *program_name;
+
+/* If not zero give a lot more messages. */
+int verbose;
+
+
+
+/* Long options. */
+static const struct option long_options[] =
+{
+ { "charmap", required_argument, NULL, 'f' },
+ { "code-set-name", required_argument, NULL, 'u' },
+ { "help", no_argument, NULL, 'h' },
+ { "force", no_argument, NULL, 'c' },
+ { "inputfile", required_argument, NULL, 'i' },
+ { "posix", no_argument, &posix_conformance, 1 },
+ { "verbose", no_argument, &verbose, 1},
+ { "version", no_argument, NULL, 'V' },
+ { NULL, 0, NULL, 0 }
+};
+
+
+/* Prototypes for global functions. */
+void *xmalloc (size_t __n);
+
+/* Prototypes for local functions. */
+static void usage (int status) __attribute__ ((noreturn));
+static void error_print (void);
+static const char *construct_output_path (const char *path);
+
+
+int
+main (int argc, char *argv[])
+{
+ int optchar;
+ int do_help = 0;
+ int do_version = 0;
+ int force_output = 0;
+ const char *charmap_file = NULL;
+ const char *input_file = NULL;
+ const char *ucs_csn = NULL;
+ const char *output_path;
+ int cannot_write_why;
+ struct charset_t *charset;
+ struct localedef_t *localedef;
+ struct copy_def_list_t *act_add_locdef;
+
+ /* Set initial values for global varaibles. */
+ copy_list = NULL;
+ posix_conformance = getenv ("POSIXLY_CORRECT") != NULL;
+ program_name = argv[0];
+ error_print_progname = error_print;
+ verbose = 0;
+
+ /* Set locale. Do not set LC_ALL because the other categories must
+ not be affected (acccording to POSIX.2). */
+ setlocale (LC_MESSAGES, "");
+ setlocale (LC_CTYPE, "");
+
+ /* Initialize the message catalog. */
+#if 0
+ /* In the final version for glibc we can use the variable. */
+ textdomain (_libc_intl_domainname);
+#else
+ textdomain ("SYS_libc");
+#endif
+
+ while ((optchar = getopt_long (argc, argv, "cf:hi:u:vV", long_options, NULL))
+ != EOF)
+ switch (optchar)
+ {
+ case '\0': /* Long option. */
+ break;
+
+ case 'c':
+ force_output = 1;
+ break;
+
+ case 'f':
+ charmap_file = optarg;
+ break;
+
+ case 'h':
+ do_help = 1;
+ break;
+
+ case 'i':
+ input_file = optarg;
+ break;
+
+ case 'u':
+ ucs_csn = optarg;
+ break;
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ case 'V':
+ do_version = 1;
+ break;
+
+ default:
+ usage (4); /* A value >3 is forced by POSIX. */
+ break;
+ }
+
+ /* POSIX.2 requires to be verbose about missing characters in the
+ character map. */
+ verbose |= posix_conformance;
+
+ /* Version information is requested. */
+ if (do_version)
+ {
+ fprintf (stderr, "%s - GNU %s %s\n", program_name, PACKAGE, VERSION);
+ exit (0);
+ }
+
+ /* Help is requested. */
+ if (do_help)
+ /* Possible violation: POSIX.2 4.35.8 defines the return value 0 as
+ "No errors occured and the locale(s) were successfully created."
+ But giving a other value than 0 does not make sense here. It
+ is perhaps not that important because POSIX does not specify the
+ -h option for localedef. */
+ usage (0);
+
+ if (argc - optind != 1)
+ /* We need exactly one non-option parameter. */
+ usage (4);
+
+ /* The parameter describes the output path of the constructed files.
+ If the described files cannot be written return a NULL pointer. */
+ output_path = construct_output_path (argv[optind]);
+ cannot_write_why = errno;
+
+ /* Now that the parameters are processed we have to reset the local
+ ctype locale. (P1003.2 4.35.5.2) */
+ setlocale (LC_CTYPE, "POSIX");
+
+ /* Look whether the system really allows locale definitions. POSIX
+ defines error code 3 for this situation so I think it must be
+ a fatal error (see P1003.2 4.35.8). */
+ if (sysconf (_SC_2_LOCALEDEF) < 0)
+ error (3, 0, _("FATAL: system does not define `_POSIX2_LOCALEDEF'"));
+
+ /* Process charmap file. */
+ charset = charmap_read (charmap_file);
+
+ /* Now read the locale file. */
+ localedef = locfile_read (input_file, charset);
+ if (localedef->failed != 0)
+ error (4, errno, _("cannot open locale definition file `%s'"), input_file);
+
+ /* Perhaps we saw some `copy' instructions. Process the given list.
+ We use a very simple algorithm: we look up the list from the
+ beginning every time. */
+ do
+ {
+ int cat;
+
+ for (act_add_locdef = copy_list; act_add_locdef != NULL;
+ act_add_locdef = act_add_locdef->next)
+ {
+ for (cat = LC_COLLATE; cat <= LC_MESSAGES; ++cat)
+ if ((act_add_locdef->mask & (1 << cat)) != 0)
+ {
+ act_add_locdef->mask &= ~(1 << cat);
+ break;
+ }
+ if (cat <= LC_MESSAGES)
+ break;
+ }
+
+ if (act_add_locdef != NULL)
+ {
+ int avail = 0;
+
+ if (act_add_locdef->locale == NULL)
+ act_add_locdef->locale = locfile_read (act_add_locdef->name,
+ charset);
+
+ if (! act_add_locdef->locale->failed)
+ {
+ avail = act_add_locdef->locale->categories[cat].generic != NULL;
+ if (avail)
+ localedef->categories[cat].generic
+ = act_add_locdef->locale->categories[cat].generic;
+ }
+
+ if (! avail)
+ {
+ const char *locale_names[] = { "LC_COLLATE", "LC_CTYPE",
+ "LC_MONETARY", "LC_NUMERIC",
+ "LC_TIME", "LC_MESSAGES" };
+ char *fname;
+ int fd;
+ struct stat st;
+
+ asprintf (&fname, LOCALE_PATH "/%s/%s", act_add_locdef->name,
+ locale_names[cat]);
+ fd = open (fname, O_RDONLY);
+ if (fd == -1)
+ {
+ free (fname);
+
+ asprintf (&fname, LOCALE_PATH "/%s/%s/SYS_%s",
+ act_add_locdef->name, locale_names[cat],
+ locale_names[cat]);
+
+ fd = open (fname, O_RDONLY);
+ if (fd == -1)
+ error (5, 0, _("\
+locale file `%s', used in `copy' statement, not found"),
+ act_add_locdef->name);
+ }
+
+ if (fstat (fd, &st) < 0)
+ error (5, errno, _("\
+cannot `stat' locale file `%s'"),
+ fname);
+
+ localedef->len[cat] = st.st_size;
+ localedef->categories[cat].generic
+ = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ if (localedef->categories[cat].generic == (void *) -1)
+ {
+ size_t left = st.st_size;
+ void *read_ptr;
+
+ localedef->categories[cat].generic
+ = xmalloc (st.st_size);
+ read_ptr = localedef->categories[cat].generic;
+
+ do
+ {
+ long int n;
+ n = read (fd, read_ptr, left);
+ if (n == 1)
+ error (5, errno, _("cannot read locale file `%s'"),
+ fname);
+ read_ptr += n;
+ left -= n;
+ }
+ while (left > 0);
+ }
+
+ close (fd);
+ free (fname);
+
+ localedef->binary |= 1 << cat;
+ }
+ }
+ }
+ while (act_add_locdef != NULL);
+
+ /* Check the categories we processed in source form. */
+ check_all_categories (localedef, charset);
+
+ /* We are now able to write the data files. If warning were given we
+ do it only if it is explicitly requested (--force). */
+ if (error_message_count == 0 || force_output != 0)
+ {
+ if (cannot_write_why != 0)
+ error (4, cannot_write_why, _("cannot write output files to `%s'"),
+ output_path);
+ else
+ write_all_categories (localedef, output_path);
+ }
+ else
+ error (4, 0, _("no output file produced because warning were issued"));
+
+ /* This exit status is prescribed by POSIX.2 4.35.7. */
+ exit (error_message_count != 0);
+}
+
+
+void
+def_to_process (const char *name, int category)
+{
+ struct copy_def_list_t *new, **rp;
+
+ for (rp = &copy_list; *rp != NULL; rp = &(*rp)->next)
+ if (strcmp (name, (*rp)->name) == 0)
+ break;
+
+ if (*rp == NULL)
+ {
+ size_t cnt;
+
+ *rp = (struct copy_def_list_t *) xmalloc (sizeof (**rp));
+
+ (*rp)->next = NULL;
+ (*rp)->name = name;
+ (*rp)->mask = 0;
+ (*rp)->locale = NULL;
+
+ for (cnt = 0; cnt < 6; ++cnt)
+ {
+ (*rp)->binary[cnt].data = NULL;
+ (*rp)->binary[cnt].len = 0;
+ }
+ }
+ new = *rp;
+
+ if ((new->mask & category) != 0)
+ /* We already have the information. This cannot happen. */
+ error (5, 0, _("\
+category data requested more than once: should not happen"));
+
+ new->mask |= category;
+}
+
+
+/* Display usage information and exit. */
+static void
+usage (int status)
+{
+ if (status != 0)
+ fprintf (stderr, _("Try `%s --help' for more information.\n"),
+ program_name);
+ else
+ printf (_("\
+Usage: %s [OPTION]... name\n\
+Mandatory arguments to long options are mandatory for short options too.\n\
+ -c, --force create output even if warning messages were issued\n\
+ -h, --help display this help and exit\n\
+ -f, --charmap=FILE symbolic character names defined in FILE\n\
+ -i, --inputfile=FILE source definitions are found in FILE\n\
+ -u, --code-set-name=NAME specify code set for mapping ISO 10646 elements\n\
+ -v, --verbose print more messages\n\
+ -V, --version output version information and exit\n\
+ --posix be strictly POSIX conform\n\
+\n\
+System's directory for character maps: %s\n\
+ locale files : %s\n"),
+ program_name, CHARMAP_PATH, LOCALE_PATH);
+
+ exit (status);
+}
+
+
+/* The address of this function will be assigned to the hook in the error
+ functions. */
+static void
+error_print ()
+{
+ /* We don't want the program name to be printed in messages. Emacs'
+ compile.el does not like this. */
+}
+
+
+/* The parameter to localedef describes the output path. If it does
+ contain a '/' character it is a relativ path. Otherwise it names the
+ locale this definition is for. */
+static const char *
+construct_output_path (const char *path)
+{
+ char *result;
+
+ if (strchr (path, '/') == NULL)
+ {
+ /* This is a system path. */
+ int path_max_len = pathconf (LOCALE_PATH, _PC_PATH_MAX) + 1;
+ result = (char *) xmalloc (path_max_len);
+
+ snprintf (result, path_max_len, "%s/%s", LOCALE_PATH, path);
+ }
+ else
+ {
+ char *t;
+ /* This is a user path. */
+ result = xmalloc (strlen (path) + 2);
+ t = stpcpy (result, path);
+ *t = '\0';
+ }
+
+ errno = 0;
+
+ if (euidaccess (result, W_OK) == -1)
+ /* Perhaps the directory does not exist now. Try to create it. */
+ if (errno == ENOENT)
+ {
+ errno = 0;
+ mkdir (result, 0777);
+ }
+
+ strcat (result, "/");
+
+ return result;
+}
diff --git a/locale/programs/locales.h b/locale/programs/locales.h
new file mode 100644
index 0000000000..3c7676b765
--- /dev/null
+++ b/locale/programs/locales.h
@@ -0,0 +1,207 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef _LOCALES_H
+#define _LOCALES_H
+
+#include <ctype.h>
+
+/* Undefine following line in production version. */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+#include "linereader.h"
+#include "locfile-token.h"
+#include "charset.h"
+#include "locfile.h"
+#include "localeinfo.h"
+
+
+/* Header of the locale data files. */
+struct locale_file
+{
+ int magic;
+ int n;
+};
+
+
+/* Handle LC_CTYPE category. */
+
+static inline unsigned int
+charclass_to_bit (enum token_t tok)
+{
+ static unsigned int lastbit = _ISalnum;
+
+ switch (tok)
+ {
+#define CLASS(name) case tok_##name: return _IS##name
+ CLASS (upper);
+ CLASS (lower);
+ CLASS (alpha);
+ CLASS (digit);
+ CLASS (alnum);
+ CLASS (space);
+ CLASS (cntrl);
+ CLASS (punct);
+ CLASS (graph);
+ CLASS (print);
+ CLASS (xdigit);
+ CLASS (blank);
+#undef CLASS
+ case tok_string:
+ lastbit <<= 1;
+ if (lastbit == 0ul)
+ /* Exit status 2 means a limitation in the implementation is
+ exceeded. */
+ error (2, 0, _("too many character classes defined"));
+ return lastbit;
+ default:
+ assert (1 == 0);
+ }
+ return 0;
+}
+
+/* Remember name of newly created charclass. */
+void ctype_startup (struct linereader *lr, struct localedef_t *locale,
+ struct charset_t *__charset);
+void ctype_finish (struct localedef_t *__locale, struct charset_t *__charset);
+
+void ctype_output (struct localedef_t *locale, const char *output_path);
+
+int ctype_is_charclass (struct linereader *lr, struct localedef_t *locale,
+ const char *__name);
+void ctype_class_new (struct linereader *lr, struct localedef_t *locale,
+ enum token_t __tok, struct token *__code,
+ struct charset_t *__charset);
+void ctype_class_start (struct linereader *lr, struct localedef_t *locale,
+ enum token_t __tok, const char *__name,
+ struct charset_t *__charset);
+void ctype_class_from (struct linereader *lr, struct localedef_t *locale,
+ struct token *__code, struct charset_t *__charset);
+void ctype_class_to (struct linereader *lr, struct localedef_t *locale,
+ struct token *__code, struct charset_t *__charset);
+void ctype_class_end (struct linereader *lr, struct localedef_t *locale);
+
+int ctype_is_charmap (struct linereader *lr, struct localedef_t *locale,
+ const char *__name);
+void ctype_map_new (struct linereader *lr, struct localedef_t *locale,
+ enum token_t __tok, struct token *__code,
+ struct charset_t *__charset);
+void ctype_map_start (struct linereader *lr, struct localedef_t *locale,
+ enum token_t __tok, const char *__name,
+ struct charset_t *__charset);
+void ctype_map_from (struct linereader *lr, struct localedef_t *locale,
+ struct token *__code, struct charset_t *__charset);
+void ctype_map_to (struct linereader *lr, struct localedef_t *locale,
+ struct token *__code, struct charset_t *__charset);
+void ctype_map_end (struct linereader *lr, struct localedef_t *locale);
+
+
+/* Handle LC_COLLATE category. */
+
+void collate_startup (struct linereader *__lr, struct localedef_t *__locale,
+ struct charset_t *__charset);
+
+void collate_finish (struct localedef_t *__locale,
+ struct charset_t *__charset);
+
+void collate_output (struct localedef_t *locale, const char *output_path);
+
+void collate_element_to (struct linereader *__lr, struct localedef_t *__locale,
+ struct token *__code, struct charset_t *__charset);
+void collate_element_from (struct linereader *__lr,
+ struct localedef_t *__locale, struct token *__code,
+ struct charset_t *__charset);
+void collate_symbol (struct linereader *__lr, struct localedef_t *__locale,
+ struct token *__code, struct charset_t *__charset);
+void collate_new_order (struct linereader *__lr, struct localedef_t *__locale,
+ enum coll_sort_rule __sort_rule);
+void collate_build_arrays (struct linereader *__lr,
+ struct localedef_t *__locale);
+int collate_order_elem (struct linereader *__lr, struct localedef_t *__locale,
+ struct token *__code, struct charset_t *__charset);
+int collate_weight_bsymbol (struct linereader *__lr,
+ struct localedef_t *__locale,
+ struct token *__code, struct charset_t *__charset);
+int collate_next_weight (struct linereader *__lr,
+ struct localedef_t *__locale);
+int collate_simple_weight (struct linereader *__lr,
+ struct localedef_t *__locale,
+ struct token *__code, struct charset_t *__charset);
+void collate_end_weight (struct linereader *__lr,
+ struct localedef_t *__locale);
+
+
+/* Handle LC_MONETARY category. */
+
+void monetary_startup (struct linereader *__lr, struct localedef_t *__locale,
+ struct charset_t *__charset);
+
+void monetary_finish (struct localedef_t *__locale);
+
+void monetary_output (struct localedef_t *locale, const char *output_path);
+
+void monetary_add (struct linereader *lr, struct localedef_t *locale,
+ enum token_t __tok, struct token *__code,
+ struct charset_t *__charset);
+
+
+/* Handle LC_NUMERIC category. */
+
+void numeric_startup (struct linereader *__lr, struct localedef_t *__locale,
+ struct charset_t *__charset);
+
+void numeric_finish (struct localedef_t *__locale);
+
+void numeric_output (struct localedef_t *locale, const char *output_path);
+
+void numeric_add (struct linereader *lr, struct localedef_t *locale,
+ enum token_t __tok, struct token *__code,
+ struct charset_t *__charset);
+
+
+/* Handle LC_TIME category. */
+
+void time_startup (struct linereader *__lr, struct localedef_t *__locale,
+ struct charset_t *__charset);
+
+void time_finish (struct localedef_t *__locale);
+
+void time_output (struct localedef_t *locale, const char *output_path);
+
+void time_add (struct linereader *lr, struct localedef_t *locale,
+ enum token_t __tok, struct token *__code,
+ struct charset_t *__charset);
+
+
+/* Handle LC_MESSAGES category. */
+
+void messages_startup (struct linereader *__lr, struct localedef_t *__locale,
+ struct charset_t *__charset);
+
+void messages_finish (struct localedef_t *__locale);
+
+void messages_output (struct localedef_t *locale, const char *output_path);
+
+void messages_add (struct linereader *lr, struct localedef_t *locale,
+ enum token_t __tok, struct token *__code,
+ struct charset_t *__charset);
+
+
+#endif /* locales.h */
diff --git a/locale/programs/locfile-kw.gperf b/locale/programs/locfile-kw.gperf
new file mode 100644
index 0000000000..85e031c777
--- /dev/null
+++ b/locale/programs/locfile-kw.gperf
@@ -0,0 +1,99 @@
+%{
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <string.h>
+
+#include "locfile-token.h"
+%}
+struct keyword_t ;
+%%
+escape_char, tok_escape_char, 0
+comment_char, tok_comment_char, 0
+LC_CTYPE, tok_lc_ctype, 0
+END, tok_end, 0
+copy, tok_copy, 0
+upper, tok_upper, 0
+lower, tok_lower, 0
+alpha, tok_alpha, 0
+digit, tok_digit, 0
+alnum, tok_alnum, 0
+space, tok_space, 0
+cntrl, tok_cntrl, 0
+punct, tok_punct, 0
+graph, tok_graph, 0
+print, tok_print, 0
+xdigit, tok_xdigit, 0
+blank, tok_blank, 0
+charclass, tok_charclass, 0
+charmap, tok_charmap, 0
+toupper, tok_toupper, 0
+tolower, tok_tolower, 0
+LC_COLLATE, tok_lc_collate, 0
+collating-element, tok_collating_element, 0
+collating-symbol, tok_collating_symbol, 0
+order_start, tok_order_start, 0
+order_end, tok_order_end, 0
+from, tok_from, 0
+forward, tok_forward, 0
+backward, tok_backward, 0
+position, tok_position, 0
+UNDEFINED, tok_undefined, 0
+IGNORE, tok_ignore, 0
+LC_MONETARY, tok_lc_monetary, 0
+int_curr_symbol, tok_int_curr_symbol, 0
+currency_symbol, tok_currency_symbol, 0
+mon_decimal_point, tok_mon_decimal_point, 0
+mon_thousands_sep, tok_mon_thousands_sep, 0
+mon_grouping, tok_mon_grouping, 0
+positive_sign, tok_positive_sign, 0
+negative_sign, tok_negative_sign, 0
+int_frac_digits, tok_int_frac_digits, 0
+frac_digits, tok_frac_digits, 0
+p_cs_precedes, tok_p_cs_precedes, 0
+p_sep_by_space, tok_p_sep_by_space, 0
+n_cs_precedes, tok_n_cs_precedes, 0
+n_sep_by_space, tok_n_sep_by_space, 0
+p_sign_posn, tok_p_sign_posn, 0
+n_sign_posn, tok_n_sign_posn, 0
+LC_NUMERIC, tok_lc_numeric, 0
+decimal_point, tok_decimal_point, 0
+thousands_sep, tok_thousands_sep, 0
+grouping, tok_grouping, 0
+LC_TIME, tok_lc_time, 0
+abday, tok_abday, 0
+day, tok_day, 0
+abmon, tok_abmon, 0
+mon, tok_mon, 0
+d_t_fmt, tok_d_t_fmt, 0
+d_fmt, tok_d_fmt, 0
+t_fmt, tok_t_fmt, 0
+am_pm, tok_am_pm, 0
+t_fmt_ampm, tok_t_fmt_ampm, 0
+era, tok_era, 0
+era_year, tok_era_year, 0
+era_d_fmt, tok_era_d_fmt, 0
+era_d_t_fmt, tok_era_d_t_fmt, 0
+era_t_fmt, tok_era_t_fmt, 0
+alt_digits, tok_alt_digits, 0
+LC_MESSAGES, tok_lc_messages, 0
+yesexpr, tok_yesexpr, 0
+noexpr, tok_noexpr, 0
+yesstr, tok_yesstr, 0
+nostr, tok_nostr, 0
diff --git a/locale/programs/locfile-kw.h b/locale/programs/locfile-kw.h
new file mode 100644
index 0000000000..c892669893
--- /dev/null
+++ b/locale/programs/locfile-kw.h
@@ -0,0 +1,211 @@
+/* C code produced by gperf version 2.5 (GNU C++ version) */
+/* Command-line: gperf -acCgopt -k1,2,5,$ -N locfile_hash programs/locfile-kw.gperf */
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <string.h>
+
+#include "locfile-token.h"
+struct keyword_t ;
+
+#define TOTAL_KEYWORDS 73
+#define MIN_WORD_LENGTH 3
+#define MAX_WORD_LENGTH 17
+#define MIN_HASH_VALUE 3
+#define MAX_HASH_VALUE 185
+/* maximum key range = 183, duplicates = 0 */
+
+#ifdef __GNUC__
+inline
+#endif
+static unsigned int
+hash (register const char *str, register int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ 186, 186, 186, 186, 186, 186, 186, 0, 0, 0,
+ 0, 0, 186, 0, 186, 186, 0, 186, 0, 35,
+ 186, 186, 0, 0, 0, 5, 186, 186, 186, 0,
+ 186, 186, 186, 186, 186, 15, 186, 0, 0, 5,
+ 15, 10, 55, 30, 15, 75, 186, 20, 5, 40,
+ 10, 0, 0, 186, 35, 30, 0, 70, 186, 10,
+ 20, 75, 186, 186, 186, 186, 186, 186,
+ };
+ register int hval = len;
+
+ switch (hval)
+ {
+ default:
+ case 5:
+ hval += asso_values[(int) str[4]];
+ case 4:
+ case 3:
+ case 2:
+ hval += asso_values[(int) str[1]];
+ case 1:
+ hval += asso_values[(int) str[0]];
+ break;
+ }
+ return hval + asso_values[(int) str[len - 1]];
+}
+
+#ifdef __GNUC__
+inline
+#endif
+const struct keyword_t *
+locfile_hash (register const char *str, register int len)
+{
+ static const struct keyword_t wordlist[] =
+ {
+ {"",}, {"",}, {"",},
+ {"END", tok_end, 0},
+ {"",}, {"",},
+ {"IGNORE", tok_ignore, 0},
+ {"LC_TIME", tok_lc_time, 0},
+ {"LC_CTYPE", tok_lc_ctype, 0},
+ {"",},
+ {"alpha", tok_alpha, 0},
+ {"LC_MESSAGES", tok_lc_messages, 0},
+ {"",}, {"",},
+ {"UNDEFINED", tok_undefined, 0},
+ {"LC_NUMERIC", tok_lc_numeric, 0},
+ {"",}, {"",},
+ {"position", tok_position, 0},
+ {"",},
+ {"t_fmt", tok_t_fmt, 0},
+ {"",},
+ {"collating-element", tok_collating_element, 0},
+ {"positive_sign", tok_positive_sign, 0},
+ {"",},
+ {"abmon", tok_abmon, 0},
+ {"collating-symbol", tok_collating_symbol, 0},
+ {"",}, {"",}, {"",},
+ {"cntrl", tok_cntrl, 0},
+ {"",}, {"",},
+ {"backward", tok_backward, 0},
+ {"",},
+ {"d_fmt", tok_d_fmt, 0},
+ {"",}, {"",}, {"",},
+ {"p_sep_by_space", tok_p_sep_by_space, 0},
+ {"print", tok_print, 0},
+ {"",},
+ {"toupper", tok_toupper, 0},
+ {"negative_sign", tok_negative_sign, 0},
+ {"",},
+ {"LC_COLLATE", tok_lc_collate, 0},
+ {"LC_MONETARY", tok_lc_monetary, 0},
+ {"",},
+ {"era", tok_era, 0},
+ {"n_sep_by_space", tok_n_sep_by_space, 0},
+ {"blank", tok_blank, 0},
+ {"noexpr", tok_noexpr, 0},
+ {"tolower", tok_tolower, 0},
+ {"mon", tok_mon, 0},
+ {"era_t_fmt", tok_era_t_fmt, 0},
+ {"space", tok_space, 0},
+ {"",},
+ {"mon_thousands_sep", tok_mon_thousands_sep, 0},
+ {"thousands_sep", tok_thousands_sep, 0},
+ {"",},
+ {"alt_digits", tok_alt_digits, 0},
+ {"",},
+ {"comment_char", tok_comment_char, 0},
+ {"",},
+ {"charclass", tok_charclass, 0},
+ {"t_fmt_ampm", tok_t_fmt_ampm, 0},
+ {"p_sign_posn", tok_p_sign_posn, 0},
+ {"charmap", tok_charmap, 0},
+ {"",},
+ {"era_d_fmt", tok_era_d_fmt, 0},
+ {"",},
+ {"era_d_t_fmt", tok_era_d_t_fmt, 0},
+ {"mon_decimal_point", tok_mon_decimal_point, 0},
+ {"p_cs_precedes", tok_p_cs_precedes, 0},
+ {"",},
+ {"punct", tok_punct, 0},
+ {"n_sign_posn", tok_n_sign_posn, 0},
+ {"forward", tok_forward, 0},
+ {"decimal_point", tok_decimal_point, 0},
+ {"",},
+ {"lower", tok_lower, 0},
+ {"order_start", tok_order_start, 0},
+ {"",},
+ {"n_cs_precedes", tok_n_cs_precedes, 0},
+ {"copy", tok_copy, 0},
+ {"nostr", tok_nostr, 0},
+ {"escape_char", tok_escape_char, 0},
+ {"",}, {"",}, {"",},
+ {"alnum", tok_alnum, 0},
+ {"",},
+ {"d_t_fmt", tok_d_t_fmt, 0},
+ {"day", tok_day, 0},
+ {"order_end", tok_order_end, 0},
+ {"digit", tok_digit, 0},
+ {"",}, {"",}, {"",}, {"",},
+ {"graph", tok_graph, 0},
+ {"",}, {"",},
+ {"grouping", tok_grouping, 0},
+ {"",},
+ {"currency_symbol", tok_currency_symbol, 0},
+ {"",}, {"",}, {"",}, {"",},
+ {"int_curr_symbol", tok_int_curr_symbol, 0},
+ {"",},
+ {"mon_grouping", tok_mon_grouping, 0},
+ {"",}, {"",}, {"",},
+ {"xdigit", tok_xdigit, 0},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"am_pm", tok_am_pm, 0},
+ {"yesstr", tok_yesstr, 0},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"from", tok_from, 0},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",},
+ {"upper", tok_upper, 0},
+ {"frac_digits", tok_frac_digits, 0},
+ {"yesexpr", tok_yesexpr, 0},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"abday", tok_abday, 0},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"era_year", tok_era_year, 0},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",},
+ {"int_frac_digits", tok_int_frac_digits, 0},
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*s == *str && !strncmp (str + 1, s + 1, len - 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/locale/programs/locfile-token.h b/locale/programs/locfile-token.h
new file mode 100644
index 0000000000..1c3cfdc9db
--- /dev/null
+++ b/locale/programs/locfile-token.h
@@ -0,0 +1,147 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef _TOKEN_H
+#define _TOKEN_H
+
+enum token_t
+{
+ tok_none = 0,
+
+ tok_eof,
+ tok_eol,
+ tok_bsymbol,
+ tok_ident,
+ tok_ellipsis,
+ tok_semicolon,
+ tok_comma,
+ tok_open_brace,
+ tok_close_brace,
+ tok_charcode,
+ tok_ucs2,
+ tok_ucs4,
+ tok_number,
+ tok_minus1,
+ tok_string,
+
+ tok_escape_char,
+ tok_comment_char,
+ tok_end,
+ tok_g0esc,
+ tok_g1esc,
+ tok_g2esc,
+ tok_g3esc,
+
+ tok_code_set_name,
+ tok_mb_cur_max,
+ tok_mb_cur_min,
+ tok_charmap,
+ tok_width,
+ tok_width_variable,
+ tok_width_default,
+
+ tok_lc_ctype,
+ tok_copy,
+ tok_upper,
+ tok_lower,
+ tok_alpha,
+ tok_digit,
+ tok_xdigit,
+ tok_space,
+ tok_print,
+ tok_graph,
+ tok_blank,
+ tok_cntrl,
+ tok_punct,
+ tok_alnum,
+ tok_charclass,
+ tok_toupper,
+ tok_tolower,
+ tok_lc_collate,
+ tok_collating_element,
+ tok_collating_symbol,
+ tok_order_start,
+ tok_order_end,
+ tok_from,
+ tok_forward,
+ tok_backward,
+ tok_position,
+ tok_undefined,
+ tok_ignore,
+ tok_lc_monetary,
+ tok_int_curr_symbol,
+ tok_currency_symbol,
+ tok_mon_decimal_point,
+ tok_mon_thousands_sep,
+ tok_mon_grouping,
+ tok_positive_sign,
+ tok_negative_sign,
+ tok_int_frac_digits,
+ tok_frac_digits,
+ tok_p_cs_precedes,
+ tok_p_sep_by_space,
+ tok_n_cs_precedes,
+ tok_n_sep_by_space,
+ tok_p_sign_posn,
+ tok_n_sign_posn,
+ tok_lc_numeric,
+ tok_decimal_point,
+ tok_thousands_sep,
+ tok_grouping,
+ tok_lc_time,
+ tok_abday,
+ tok_day,
+ tok_abmon,
+ tok_mon,
+ tok_d_t_fmt,
+ tok_d_fmt,
+ tok_t_fmt,
+ tok_am_pm,
+ tok_t_fmt_ampm,
+ tok_era,
+ tok_era_year,
+ tok_era_d_fmt,
+ tok_era_d_t_fmt,
+ tok_era_t_fmt,
+ tok_alt_digits,
+ tok_lc_messages,
+ tok_yesexpr,
+ tok_noexpr,
+ tok_yesstr,
+ tok_nostr,
+
+ tok_error
+};
+
+
+struct keyword_t
+{
+ const char *name;
+ enum token_t token;
+ int symname_or_ident;
+
+ /* Only for locdef file. */
+ int locale;
+ enum token_t base;
+ enum token_t group;
+ enum token_t list;
+};
+
+
+#endif /* token.h */
diff --git a/locale/programs/locfile.c b/locale/programs/locfile.c
new file mode 100644
index 0000000000..cb98a5d530
--- /dev/null
+++ b/locale/programs/locfile.c
@@ -0,0 +1,979 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include "locfile.h"
+#include "linereader.h"
+#include "localeinfo.h"
+#include "locales.h"
+
+
+/* Uncomment the following line in the production version. */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+/* Define the lookup function. */
+#include "locfile-kw.h"
+
+
+/* Some useful macros. */
+#define MIN(a, b) (__extension__ ({ typeof (a) _a = (a); \
+ typeof (b) _b = (b); \
+ _a < _b ? _a : _b; }))
+
+
+void *xmalloc (size_t __n);
+char *xstrdup (const char *__str);
+
+struct localedef_t *
+locfile_read (const char *filename, struct charset_t *charset)
+{
+ struct linereader *ldfile;
+ struct localedef_t *result;
+ int state;
+ enum token_t expected_tok = tok_none;
+ const char *expected_str = NULL;
+ enum token_t ctype_tok_sym = tok_none;
+ const char *ctype_tok_str = NULL;
+ int copy_category = 0;
+ int cnt;
+
+ /* Allocate space for result. */
+ result = (struct localedef_t *) xmalloc (sizeof (struct localedef_t));
+ memset (result, '\0', sizeof (struct localedef_t));
+
+ ldfile = lr_open (filename, locfile_hash);
+ if (ldfile == NULL)
+ {
+ if (filename[0] != '/')
+ {
+ char path[strlen (filename) + 1 + sizeof (LOCSRCDIR)];
+
+ stpcpy (stpcpy (stpcpy (path, LOCSRCDIR), "/"), filename);
+ ldfile = lr_open (path, locfile_hash);
+ }
+
+ if (ldfile == NULL)
+ {
+ result->failed = 1;
+ return result;
+ }
+ }
+
+#define HANDLE_COPY(category, token, string) \
+ if (nowtok == tok_copy) \
+ { \
+ copy_category = category; \
+ expected_tok = token; \
+ expected_str = string; \
+ state = 8; \
+ continue; \
+ } \
+ ++state
+
+#define LOCALE_PROLOG(token, string) \
+ if (nowtok == tok_eol) \
+ /* Ignore empty lines. */ \
+ continue; \
+ if (nowtok == tok_end) \
+ { \
+ expected_tok = token; \
+ expected_str = string; \
+ state = 4; \
+ continue; \
+ } \
+ if (nowtok == tok_copy) \
+ goto only_copy;
+
+
+#define READ_STRING(fn, errlabel) \
+ do \
+ { \
+ arg = lr_token (ldfile, charset); \
+ if (arg->tok != tok_string) \
+ goto errlabel; \
+ fn (ldfile, result, nowtok, arg, charset); \
+ lr_ignore_rest (ldfile, 1); \
+ } \
+ while (0)
+
+#define READ_STRING_LIST(fn, errlabel) \
+ do \
+ { \
+ arg = lr_token (ldfile, charset); \
+ while (arg->tok == tok_string) \
+ { \
+ fn (ldfile, result, nowtok, arg, charset); \
+ arg = lr_token (ldfile, charset); \
+ if (arg->tok != tok_semicolon) \
+ break; \
+ arg = lr_token (ldfile, charset); \
+ } \
+ if (arg->tok != tok_eol) \
+ goto errlabel; \
+ } \
+ while (0)
+
+#define READ_NUMBER(fn, errlabel) \
+ do \
+ { \
+ arg = lr_token (ldfile, charset); \
+ if (arg->tok != tok_minus1 && arg->tok != tok_number) \
+ goto errlabel; \
+ fn (ldfile, result, nowtok, arg, charset); \
+ lr_ignore_rest (ldfile, 1); \
+ } \
+ while (0)
+
+#define READ_NUMBER_LIST(fn, errlabel) \
+ do \
+ { \
+ arg = lr_token (ldfile, charset); \
+ while (arg->tok == tok_minus1 || arg->tok == tok_number) \
+ { \
+ fn (ldfile, result, nowtok, arg, charset); \
+ arg = lr_token (ldfile, charset); \
+ if (arg->tok != tok_semicolon) \
+ break; \
+ arg = lr_token (ldfile, charset); \
+ } \
+ if (arg->tok != tok_eol) \
+ goto errlabel; \
+ } \
+ while (0)
+
+#define SYNTAX_ERROR(string) \
+ lr_error (ldfile, string); \
+ lr_ignore_rest (ldfile, 0);
+
+
+ /* Parse locale definition file and store result in RESULT. */
+ state = 1;
+ while (1)
+ {
+ /* What's on? */
+ struct token *now = lr_token (ldfile, charset);
+ enum token_t nowtok = now->tok;
+ struct token *arg;
+
+ if (nowtok == tok_eof)
+ break;
+
+ switch (state)
+ {
+ case 1:
+ /* The beginning. We expect the special declarations, EOL or
+ the start of any locale. */
+ if (nowtok == tok_eol)
+ /* Ignore empty lines. */
+ continue;
+
+ switch (nowtok)
+ {
+ case tok_escape_char:
+ case tok_comment_char:
+ /* We need an argument. */
+ arg = lr_token (ldfile, charset);
+
+ if (arg->tok != tok_ident)
+ {
+ SYNTAX_ERROR (_("bad argument"));
+ continue;
+ }
+
+ if (arg->val.str.len != 1)
+ {
+ lr_error (ldfile, _("\
+argument to `%s' must be a single character"),
+ nowtok == tok_escape_char ? "escape_char"
+ : "comment_char");
+
+ lr_ignore_rest (ldfile, 0);
+ continue;
+ }
+
+ if (nowtok == tok_escape_char)
+ ldfile->escape_char = *arg->val.str.start;
+ else
+ ldfile->comment_char = *arg->val.str.start;
+ break;
+
+ case tok_lc_ctype:
+ state = 2;
+ break;
+
+ case tok_lc_collate:
+ state = 10;
+ break;
+
+ case tok_lc_monetary:
+ state = 20;
+ break;
+
+ case tok_lc_numeric:
+ state = 30;
+ break;
+
+ case tok_lc_time:
+ state = 40;
+ break;
+
+ case tok_lc_messages:
+ state = 50;
+ break;
+
+ default:
+ SYNTAX_ERROR (_("\
+syntax error: not inside a locale definition section"));
+ continue;
+ }
+ lr_ignore_rest (ldfile, 1);
+ continue;
+
+ case 2:
+ HANDLE_COPY (LC_CTYPE, tok_lc_ctype, "LC_CYTPE");
+
+ ctype_startup (ldfile, result, charset);
+ /* FALLTHROUGH */
+
+ case 3:
+ /* Here we accept all the character classes, tolower/toupper,
+ and following ANSI C:1995 self-defined classes. */
+ LOCALE_PROLOG (tok_lc_ctype, "LC_CTYPE");
+
+ if (nowtok == tok_charclass)
+ {
+ READ_STRING_LIST (ctype_class_new, bad_new_charclass);
+ continue;
+ bad_new_charclass:
+ SYNTAX_ERROR (_("\
+syntax error in definition of new character class"));
+ continue;
+ }
+
+ if (nowtok == tok_charmap)
+ {
+ READ_STRING_LIST (ctype_map_new, bad_new_charmap);
+ continue;
+ bad_new_charmap:
+ SYNTAX_ERROR (_("\
+syntax error in definition of new character map"));
+ continue;
+ }
+
+ if (nowtok == tok_upper || nowtok == tok_lower
+ || nowtok == tok_alpha || nowtok == tok_digit
+ || nowtok == tok_alnum || nowtok == tok_space
+ || nowtok == tok_cntrl || nowtok == tok_punct
+ || nowtok == tok_graph || nowtok == tok_print
+ || nowtok == tok_xdigit || nowtok == tok_blank)
+ {
+ ctype_tok_sym = nowtok;
+ ctype_tok_str = NULL;
+ state = 5;
+ continue;
+ }
+
+ if (nowtok == tok_toupper|| nowtok == tok_tolower)
+ {
+ ctype_tok_sym = nowtok;
+ ctype_tok_str = NULL;
+ state = 6;
+ continue;
+ }
+
+ if (nowtok != tok_ident)
+ goto bad_charclass;
+
+ /* We possibly have a self-defined character class. */
+ if (ctype_is_charclass (ldfile, result, now->val.str.start))
+ {
+ ctype_tok_sym = nowtok;
+ ctype_tok_str = now->val.str.start;
+ state = 5;
+ continue;
+ }
+
+ /* ...or a self-defined character map. */
+ if (ctype_is_charmap (ldfile, result, now->val.str.start))
+ {
+ ctype_tok_sym = nowtok;
+ ctype_tok_str = now->val.str.start;
+ state = 6;
+ continue;
+ }
+
+ SYNTAX_ERROR (_("syntax error in definition of LC_CTYPE category"));
+ continue;
+
+ case 4:
+ /* Handle `END xxx'. */
+ if (nowtok != expected_tok)
+ lr_error (ldfile, _("\
+`%1$s' definition does not end with `END %1$s'"), expected_str);
+
+ lr_ignore_rest (ldfile, nowtok == expected_tok);
+ state = 1;
+ continue;
+
+ case 5:
+ /* Here we expect a semicolon separated list of bsymbols. The
+ bit to be set in the word is given in CHARCLASS_BIT. */
+ arg = now;
+
+ ctype_class_start (ldfile, result, ctype_tok_sym, ctype_tok_str,
+ charset);
+
+ while (arg->tok != tok_eol)
+ {
+ /* Any token other than a bsymbol is an error. */
+ if (arg->tok != tok_bsymbol)
+ {
+ bad_charclass:
+ SYNTAX_ERROR (_("\
+syntax error in character class definition"));
+ break;
+ }
+
+ /* Lookup value for token and write into array. */
+ ctype_class_from (ldfile, result, arg, charset);
+
+ arg = lr_token (ldfile, charset);
+ if (arg->tok == tok_semicolon)
+ arg = lr_token (ldfile, charset);
+ else if (arg->tok != tok_eol)
+ goto bad_charclass;
+
+ /* Look for ellipsis. */
+ if (arg->tok == tok_ellipsis)
+ {
+ arg = lr_token (ldfile, charset);
+ if (arg->tok != tok_semicolon)
+ goto bad_charclass;
+
+ arg = lr_token (ldfile, charset);
+ if (arg->tok != tok_bsymbol)
+ goto bad_charclass;
+
+ /* Write range starting at LAST to ARG->VAL. */
+ ctype_class_to (ldfile, result, arg, charset);
+
+ arg = lr_token (ldfile, charset);
+ if (arg->tok == tok_semicolon)
+ arg = lr_token (ldfile, charset);
+ else if (arg->tok != tok_eol)
+ goto bad_charclass;
+ }
+ }
+
+ /* Mark class as already seen. */
+ ctype_class_end (ldfile, result);
+ state = 3;
+
+ continue;
+
+ case 6:
+ /* Here we expect a list of character mappings. Note: the
+ first opening brace is already matched. */
+ ctype_map_start (ldfile, result, ctype_tok_sym, ctype_tok_str,
+ charset);
+
+ while (1)
+ {
+ /* Match ( bsymbol , bsymbol ) */
+ if (now->tok != tok_open_brace)
+ goto bad_charmap;
+
+ now = lr_token (ldfile, charset);
+ if (now->tok != tok_bsymbol)
+ {
+ bad_charmap:
+ SYNTAX_ERROR (_("\
+syntax error in character mapping definition"));
+ state = 3;
+ break;
+ }
+
+ /* Lookup arg and assign to FROM. */
+ ctype_map_from (ldfile, result, now, charset);
+
+ now = lr_token (ldfile, charset);
+ if (now->tok != tok_comma)
+ goto bad_charmap;
+
+ now = lr_token (ldfile, charset);
+ if (now->tok != tok_bsymbol)
+ goto bad_charmap;
+
+ /* Lookup arg and assign to TO. */
+ ctype_map_to (ldfile, result, now, charset);
+
+ now = lr_token (ldfile, charset);
+ if (now->tok != tok_close_brace)
+ goto bad_charmap;
+
+ now = lr_token (ldfile, charset);
+ if (now->tok == tok_eol)
+ {
+ state = 3;
+ break;
+ }
+ if (now->tok != tok_semicolon)
+ goto bad_charmap;
+
+ now = lr_token (ldfile, charset);
+ }
+
+ ctype_map_end (ldfile, result);
+ continue;
+
+ case 8:
+ {
+ /* We have seen `copy'. First match the argument. */
+ int warned = 0;
+
+ if (nowtok != tok_string)
+ lr_error (ldfile, _("expect string argument for `copy'"));
+ else
+ def_to_process (now->val.str.start, 1 << copy_category);
+
+ lr_ignore_rest (ldfile, nowtok == tok_string);
+
+ /* The rest of the line must be empty
+ and the next keyword must be `END xxx'. */
+
+ while (lr_token (ldfile, charset)->tok != tok_end)
+ {
+ if (warned == 0)
+ {
+ only_copy:
+ lr_error (ldfile, _("\
+no other keyword shall be specified when `copy' is used"));
+ warned = 1;
+ }
+
+ lr_ignore_rest (ldfile, 0);
+ }
+
+ state = 4;
+ }
+ continue;
+
+ case 10:
+ HANDLE_COPY (LC_COLLATE, tok_lc_collate, "LC_COLLATE");
+
+ collate_startup (ldfile, result, charset);
+ /* FALLTHROUGH */
+
+ case 11:
+ /* Process the LC_COLLATE section. We expect `END LC_COLLATE'
+ any of the collation specifications, or any bsymbol. */
+ LOCALE_PROLOG (tok_lc_collate, "LC_COLLATE");
+
+ if (nowtok == tok_order_start)
+ {
+ state = 12;
+ continue;
+ }
+
+ if (nowtok != tok_collating_element
+ && nowtok != tok_collating_symbol)
+ {
+ bad_collation:
+ lr_error (ldfile, _("\
+syntax error in collation definition"));
+ lr_ignore_rest (ldfile, 0);
+ continue;
+ }
+
+ /* Get argument. */
+ arg = lr_token (ldfile, charset);
+ if (arg->tok != tok_bsymbol)
+ {
+ lr_error (ldfile, _("\
+collation symbol expected after `%s'"),
+ nowtok == tok_collating_element
+ ? "collating-element" : "collating-symbol");
+ lr_ignore_rest (ldfile, 0);
+ continue;
+ }
+
+ if (nowtok == tok_collating_element)
+ {
+ /* Save to-value as new name. */
+ collate_element_to (ldfile, result, arg, charset);
+
+ arg = lr_token (ldfile, charset);
+ if (arg->tok != tok_from)
+ {
+ lr_error (ldfile, _("\
+`from' expected after first argument to `collating-element'"));
+ lr_ignore_rest (ldfile, 0);
+ continue;
+ }
+
+ arg = lr_token (ldfile, charset);
+ if (arg->tok != tok_string)
+ {
+ lr_error (ldfile, _("\
+from-value of `collating-element' must be a string"));
+ lr_ignore_rest (ldfile, 0);
+ continue;
+ }
+
+ /* Enter new collating element. */
+ collate_element_from (ldfile, result, arg, charset);
+ }
+ else
+ /* Enter new collating symbol into table. */
+ collate_symbol (ldfile, result, arg, charset);
+
+ lr_ignore_rest (ldfile, 1);
+ continue;
+
+ case 12:
+ /* We parse the rest of the line containing `order_start'.
+ In any case we continue with parsing the symbols. */
+ state = 13;
+
+ cnt = 0;
+ while (now->tok != tok_eol)
+ {
+ int collation_method = 0;
+
+ ++cnt;
+
+ do
+ {
+ if (now->tok == tok_forward)
+ collation_method |= sort_forward;
+ else if (now->tok == tok_backward)
+ collation_method |= sort_backward;
+ else if (now->tok == tok_position)
+ collation_method |= sort_position;
+ else
+ {
+ lr_error (ldfile, _("unknown collation directive"));
+ lr_ignore_rest (ldfile, 0);
+ continue;
+ }
+
+ now = lr_token (ldfile, charset);
+ }
+ while (now->tok == tok_comma
+ && (now == lr_token (ldfile, charset) != tok_none));
+
+ /* Check for consistency: forward and backwards are
+ mutually exclusive. */
+ if ((collation_method & sort_forward) != 0
+ && (collation_method & sort_backward) != 0)
+ {
+ lr_error (ldfile, _("\
+sorting order `forward' and `backward' are mutually exclusive"));
+ /* The recover clear the backward flag. */
+ collation_method &= ~sort_backward;
+ }
+
+ /* ??? I don't know whether this is correct but while
+ thinking about the `strcoll' functions I found that I
+ need a direction when performing position depended
+ collation. So I assume here that implicitly the
+ direction `forward' is given when `position' alone is
+ written. --drepper */
+ if (collation_method == sort_position)
+ collation_method |= sort_forward;
+
+ /* Enter info about next collation order. */
+ collate_new_order (ldfile, result, collation_method);
+
+ if (now->tok != tok_eol && now->tok != tok_semicolon)
+ {
+ lr_error (ldfile, _("\
+syntax error in `order_start' directive"));
+ lr_ignore_rest (ldfile, 0);
+ break;
+ }
+
+ if (now->tok == tok_semicolon)
+ now = lr_token (ldfile, charset);
+ }
+
+ /* If no argument to `order_start' is given, one `forward'
+ argument is implicitely assumed. */
+ if (cnt == 0)
+ collate_new_order (ldfile, result, sort_forward);
+
+
+ /* We now know about all sorting rules. */
+ collate_build_arrays (ldfile, result);
+
+ continue;
+
+ case 13:
+ /* We read one symbol a line until `order_end' is found. */
+ {
+ static int last_correct = 1;
+
+ if (nowtok == tok_order_end)
+ {
+ state = 14;
+ lr_ignore_rest (ldfile, 1);
+ continue;
+ }
+
+ /* Ignore empty lines. */
+ if (nowtok == tok_eol)
+ continue;
+
+ if (nowtok != tok_bsymbol && nowtok != tok_undefined
+ && nowtok != tok_ellipsis)
+ {
+ if (last_correct == 1)
+ {
+ lr_error (ldfile, _("\
+syntax error in collating order definition"));
+ last_correct = 0;
+ }
+ lr_ignore_rest (ldfile, 0);
+ continue;
+ }
+ else
+ {
+ last_correct = 1;
+
+ /* Remember current token. */
+ if (collate_order_elem (ldfile, result, now, charset) < 0)
+ continue;
+ }
+
+ /* Read optional arguments. */
+ arg = lr_token (ldfile, charset);
+ while (arg->tok != tok_eol)
+ {
+ if (arg->tok != tok_ignore && arg->tok != tok_ellipsis
+ && arg->tok != tok_bsymbol && arg->tok != tok_string)
+ break;
+
+ if (arg->tok == tok_ignore || arg->tok == tok_ellipsis
+ || arg->tok == tok_string)
+ {
+ /* Call handler for simple weights. */
+ if (collate_simple_weight (ldfile, result, arg, charset)
+ < 0)
+ goto illegal_weight;
+
+ arg = lr_token (ldfile, charset);
+ }
+ else
+ do
+ {
+ /* Collect char. */
+ int ok = collate_weight_bsymbol (ldfile, result, arg,
+ charset);
+ if (ok < 0)
+ goto illegal_weight;
+
+ arg = lr_token (ldfile, charset);
+ }
+ while (arg->tok == tok_bsymbol);
+
+ /* Are there more weights? */
+ if (arg->tok != tok_semicolon)
+ break;
+
+ /* Yes, prepare next weight. */
+ if (collate_next_weight (ldfile, result) < 0)
+ goto illegal_weight;
+
+ arg = lr_token (ldfile, charset);
+ }
+
+ if (arg->tok != tok_eol)
+ {
+ SYNTAX_ERROR (_("syntax error in order specification"));
+ }
+
+ collate_end_weight (ldfile, result);
+ illegal_weight:
+ }
+ continue;
+
+ case 14:
+ /* Following to the `order_end' keyword we don't expect
+ anything but the `END'. */
+ if (nowtok == tok_eol)
+ continue;
+
+ if (nowtok != tok_end)
+ goto bad_collation;
+
+ expected_tok = tok_lc_collate;
+ expected_str = "LC_COLLATE";
+ state = 4;
+
+ ldfile->translate_strings = 1;
+ continue;
+
+ case 20:
+ HANDLE_COPY (LC_MONETARY, tok_lc_monetary, "LC_MONETARY");
+
+ monetary_startup (ldfile, result, charset);
+ /* FALLTHROUGH */
+
+ case 21:
+ LOCALE_PROLOG (tok_lc_monetary, "LC_MONETARY");
+
+ switch (nowtok)
+ {
+ case tok_int_curr_symbol:
+ case tok_currency_symbol:
+ case tok_mon_decimal_point:
+ case tok_mon_thousands_sep:
+ case tok_positive_sign:
+ case tok_negative_sign:
+ READ_STRING (monetary_add, bad_monetary);
+ break;
+
+ case tok_int_frac_digits:
+ case tok_frac_digits:
+ case tok_p_cs_precedes:
+ case tok_p_sep_by_space:
+ case tok_n_cs_precedes:
+ case tok_n_sep_by_space:
+ case tok_p_sign_posn:
+ case tok_n_sign_posn:
+ READ_NUMBER (monetary_add, bad_monetary);
+ break;
+
+ case tok_mon_grouping:
+ /* We have a semicolon separated list of integers. */
+ READ_NUMBER_LIST (monetary_add, bad_monetary);
+ break;
+
+ default:
+ bad_monetary:
+ SYNTAX_ERROR (_("syntax error in monetary locale definition"));
+ }
+ continue;
+
+ case 30:
+ HANDLE_COPY (LC_NUMERIC, tok_lc_numeric, "LC_NUMERIC");
+
+ numeric_startup (ldfile, result, charset);
+ /* FALLTHROUGH */
+
+ case 31:
+ LOCALE_PROLOG (tok_lc_numeric, "LC_NUMERIC");
+
+ switch (nowtok)
+ {
+ case tok_decimal_point:
+ case tok_thousands_sep:
+ READ_STRING (numeric_add, bad_numeric);
+ break;
+
+ case tok_grouping:
+ /* We have a semicolon separated list of integers. */
+ READ_NUMBER_LIST (numeric_add, bad_numeric);
+ break;
+
+ default:
+ bad_numeric:
+ SYNTAX_ERROR (_("syntax error in numeric locale definition"));
+ }
+ continue;
+
+ case 40:
+ HANDLE_COPY (LC_TIME, tok_lc_time, "LC_TIME");
+
+ time_startup (ldfile, result, charset);
+ /* FALLTHROUGH */
+
+ case 41:
+ LOCALE_PROLOG (tok_lc_time, "LC_TIME");
+
+ switch (nowtok)
+ {
+ case tok_abday:
+ case tok_day:
+ case tok_abmon:
+ case tok_mon:
+ case tok_am_pm:
+ case tok_alt_digits:
+ READ_STRING_LIST (time_add, bad_time);
+ continue;
+
+ case tok_d_t_fmt:
+ case tok_d_fmt:
+ case tok_t_fmt:
+ case tok_t_fmt_ampm:
+ case tok_era:
+ case tok_era_year:
+ case tok_era_d_t_fmt:
+ case tok_era_d_fmt:
+ case tok_era_t_fmt:
+ READ_STRING (time_add, bad_time);
+ break;
+
+ default:
+ bad_time:
+ SYNTAX_ERROR (_("syntax error in time locale definition"));
+ }
+ continue;
+
+ case 50:
+ HANDLE_COPY (LC_MESSAGES, tok_lc_messages, "LC_MESSAGES");
+
+ messages_startup (ldfile, result, charset);
+ /* FALLTHROUGH */
+
+ case 51:
+ LOCALE_PROLOG (tok_lc_messages, "LC_MESSAGES");
+
+ switch (nowtok)
+ {
+ case tok_yesexpr:
+ case tok_noexpr:
+ case tok_yesstr:
+ case tok_nostr:
+ READ_STRING (messages_add, bad_message);
+ break;
+
+ default:
+ bad_message:
+ SYNTAX_ERROR (_("syntax error in message locale definition"));
+ }
+ continue;
+
+ default:
+ error (5, 0, _("%s: error in state machine"), __FILE__);
+ /* NOTREACHED */
+ }
+
+ break;
+ }
+
+ /* We read all of the file. */
+ lr_close (ldfile);
+
+ /* Let's see what information is available. */
+ for (cnt = LC_CTYPE; cnt <= LC_MESSAGES; ++cnt)
+ if (result->categories[cnt].generic != NULL)
+ result->avail |= 1 << cnt;
+
+ return result;
+}
+
+
+void
+check_all_categories (struct localedef_t *locale, struct charset_t *charset)
+{
+ /* Call the finishing functions for all locales. */
+ if ((locale->binary & (1 << LC_CTYPE)) == 0)
+ ctype_finish (locale, charset);
+ if ((locale->binary & (1 << LC_COLLATE)) == 0)
+ collate_finish (locale, charset);
+ if ((locale->binary & (1 << LC_MONETARY)) == 0)
+ monetary_finish (locale);
+ if ((locale->binary & (1 << LC_NUMERIC)) == 0)
+ numeric_finish (locale);
+ if ((locale->binary & (1 << LC_TIME)) == 0)
+ time_finish (locale);
+ if ((locale->binary & (1 << LC_MESSAGES)) == 0)
+ messages_finish (locale);
+}
+
+
+void
+write_all_categories (struct localedef_t *locale, const char *output_path)
+{
+ /* Call all functions to write locale data. */
+ ctype_output (locale, output_path);
+ collate_output (locale, output_path);
+ monetary_output (locale, output_path);
+ numeric_output (locale, output_path);
+ time_output (locale, output_path);
+ messages_output (locale, output_path);
+}
+
+
+void
+write_locale_data (const char *output_path, const char *category,
+ size_t n_elem, struct iovec *vec)
+{
+ size_t cnt, step;
+ int fd;
+ char *fname;
+
+ asprintf (&fname, "%s/%s", output_path, category);
+ fd = creat (fname, 0666);
+ if (fd == -1)
+ {
+ int save_err = errno;
+
+ if (errno == EISDIR)
+ {
+ free (fname);
+ asprintf (&fname, "%1$s/%2$s/SYS_%2$s", output_path, category);
+ fd = creat (fname, 0666);
+ if (fd == -1)
+ save_err = errno;
+ }
+
+ if (fd == -1)
+ {
+ error (0, save_err, _("cannot open output file for category `%s'"),
+ category);
+ return;
+ }
+ }
+ free (fname);
+
+ /* Write the data using writev. But we must take care for the
+ limitation of the implementation. */
+ for (cnt = 0; cnt < n_elem; cnt += step)
+ {
+ /* XXX Fixme: should be in libc header. */
+#ifndef MAX_IOVEC
+# define MAX_IOVEC 8
+#endif
+ step = MIN (MAX_IOVEC, n_elem - cnt);
+
+ if (writev (fd, &vec[cnt], step) < 0)
+ {
+ error (0, errno, _("failure while writing data for category `%s'"),
+ category);
+ break;
+ }
+ }
+
+ close (fd);
+}
diff --git a/locale/programs/locfile.h b/locale/programs/locfile.h
new file mode 100644
index 0000000000..e337e961ed
--- /dev/null
+++ b/locale/programs/locfile.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef _LOCFILE_H
+#define _LOCFILE_H
+
+#include <sys/uio.h>
+
+#include "charset.h"
+
+/* Opaque types for the different loales. */
+struct locale_ctype_t;
+struct locale_collate_t;
+struct locale_monetary_t;
+struct locale_numeric_t;
+struct locale_time_t;
+struct locale_messages_t;
+
+struct localedef_t
+{
+ int failed;
+
+ int avail;
+ int binary;
+
+ union
+ {
+ void *generic;
+ struct locale_ctype_t *ctype;
+ struct locale_collate_t *collate;
+ struct locale_monetary_t *monetary;
+ struct locale_numeric_t *numeric;
+ struct locale_time_t *time;
+ struct locale_messages_t *messages;
+ } categories[6];
+
+ size_t len[6];
+};
+
+
+/* Found in localedef.c. */
+void def_to_process (const char *name, int category);
+
+
+/* Found in locfile.c. */
+struct localedef_t *locfile_read (const char *filename,
+ struct charset_t *charset);
+
+void check_all_categories (struct localedef_t *locale,
+ struct charset_t *charset);
+
+void write_all_categories (struct localedef_t *locale,
+ const char *output_path);
+
+
+void write_locale_data (const char *output_path, const char *category,
+ size_t n_elem, struct iovec *vec);
+
+#endif /* locfile.h */
diff --git a/locale/programs/stringtrans.c b/locale/programs/stringtrans.c
new file mode 100644
index 0000000000..bff5aa41a2
--- /dev/null
+++ b/locale/programs/stringtrans.c
@@ -0,0 +1,146 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+COntributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "charset.h"
+#include "stringtrans.h"
+
+
+/* Global variable. */
+enum encoding_method encoding_method = ENC_UCS4;
+
+
+void *xmalloc (size_t __n);
+void *xrealloc (void *__p, size_t __n);
+
+
+#define ADDC(ch) \
+ do \
+ { \
+ if (bufact == bufmax) \
+ { \
+ bufmax *= 2; \
+ buf = xrealloc (buf, bufmax); \
+ } \
+ buf[bufact++] = (ch); \
+ } \
+ while (0)
+
+
+char *
+translate_string (char *str, struct charset_t *charset)
+{
+ char *buf;
+ size_t bufact = 0;
+ size_t bufmax = 56;
+
+ buf = (char *) xmalloc (bufmax);
+
+ while (str[0] != '\0')
+ {
+ char *tp;
+ unsigned int value;
+
+ if (str[0] != '<')
+ {
+ ADDC (*str++);
+ continue;
+ }
+
+ tp = &str[1];
+ while (tp[0] != '\0' && tp[0] != '>')
+ if (tp[0] == '\\')
+ if (tp[1] != '\0')
+ tp += 2;
+ else
+ ++tp;
+ else
+ ++tp;
+
+ if (tp[0] == '\0')
+ {
+ free (buf);
+ return NULL;
+ }
+
+ value = charset_find_value (charset, str + 1, tp - (str + 1));
+ if (value == ILLEGAL_CHAR_VALUE)
+ {
+ free (buf);
+ return NULL;
+ }
+ else
+ {
+ /* Encode string using current method. */
+ char *cp;
+
+ if (bufmax - bufact < 8)
+ {
+ bufmax *= 2;
+ buf = (char *) xrealloc (buf, bufmax);
+ }
+
+ cp = &buf[bufact];
+ if (encode_char (value, &cp) < 0)
+ {
+ free (buf);
+ return NULL;
+ }
+ bufact = cp - buf;
+ }
+
+ str = &tp[1];
+ }
+
+ ADDC ('\0');
+
+ return buf;;
+}
+
+
+int
+encode_char (unsigned int value, char **cpp)
+{
+ switch (encoding_method)
+ {
+ case ENC_UCS1:
+ if (value > 255)
+ return -11;
+ *(*cpp)++ = (char) value;
+ break;
+
+ case ENC_UCS4:
+ *(*cpp)++ = (char) (value >> 24);
+ *(*cpp)++ = (char) ((value >> 16) & 0xff);
+ *(*cpp)++ = (char) ((value >> 8) & 0xff);
+ *(*cpp)++ = (char) (value & 0xff);
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/locale/programs/stringtrans.h b/locale/programs/stringtrans.h
new file mode 100644
index 0000000000..3576ce445c
--- /dev/null
+++ b/locale/programs/stringtrans.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef _TRANSLATE_H
+#define _TRANSLATE_H 1
+
+enum encoding_method
+{
+ ENC_UCS1,
+ ENC_UCS4
+};
+
+
+extern enum encoding_method encoding_method;
+
+
+char *translate_string (char *__str, struct charset_t *__charset);
+
+int encode_char (unsigned int __value, char **__cpp);
+
+
+#endif /* translate.h */
diff --git a/locale/setlocale.c b/locale/setlocale.c
index 509bb4ffa1..70ec6eba6e 100644
--- a/locale/setlocale.c
+++ b/locale/setlocale.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -290,7 +290,7 @@ setlocale (int category, const char *name)
/* The composite name did not specify all categories. */
return NULL;
}
-
+
/* Load the new data for each category. */
while (category-- > 0)
/* Only actually load the data if anything will use it. */
diff --git a/locale/token.h b/locale/token.h
deleted file mode 100644
index 1227920083..0000000000
--- a/locale/token.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
-
-The GNU C 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.
-
-The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#ifndef _TOKEN_H
-#define _TOKEN_H 1
-
-/* Define those keywords which does not correspond directly to any
- item in a category. Those already have values. */
-
-enum token
- {
- /* We must make sure that these values do not overlap with the
- other possible return values of the lexer. */
- TOK_LAST_USED = _NL_NUM,
-
- /* General tokens. */
- TOK_END, TOK_COMMENT_CHAR, TOK_COPY, TOK_ESCAPE_CHAR, TOK_FROM,
- TOK_ENDOFLINE, TOK_IDENT, TOK_STRING, TOK_ELLIPSIS, TOK_CHAR,
- TOK_ILL_CHAR, TOK_NUMBER, TOK_MINUS1,
-
- /* Tokens from the collate category. */
- TOK_IGNORE, TOK_UNDEFINED, TOK_BACKWARD, TOK_FORWARD, TOK_POSITION,
- TOK_COLLATING_ELEMENT, TOK_COLLATING_SYMBOL, TOK_ORDER_END,
- TOK_ORDER_START,
-
- /* Tokens from the ctype category. */
- TOK_TOLOWER, TOK_TOUPPER,
- /* The order here is important. It must correspond to the bits
- used for indicating the class membership (ctype.h). */
- TOK_UPPER, TOK_LOWER, TOK_ALPHA, TOK_DIGIT, TOK_XDIGIT, TOK_SPACE,
- TOK_PRINT, TOK_GRAPH, TOK_BLANK, TOK_CNTRL, TOK_PUNCT,
- };
-
-/*
- * Local Variables:
- * mode:c
- * c-basic-offset:2
- * End:
- */
-#endif /* token.h */
diff --git a/locale/weight.h b/locale/weight.h
new file mode 100644
index 0000000000..5a9bcd7486
--- /dev/null
+++ b/locale/weight.h
@@ -0,0 +1,171 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Written by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <alloca.h>
+
+
+#ifndef STRING_TYPE
+# error STRING_TYPE not defined
+#endif
+
+#ifndef USTRING_TYPE
+# error USTRING_TYPE not defined
+#endif
+
+typedef struct weight_t
+{
+ struct weight_t *prev;
+ struct weight_t *next;
+ struct data_pair {
+ size_t number;
+ u32_t *value;
+ } data[0];
+} weight_t;
+
+
+/* The following five macros grant access to the non-byte order
+ dependend values in the collate locale file. */
+#define collate_nrules \
+ (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES))
+#define collate_hash_size \
+ (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_HASH_SIZE))
+#define collate_hash_layers \
+ (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_HASH_LAYERS))
+#define collate_undefined \
+ (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_UNDEFINED))
+#define collate_rules \
+ (_NL_CURRENT (LC_COLLATE, _NL_COLLATE_RULES))
+
+
+static __inline int get_weight (const STRING_TYPE **str, weight_t *result);
+static __inline int
+get_weight (const STRING_TYPE **str, weight_t *result)
+{
+ unsigned int ch = *((USTRING_TYPE *) (*str))++;
+ size_t slot;
+
+ if (sizeof (STRING_TYPE) == 1)
+ slot = ch * (collate_nrules + 1);
+ else
+ {
+ const size_t level_size = collate_hash_size * (collate_nrules + 1);
+ size_t level;
+
+ slot = (ch * (collate_nrules + 1)) % collate_hash_size;
+
+ level = 0;
+ while (__collate_table[slot] != (u32_t) ch)
+ {
+ if (__collate_table[slot + 1] == 0
+ || ++level >= collate_hash_layers)
+ {
+ size_t idx = collate_undefined;
+ size_t cnt;
+
+ for (cnt = 0; cnt < collate_nrules; ++cnt)
+ {
+ result->data[cnt].number = __collate_extra[idx++];
+ result->data[cnt].value = &__collate_extra[idx];
+ idx += result->data[cnt].number;
+ }
+ return 0;
+ }
+ slot += level_size;
+ }
+ }
+
+ if (__collate_table[slot + 1] != FORWARD_CHAR)
+ {
+ /* We have a simple form. One one value for each weight. */
+ size_t cnt;
+
+ for (cnt = 0; cnt < collate_nrules; ++cnt)
+ {
+ result->data[cnt].number = 1;
+ result->data[cnt].value = &__collate_table[slot + 1 + cnt];
+ }
+ return ch == 0;
+ }
+
+ /* We now look for any collation element which starts with CH.
+ There might none, but the last list member is a catch-all case
+ because it is simple the character CH. The value of this entry
+ might be the same as UNDEFINED. */
+ slot = __collate_table[slot + 2];
+
+ while (1)
+ {
+ size_t idx;
+
+ /* This is a comparison between a u32_t array (aka wchar_t) and
+ an 8-bit string. */
+ for (idx = 0; __collate_extra[slot + 2 + idx] != 0; ++idx)
+ if (__collate_extra[slot + 2 + idx] != (u32_t) str[idx])
+ break;
+
+ /* When the loop finished with all character of the collation
+ element used, we found the longest prefix. */
+ if (__collate_extra[slot + 2 + idx] == 0)
+ {
+ size_t cnt;
+
+ idx += slot + 3;
+ for (cnt = 0; cnt < collate_nrules; ++cnt)
+ {
+ result->data[cnt].number = __collate_extra[idx++];
+ result->data[cnt].value = &__collate_extra[idx];
+ idx += result->data[cnt].number;
+ }
+ return 0;
+ }
+
+ /* To next entry in list. */
+ slot += __collate_extra[slot];
+ }
+ /* NOTREACHED */
+ return 0; /* To calm down gcc. */
+}
+
+
+/* To process a string efficiently we retrieve all information about
+ the string at once. The following macro constructs a double linked
+ list of this information. It is a macro because we use `alloca'
+ and we use a double linked list because of the backward collation
+ order. */
+#define get_string(str, forw, backw) \
+ do \
+ { \
+ weight_t *newp; \
+ do \
+ { \
+ newp = (weight_t *) alloca (sizeof (weight_t) \
+ + (collate_nrules \
+ * sizeof (struct data_pair))); \
+ \
+ newp->prev = backw; \
+ if (backw == NULL) \
+ forw = newp; \
+ else \
+ backw->next = newp; \
+ newp->next = NULL; \
+ backw = newp; \
+ } \
+ while (get_weight (&str, newp) == 0); \
+ } \
+ while (0)
diff --git a/misc/error.c b/misc/error.c
index c48c0f3c46..b12041c761 100644
--- a/misc/error.c
+++ b/misc/error.c
@@ -47,11 +47,15 @@ Cambridge, MA 02139, USA. */
void exit ();
#endif
+#ifndef _
+#define _(String) String
+#endif
+
/* If NULL, error will flush stdout, then print on stderr the program
name, a colon and a space. Otherwise, error will call this
function without parameters instead. */
void (*error_print_progname) (
-#if __STDC__
+#if __STDC__ - 0
void
#endif
);
@@ -85,7 +89,7 @@ private_strerror (errnum)
if (errnum > 0 && errnum <= sys_nerr)
return sys_errlist[errnum];
- return "Unknown system error";
+ return _("Unknown system error");
}
#define strerror private_strerror
#endif /* HAVE_STRERROR */
@@ -133,7 +137,74 @@ error (status, errnum, message, va_alist)
#endif
++error_message_count;
+ if (errnum)
+ fprintf (stderr, ": %s", strerror (errnum));
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
+
+/* Sometimes we want to have at most one error per line. This
+ variable controls whether this mode is selected or not. */
+int error_one_per_line;
+
+void
+#if defined(VA_START) && __STDC__
+error_at_line (int status, int errnum, const char *file_name,
+ unsigned int line_number, const char *message, ...)
+#else
+error_at_line (status, errnum, file_name, line_number, message, va_alist)
+ int status;
+ int errnum;
+ const char *file_name;
+ unsigned int line_number;
+ char *message;
+ va_dcl
+#endif
+{
+#ifdef VA_START
+ va_list args;
+#endif
+
+ if (error_one_per_line)
+ {
+ static const char *old_file_name;
+ static unsigned int old_line_number;
+ if (old_line_number == line_number
+ && (file_name == old_file_name || !strcmp (old_file_name, file_name))
+ /* Simply return and print nothing. */
+ return;
+
+ old_file_name = file_name;
+ old_line_number = line_number;
+ }
+
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ {
+ fflush (stdout);
+ fprintf (stderr, "%s:", program_name);
+ }
+
+ if (file_name != NULL)
+ fprintf (stderr, "%s:%d: ", file_name, line_number);
+
+#ifdef VA_START
+ VA_START (args, message);
+# if HAVE_VPRINTF || _LIBC
+ vfprintf (stderr, message, args);
+# else
+ _doprnt (message, args, stderr);
+# endif
+ va_end (args);
+#else
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+ ++error_message_count;
if (errnum)
fprintf (stderr, ": %s", strerror (errnum));
putc ('\n', stderr);
diff --git a/misc/error.h b/misc/error.h
index 749dce429d..95ceb1aa82 100644
--- a/misc/error.h
+++ b/misc/error.h
@@ -44,6 +44,10 @@ Cambridge, MA 02139, USA. */
extern void error (int status, int errnum, const char *format, ...)
__attribute__ ((__format__ (__printf__, 3, 4)));
+extern void error_at_line (int status, int errnum, const char *fname,
+ unsigned int lineno, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 5, 6)));
+
/* If NULL, error will flush stdout, then print on stderr the program
name, a colon and a space. Otherwise, error will call this
function without parameters instead. */
@@ -51,10 +55,15 @@ extern void (*error_print_progname) (void);
#else
void error ();
+void error_at_line ();
extern void (*error_print_progname) ();
#endif
/* This variable is incremented each time `error' is called. */
extern unsigned int error_message_count;
+/* Sometimes we want to have at most one error per line. This
+ variable controls whether this mode is selected or not. */
+extern int error_one_per_line;
+
#endif /* _error_h_ */
diff --git a/posix/unistd.h b/posix/unistd.h
index 2ac0b2f172..0fc3d7bb92 100644
--- a/posix/unistd.h
+++ b/posix/unistd.h
@@ -50,6 +50,10 @@ __BEGIN_DECLS
Software Development Utilities Option. */
#define _POSIX2_SW_DEV 1
+/* If defined, the implementation supports the
+ creation of locales with the localedef utility. */
+#define _POSIX2_LOCALEDEF 1
+
/* Get values of POSIX options:
diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c
index 5cf60f131c..009bdee0d5 100644
--- a/stdio-common/printf_fp.c
+++ b/stdio-common/printf_fp.c
@@ -625,11 +625,22 @@ __printf_fp (FILE *fp,
/* All factors but 10^-1 are tested now. */
if (exponent > 0)
{
+ int cnt_l;
+
cy = __mpn_mul_1 (tmp, frac, fracsize, 10);
tmpsize = fracsize;
assert (cy == 0 || tmp[tmpsize - 1] < 20);
- (void) __mpn_rshift (frac, tmp, tmpsize, MIN (4, exponent));
+ count_trailing_zeros (cnt_l, tmp[0]);
+ if (cnt_l < MIN (4, exponent))
+ {
+ cy = __mpn_lshift (frac, tmp, tmpsize,
+ BITS_PER_MP_LIMB - MIN (4, exponent));
+ if (cy != 0)
+ frac[tmpsize++] = cy;
+ }
+ else
+ (void) __mpn_rshift (frac, tmp, tmpsize, MIN (4, exponent));
fracsize = tmpsize;
exp10 |= 1;
assert (frac[fracsize - 1] < 10);
diff --git a/stdio-common/tfformat.c b/stdio-common/tfformat.c
index 02230f11ba..60785d803f 100644
--- a/stdio-common/tfformat.c
+++ b/stdio-common/tfformat.c
@@ -10,7 +10,7 @@ typedef struct
const char *format_string;
} sprint_double_type;
-sprint_double_type sprint_doubles[] =
+sprint_double_type sprint_doubles[] =
{
__LINE__, 30.3, "< +30.3>", "<%+15.10g>",
__LINE__, 10.0, "<10.00>", "<%5.2f>",
@@ -4071,6 +4071,23 @@ int main()
testcount++;
}
+ /* And one special test. */
+ {
+ const char ref[] = "1.7763568394002504646778106689453125e-15";
+ int i;
+ d = 1.0;
+ for (i = 1; i < 50; ++i)
+ d /= 2;
+ sprintf (buffer, "%.100g", d);
+ if (!matches (buffer, ref))
+ {
+ ++errcount;
+ printf (
+ "Error in line %d using \"%s\". Result is \"%s\"; should be: \"%s\".\n",
+ __LINE__, "%.100g", buffer, ref);
+ }
+ }
+
if (errcount == 0)
{
printf("Encountered no errors in %d tests.\n", testcount);
diff --git a/string/strcoll.c b/string/strcoll.c
index 9dee89fa7a..13e9f0d132 100644
--- a/string/strcoll.c
+++ b/string/strcoll.c
@@ -1,5 +1,6 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
+Written by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
@@ -13,22 +14,145 @@ Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
+#include "localeinfo.h"
+
+#ifndef STRING_TYPE
+# define STRING_TYPE char
+# define USTRING_TYPE unsigned char
+# define STRCOLL strcoll
+#endif
+
+/* Include the shared helper functions. `strxfrm'/`wcsxfrm' also use
+ these functions. */
+#include "weight.h"
/* Compare S1 and S2, returning less than, equal to or
- greater than zero if the collated form of S1 is lexiographically
+ greater than zero if the collated form of S1 is lexicographically
less than, equal to or greater than the collated form of S2. */
int
-strcoll (s1, s2)
- const char *s1;
- const char *s2;
+STRCOLL (s1, s2)
+ const STRING_TYPE *s1;
+ const STRING_TYPE *s2;
{
- /* XXX LC_COLLATE not implemented yet. */
- return strcmp (s1, s2);
+ weight_t *s1forw = NULL;
+ weight_t *s1backw = NULL;
+ weight_t *s2forw = NULL;
+ weight_t *s2backw = NULL;
+ size_t pass;
+
+ /* If the current locale does not specify locale data we use normal
+ 8-bit string comparison. */
+ if (collate_nrules == 0)
+ return strcmp (s1, s2);
+
+ /* Get full information about the strings. This means we get
+ information for all passes in a special data structure. */
+ get_string (s1, s1forw, s1backw);
+ get_string (s2, s2forw, s2backw);
+
+ /* Now we have all the information. In at most the given number of
+ passes we can finally decide about the order. */
+ for (pass = 0; pass < collate_nrules; ++pass)
+ {
+ int forward = (collate_rules[pass] & sort_forward) != 0;
+ const weight_t *s1run = forward ? s1forw : s1backw;
+ const weight_t *s2run = forward ? s2forw : s2backw;
+ int s1idx = forward ? 0 : s1run->data[pass].number - 1;
+ int s2idx = forward ? 0 : s2run->data[pass].number - 1;
+
+ do
+ {
+ int s1ignore = 0;
+ int s2ignore = 0;
+ u32_t w1, w2;
+
+ /* Here we have to check for IGNORE entries. If these are
+ found we count them and go on witht he next value. */
+ while ((w1 = s1run->data[pass].value[s1idx]) == IGNORE_CHAR)
+ {
+ ++s1ignore;
+ if ((forward && ++s1idx >= s1run->data[pass].number)
+ || (!forward && --s1idx < 0))
+ {
+ weight_t *nextp = forward ? s1run->next : s1run->prev;
+ if (nextp == NULL)
+ {
+ w1 = 0;
+ break;
+ }
+ s1run = nextp;
+ s1idx = forward ? 0 : s1run->data[pass].number - 1;
+ }
+ }
+
+ while ((w2 = s2run->data[pass].value[s2idx]) == IGNORE_CHAR)
+ {
+ ++s2ignore;
+ if ((forward && ++s2idx >= s2run->data[pass].number)
+ || (!forward && --s2idx < 0))
+ {
+ weight_t *nextp = forward ? s2run->next : s2run->prev;
+ if (nextp == NULL)
+ {
+ w2 = 0;
+ break;
+ }
+ s2run = nextp;
+ s2idx = forward ? 0 : s2run->data[pass].number - 1;
+ }
+ }
+
+ /* Now we have information of the number of ignored
+ weights and the value of the next weight. */
+ if ((collate_rules[pass] & sort_position) != 0
+ && s1ignore != s2ignore && (w1 != 0 || w2 != 0))
+ return s1ignore < s2ignore ? -1 : 1;
+
+ if (w1 != w2)
+ return w1 < w2 ? -1 : 1;
+
+ /* We have to increment the index counters. */
+ if ((forward && ++s1idx >= s1run->data[pass].number)
+ || (!forward && --s1idx < 0))
+ if (forward)
+ {
+ s1run = s1run->next;
+ s1idx = 0;
+ }
+ else
+ {
+ s1run = s1run->prev;
+ if (s1run != NULL)
+ s1idx = s1run->data[pass].number - 1;
+ }
+
+ if ((forward && ++s2idx >= s2run->data[pass].number)
+ || (!forward && --s2idx < 0))
+ if (forward)
+ {
+ s2run = s2run->next;
+ s2idx = 0;
+ }
+ else
+ {
+ s2run = s2run->prev;
+ if (s2run != NULL)
+ s2idx = s2run->data[pass].number - 1;
+ }
+
+ }
+ while (s1run != NULL && s2run != NULL);
+
+ if (s1run != s2run)
+ return s1run != NULL ? 1 : -1;
+ }
+
+ return 0;
}
diff --git a/string/strxfrm.c b/string/strxfrm.c
index e40ae1c433..7dce9c117f 100644
--- a/string/strxfrm.c
+++ b/string/strxfrm.c
@@ -1,5 +1,6 @@
-/* Copyright (C) 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
+Written by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
@@ -13,12 +14,87 @@ Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
+#include "localeinfo.h"
+
+#ifndef STRING_TYPE
+# define STRING_TYPE char
+# define USTRING_TYPE unsigned char
+# define STRXFRM strxfrm
+# define STRLEN strlen
+# define STPNCPY __stpncpy
+#endif
+
+/* Include the shared helper functions. `strxfrm'/`wcsxfrm' also use
+ these functions. */
+#include "weight.h"
+
+
+/* Write 32 bit value UTF-8 encoded but only if enough space is left. */
+static __inline size_t
+print_val (value, dest, max, act)
+ u32_t value;
+ STRING_TYPE *dest;
+ size_t max;
+ size_t act;
+{
+ char tmp[6];
+ int idx = 0;
+
+ if (value < 0x80)
+ tmp[idx++] = (char) value;
+ else
+ {
+ tmp[idx++] = '\x80' + (char) (value & 0x3f);
+ value >>= 6;
+
+ if (value < 0x20)
+ tmp[idx++] = '\xc0' + (char) value;
+ else
+ {
+ tmp[idx++] = '\x80' + (char) (value & 0x3f);
+ value >>= 6;
+
+ if (value < 0x10)
+ tmp[idx++] = '\xe0' + (char) value;
+ else
+ {
+ tmp[idx++] = '\x80' + (char) (value & 0x3f);
+ value >>= 6;
+
+ if (value < 0x08)
+ tmp[idx++] = '\xf0' + (char) value;
+ else
+ {
+ tmp[idx++] = '\x80' + (char) (value & 0x3f);
+ value >>= 6;
+
+ if (value < 0x04)
+ tmp[idx++] = '\xf8' + (char) value;
+ else
+ {
+ tmp[idx++] = '\x80' + (char) (value & 0x3f);
+ tmp[idx++] = '\xfc' + (char) (value >> 6);
+ }
+ }
+ }
+ }
+ }
+
+ while (idx-- > 0)
+ {
+ if (act < max)
+ dest[act] = tmp[idx];
+ ++act;
+ }
+
+ return act;
+}
/* Transform SRC into a form such that the result of strcmp
@@ -27,13 +103,94 @@ Cambridge, MA 02139, USA. */
their transformation. The transformed string is put in at
most N characters of DEST and its length is returned. */
size_t
-strxfrm (dest, src, n)
- char *dest;
- const char *src;
+STRXFRM (dest, src, n)
+ STRING_TYPE *dest;
+ const STRING_TYPE *src;
size_t n;
{
- if (n == 0)
- return strlen (src);
+ weight_t *forw = NULL;
+ weight_t *backw = NULL;
+ size_t pass;
+ size_t written;
+
+ /* If the current locale does not specify locale data we use normal
+ 8-bit string comparison. */
+ if (collate_nrules == 0)
+ {
+ if (n != 0)
+ STPNCPY (dest, src, n);
+
+ return STRLEN (src);
+ }
+
+ /* Get full information about the string. This means we get
+ information for all passes in a special data structure. */
+ get_string (src, forw, backw);
+
+ /* Now we have all the information. In at most the given number of
+ passes we can finally decide about the order. */
+ written = 0;
+ for (pass = 0; pass < collate_nrules; ++pass)
+ {
+ int forward = (collate_rules[pass] & sort_forward) != 0;
+ const weight_t *run = forward ? forw : backw;
+ int idx = forward ? 0 : run->data[pass].number - 1;
+
+ do
+ {
+ int ignore = 0;
+ u32_t w;
+
+ /* Here we have to check for IGNORE entries. If these are
+ found we count them and go on witht he next value. */
+ while ((w = run->data[pass].value[idx]) == IGNORE_CHAR)
+ {
+ ++ignore;
+ if ((forward && ++idx >= run->data[pass].number)
+ || (!forward && --idx < 0))
+ {
+ weight_t *nextp = forward ? run->next : run->prev;
+ if (nextp == NULL)
+ {
+ w = 0;
+ break;
+ }
+ run = nextp;
+ idx = forward ? 0 : run->data[pass].number - 1;
+ }
+ }
+
+ /* Now we have information of the number of ignored weights
+ and the value of the next weight. We have to add 2
+ because 0 means EOS and 1 is the intermediate string end. */
+ if ((collate_rules[pass] & sort_position) != 0)
+ written = print_val (ignore + 2, dest, n, written);
+
+ if (w != 0)
+ written = print_val (w, dest, n, written);
+
+ /* We have to increment the index counters. */
+ if ((forward && ++idx >= run->data[pass].number)
+ || (!forward && --idx < 0))
+ if (forward)
+ {
+ run = run->next;
+ idx = 0;
+ }
+ else
+ {
+ run = run->prev;
+ if (run != NULL)
+ idx = run->data[pass].number - 1;
+ }
+ }
+ while (run != NULL);
+
+ /* Write marker for end of word. */
+ if (pass + 1 < collate_nrules)
+ written = print_val (1, dest, n, written);
+ }
- return __stpncpy (dest, src, n) - dest;
+ /* Terminate string. */
+ return print_val (0, dest, n, written);
}
diff --git a/wctype/Makefile b/wctype/Makefile
new file mode 100644
index 0000000000..e0c84c39f1
--- /dev/null
+++ b/wctype/Makefile
@@ -0,0 +1,30 @@
+# Copyright (C) 1996 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C 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.
+
+# The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+# not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+# Cambridge, MA 02139, USA.
+
+#
+# Sub-makefile for wctype portion of the library.
+#
+subdir := wctype
+
+headers := wctype.h
+distribute := cname-lookup.h
+routines := wcfuncs wctype iswctype wctrans towctrans
+
+tests := test_wctype
+
+include ../Rules
diff --git a/wctype/cname-lookup.h b/wctype/cname-lookup.h
new file mode 100644
index 0000000000..bef38a12d3
--- /dev/null
+++ b/wctype/cname-lookup.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "localeinfo.h"
+
+/* Some words on the runtime of this functions. Although there is a
+ loop in the function the runtime is asymptotically quasi constant.
+ The reason is that even for the largest character sets HASH_LAYERS
+ will not grow beyond 15 (a guess!). */
+static __inline size_t
+cname_lookup (wint_t wc)
+{
+ extern unsigned int *__ctype_names;
+ unsigned int hash_size, hash_layers;
+ size_t result, cnt;
+
+ hash_size = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_HASH_SIZE);
+ hash_layers = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_HASH_LAYERS);
+
+ result = wc % hash_size;
+ for (cnt = 0; cnt < hash_layers; ++cnt)
+ {
+ if (__ctype_names[result] == wc)
+ break;
+ result += hash_size;
+ }
+
+ return cnt < hash_layers ? result : ~((size_t) 0);
+}
diff --git a/wctype/iswctype.c b/wctype/iswctype.c
new file mode 100644
index 0000000000..041548b2dc
--- /dev/null
+++ b/wctype/iswctype.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <ctype.h>
+#include <wctype.h>
+
+#include "cname-lookup.h"
+
+
+extern unsigned int *__ctype32_b;
+
+
+int
+iswctype (wint_t wc, wctype_t desc)
+{
+ size_t idx;
+
+ idx = cname_lookup (wc);
+ if (idx == ~((size_t) 0))
+ return 0;
+
+ return __ctype32_b[idx] & desc;
+}
diff --git a/wctype/test_wctype.c b/wctype/test_wctype.c
new file mode 100644
index 0000000000..bf3de172df
--- /dev/null
+++ b/wctype/test_wctype.c
@@ -0,0 +1,75 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wctype.h>
+
+int
+main (int argc, char *argv[])
+{
+ int result = 0;
+ wctype_t bit_alnum = wctype ("alnum");
+ wctype_t bit_alpha = wctype ("alpha");
+ wctype_t bit_cntrl = wctype ("cntrl");
+ wctype_t bit_digit = wctype ("digit");
+ wctype_t bit_graph = wctype ("graph");
+ wctype_t bit_lower = wctype ("lower");
+ wctype_t bit_print = wctype ("print");
+ wctype_t bit_punct = wctype ("punct");
+ wctype_t bit_space = wctype ("space");
+ wctype_t bit_upper = wctype ("upper");
+ wctype_t bit_xdigit = wctype ("xdigit");
+ int ch;
+
+ if (wctype ("does not exist") != 0)
+ {
+ puts ("wctype return value != 0 for non existing property");
+ result = 1;
+ }
+
+ for (ch = 0; ch < 256; ++ch)
+ {
+#define TEST(test) \
+ do \
+ if (is##test (ch) != iswctype ((wchar_t) ch, bit_##test)) \
+ { \
+ printf ("class `%s' test for character \\%o failed\n", \
+ #test, ch); \
+ result = 1; \
+ } \
+ while (0)
+
+ TEST (alnum);
+ TEST (alpha);
+ TEST (cntrl);
+ TEST (digit);
+ TEST (graph);
+ TEST (lower);
+ TEST (print);
+ TEST (punct);
+ TEST (space);
+ TEST (upper);
+ TEST (xdigit);
+ }
+
+ if (result == 0)
+ puts ("All test successful!");
+ exit (result);
+}
diff --git a/wctype/towctrans.c b/wctype/towctrans.c
new file mode 100644
index 0000000000..fd15599a6e
--- /dev/null
+++ b/wctype/towctrans.c
@@ -0,0 +1,36 @@
+/* towctrans - map wide character using given mapping.
+Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <wctype.h>
+
+/* Define the lookup function. */
+#include "cname-lookup.h"
+
+wint_t
+towctrans (wint_t wc, wctrans_t desc)
+{
+ size_t idx;
+
+ idx = cname_lookup (wc);
+ if (idx == ~((size_t) 0))
+ /* Character is not known. Default action is to simply return it. */
+ return wc;
+
+ return (wint_t) desc[idx];
+}
diff --git a/wctype/wcfuncs.c b/wctype/wcfuncs.c
new file mode 100644
index 0000000000..b5ac890609
--- /dev/null
+++ b/wctype/wcfuncs.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#define __NO_WCTYPE
+#include <wctype.h>
+#include <ctype.h> /* For __ctype_tolower and __ctype_toupper. */
+
+/* Provide real-function versions of all the wctype macros. */
+
+#define func(name, type) \
+ int name (wc) wint_t wc; { return iswctype (wc, type); }
+
+func (iswalnum, _ISalnum)
+func (iswalpha, _ISalpha)
+func (iswcntrl, _IScntrl)
+func (iswdigit, _ISdigit)
+func (iswlower, _ISlower)
+func (iswgraph, _ISgraph)
+func (iswprint, _ISprint)
+func (iswpunct, _ISpunct)
+func (iswspace, _ISspace)
+func (iswupper, _ISupper)
+func (iswxdigit, _ISxdigit)
+
+wint_t
+towlower (wc)
+ wint_t wc;
+{
+ return towctrans (wc, __ctype_tolower);
+}
+
+wint_t
+towupper (wc)
+ wint_t wc;
+{
+ return towctrans (wc, __ctype_toupper);
+}
diff --git a/wctype/wctrans.c b/wctype/wctrans.c
new file mode 100644
index 0000000000..afe47a915d
--- /dev/null
+++ b/wctype/wctrans.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <ctype.h>
+#include <string.h>
+#include <wctype.h>
+#include "localeinfo.h"
+
+wctrans_t
+wctrans (const char *property)
+{
+ const char *names;
+ size_t cnt;
+ unsigned int **result;
+
+ names = _NL_CURRENT (LC_CTYPE, _NL_CTYPE_MAP_NAMES);
+ cnt = 0;
+ while (names[0] != '\0')
+ {
+ if (strcmp (property, names) == 0)
+ break;
+
+ names = strchr (names, '\0') + 1;
+ ++cnt;
+ }
+
+ if (names[0] == '\0')
+ return 0;
+
+ if (cnt == 0)
+ return (wctrans_t) __ctype_toupper;
+ else if (cnt == 1)
+ return (wctrans_t) __ctype_tolower;
+
+ /* We have to search the table. */
+ result = (unsigned int **) &_NL_CURRENT (LC_CTYPE, _NL_CTYPE_WIDTH);
+
+#if __BYTE_ORDER == _BIG_ENDIAN
+ return (wctrans_t) result[1 + 2 * cnt];
+#else
+ return (wctrans_t) result[1 + 2 * cnt + 1];
+#endif
+}
diff --git a/wctype/wctype.c b/wctype/wctype.c
new file mode 100644
index 0000000000..36db3b95a4
--- /dev/null
+++ b/wctype/wctype.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <endian.h>
+#include <string.h>
+#include <wctype.h>
+#include "localeinfo.h"
+
+wctype_t
+wctype (const char *property)
+{
+ const char *names;
+ wctype_t result;
+
+ names = _NL_CURRENT (LC_CTYPE, _NL_CTYPE_CLASS_NAMES);
+ for (result = 1; result != 0; result <<= 1)
+ {
+ if (strcmp (property, names) == 0)
+ break;
+
+ names = strchr (names, '\0') + 1;
+ if (names[0] == '\0')
+ return 0;
+ }
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ return result;
+#else
+# define SWAPU32(w) \
+ (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24))
+
+# define SWAPU16(w) \
+ (((w) >> 8) | ((w) << 8))
+
+ if (sizeof (wctype_t) == 4)
+ return SWAPU32 (result);
+ else
+ return SWAPU16 (result);
+#endif
+}
diff --git a/wctype/wctype.h b/wctype/wctype.h
new file mode 100644
index 0000000000..7e90e2bad5
--- /dev/null
+++ b/wctype/wctype.h
@@ -0,0 +1,215 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/*
+ * ISO/IEC 9899:1990/Amendment 1:1995 7.15:
+ * Wide-character classification and mapping utilities <wctype.h>
+ */
+
+#ifndef _WCTYPE_H
+
+#define _WCTYPE_H 1
+#include <features.h>
+
+
+__BEGIN_DECLS
+
+/* FIXME: should this go into <stddef.h>??? */
+#if 0
+#define __need_wint_t
+#include <stddef.h>
+#else
+/* Integral type unchanged by default argument promotions that can
+ hold any value corresponding to members of the extended character
+ set, as well as at least one value that does not correspond to any
+ member of the extended character set. */
+typedef unsigned int wint_t;
+#endif
+
+/* Scalar type that can hold values which represent locale-specific
+ character mappings. */
+typedef const unsigned int *wctrans_t;
+
+/* Scalar type that can hold values which represent locale-specific
+ character classifications. */
+#if 0
+typedef unsigned long int wctype_t;
+#else
+/* For compatibility reasons we have to use shorts for now. */
+typedef unsigned short int wctype_t;
+#endif
+
+
+/* Constant expression of type `wint_t' whose value does not correspond
+ to any member of the extended character set. */
+#ifndef WEOF
+#define WEOF (0xffffffffu)
+#endif
+
+#ifndef _ISbit
+/* These are all the characteristics of characters.
+ If there get to be more than 16 distinct characteristics,
+ many things must be changed that use `unsigned short int's.
+
+ The characteristics are stored always in network byte order (big
+ endian). We define the bit value interpretations here dependent on the
+ machine's byte order. */
+
+#include <endian.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define _ISbit(bit) (1 << bit)
+#else /* __BYTE_ORDER == __LITTLE_ENDIAN */
+#define _ISbit(bit) (bit < 8 ? ((1 << bit) << 8) : ((1 << bit) >> 8))
+#endif
+
+enum
+{
+ _ISupper = _ISbit (0), /* UPPERCASE. */
+ _ISlower = _ISbit (1), /* lowercase. */
+ _ISalpha = _ISbit (2), /* Alphabetic. */
+ _ISdigit = _ISbit (3), /* Numeric. */
+ _ISxdigit = _ISbit (4), /* Hexadecimal numeric. */
+ _ISspace = _ISbit (5), /* Whitespace. */
+ _ISprint = _ISbit (6), /* Printing. */
+ _ISgraph = _ISbit (7), /* Graphical. */
+ _ISblank = _ISbit (8), /* Blank (usually SPC and TAB). */
+ _IScntrl = _ISbit (9), /* Control character. */
+ _ISpunct = _ISbit (10), /* Punctuation. */
+ _ISalnum = _ISbit (11) /* Alphanumeric. */
+};
+#endif /* Not _ISbit */
+
+
+/*
+ * Wide-character classification functions: 7.15.2.1.
+ */
+
+/* Test for any wide character for which `iswalpha' or `iswdigit' is
+ true. */
+int iswalnum __P ((wint_t __wc));
+
+/* Test for any wide character for which `iswupper' or 'iswlower' is
+ true, or any wide character that is one of a locale-specific set of
+ wide-characters for which none of `iswcntrl', `iswdigit',
+ `iswpunct', or `iswspace' is true. */
+int iswalpha __P ((wint_t __wc));
+
+/* Test for any control wide character. */
+int iswcntrl __P ((wint_t __wc));
+
+/* Test for any wide character that corresponds to a decimal-digit
+ character. */
+int iswdigit __P ((wint_t __wc));
+
+/* Test for any wide character for which `iswprint' is true and
+ `iswspace' is false. */
+int iswgraph __P ((wint_t __wc));
+
+/* Test for any wide character that corresponds to a lowercase letter
+ or is one of a locale-specific set of wide characters for which
+ none of `iswcntrl', `iswdigit', `iswpunct', or `iswspace' is true. */
+int iswlower __P ((wint_t __wc));
+
+/* Test for any printing wide character. */
+int iswprint __P ((wint_t __wc));
+
+/* Test for any printing wide character that is one of a
+ locale-specific et of wide characters for which neither `iswspace'
+ nor `iswalnum' is true. */
+int iswpunct __P ((wint_t __wc));
+
+/* Test for any wide character that corresponds to a locale-specific
+ set of wide characters for which none of `iswalnum', `iswgraph', or
+ `iswpunct' is true. */
+int iswspace __P ((wint_t __wc));
+
+/* Test for any wide character that corresponds to an uppercase letter
+ or is one of a locale-specific set of wide character for which none
+ of `iswcntrl', `iswdigit', `iswpunct', or `iswspace' is true. */
+int iswupper __P ((wint_t __wc));
+
+/* Test for any wide character that corresponds to a hexadecimal-digit
+ character equivalent to that performed be the functions described
+ in the previous subclause. */
+int iswxdigit __P ((wint_t __wc));
+
+/*
+ * Extensible wide-character classification functions: 7.15.2.2.
+ */
+
+/* Construct value that describes a class of wide characters identified
+ by the string argument PROPERTY. */
+wctype_t wctype __P ((__const char *__property));
+
+/* Determine whether the wide-character WC has the property described by
+ DESC. */
+int iswctype __P ((wint_t __wc, wctype_t __desc));
+
+
+/*
+ * Wide-character case-mapping functions: 7.15.3.1.
+ */
+
+/* Converts an uppercase letter to the corresponding lowercase letter. */
+wint_t towlower __P ((wint_t __wc));
+
+/* Converts an lowercase letter to the corresponding uppercase letter. */
+wint_t towupper __P ((wint_t __wc));
+
+/*
+ * Extensible wide-character mapping functions: 7.15.3.2.
+ */
+
+/* Construct value that describes a mapping between wide characters
+ identified by the string argument PROPERTY. */
+wctrans_t wctrans __P ((__const char *__property));
+
+/* Map the wide character WC using the mapping described by DESC. */
+wint_t towctrans __P ((wint_t __wc, wctrans_t __desc));
+
+
+
+#ifndef __NO_WCTYPE
+#define iswalnum(wc) iswctype ((wc), _ISalnum)
+#define iswalpha(wc) iswctype ((wc), _ISalpha)
+#define iswcntrl(wc) iswctype ((wc), _IScntrl)
+#define iswdigit(wc) iswctype ((wc), _ISdigit)
+#define iswlower(wc) iswctype ((wc), _ISlower)
+#define iswgraph(wc) iswctype ((wc), _ISgraph)
+#define iswprint(wc) iswctype ((wc), _ISprint)
+#define iswpunct(wc) iswctype ((wc), _ISpunct)
+#define iswspace(wc) iswctype ((wc), _ISspace)
+#define iswupper(wc) iswctype ((wc), _ISupper)
+#define iswxdigit(wc) iswctype ((wc), _ISxdigit)
+
+#ifdef __USE_GNU
+#define iswblank(wc) iswctype ((wc), _ISblank)
+#endif
+
+/* Pointer to conversion tables. */
+extern __const int *__ctype_tolower; /* Case conversions. */
+extern __const int *__ctype_toupper; /* Case conversions. */
+
+#define towlower(wc) towctrans (wc, __ctype_tolower)
+#define towupper(wc) towctrans (wc, __ctype_toupper)
+
+#endif /* Not __NO_WCTYPE. */
+
+__END_DECLS
+
+#endif /* wctype.h */