Thu Mar 28 03:25:10 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
authorRoland McGrath <roland@gnu.org>
Thu, 28 Mar 1996 08:30:38 +0000 (08:30 +0000)
committerRoland McGrath <roland@gnu.org>
Thu, 28 Mar 1996 08:30:38 +0000 (08:30 +0000)
* 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.

78 files changed:
ChangeLog
Makeconfig
Makefile
ctype/ctype-info.c
ctype/ctype.h
intl/Makefile
libio/genops.c
locale/C-ctype.c
locale/C-messages.c
locale/C-monetary.c
locale/C-numeric.c
locale/C-time.c
locale/Makefile
locale/categories.def
locale/charmap.c [deleted file]
locale/collate.c [deleted file]
locale/config.h [deleted file]
locale/hash.h [deleted file]
locale/keyword.gperf [deleted file]
locale/keyword.h [deleted file]
locale/langinfo.h
locale/lc-collate.c
locale/lc-ctype.c
locale/loadlocale.c
locale/locale-ctype.c [deleted file]
locale/localedef.c [deleted file]
locale/localedef.h [deleted file]
locale/localeinfo.h
locale/locfile-hash.c [deleted file]
locale/locfile-lex.c [deleted file]
locale/locfile-parse.c [deleted file]
locale/messages.c [deleted file]
locale/monetary.c [deleted file]
locale/numeric.c [deleted file]
locale/programs/charmap-kw.gperf [new file with mode: 0644]
locale/programs/charmap-kw.h [new file with mode: 0644]
locale/programs/charmap.c [new file with mode: 0644]
locale/programs/charset.c [new file with mode: 0644]
locale/programs/charset.h [new file with mode: 0644]
locale/programs/config.h [new file with mode: 0644]
locale/programs/ctypedump.c [moved from locale/ctypedump.c with 93% similarity]
locale/programs/ld-collate.c [new file with mode: 0644]
locale/programs/ld-ctype.c [new file with mode: 0644]
locale/programs/ld-messages.c [new file with mode: 0644]
locale/programs/ld-monetary.c [new file with mode: 0644]
locale/programs/ld-numeric.c [new file with mode: 0644]
locale/programs/ld-time.c [new file with mode: 0644]
locale/programs/linereader.c [new file with mode: 0644]
locale/programs/linereader.h [new file with mode: 0644]
locale/programs/locale.c [moved from locale/locale.c with 94% similarity]
locale/programs/localedef.c [new file with mode: 0644]
locale/programs/locales.h [new file with mode: 0644]
locale/programs/locfile-kw.gperf [new file with mode: 0644]
locale/programs/locfile-kw.h [new file with mode: 0644]
locale/programs/locfile-token.h [new file with mode: 0644]
locale/programs/locfile.c [new file with mode: 0644]
locale/programs/locfile.h [new file with mode: 0644]
locale/programs/stringtrans.c [new file with mode: 0644]
locale/programs/stringtrans.h [new file with mode: 0644]
locale/setlocale.c
locale/token.h [deleted file]
locale/weight.h [new file with mode: 0644]
misc/error.c
misc/error.h
posix/unistd.h
stdio-common/printf_fp.c
stdio-common/tfformat.c
string/strcoll.c
string/strxfrm.c
wctype/Makefile [new file with mode: 0644]
wctype/cname-lookup.h [new file with mode: 0644]
wctype/iswctype.c [new file with mode: 0644]
wctype/test_wctype.c [new file with mode: 0644]
wctype/towctrans.c [new file with mode: 0644]
wctype/wcfuncs.c [new file with mode: 0644]
wctype/wctrans.c [new file with mode: 0644]
wctype/wctype.c [new file with mode: 0644]
wctype/wctype.h [new file with mode: 0644]

index c5f49f2..aedd2d0 100644 (file)
--- 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
index 46da933..fe4db0b 100644 (file)
@@ -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
 
 
index a52d845..30e0204 100644 (file)
--- 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
index a1054b2..3a47b34 100644 (file)
@@ -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);
index 025373c..af2d6a9 100644 (file)
@@ -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.  */
index 8b1c056..159d1b1 100644 (file)
@@ -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 $<' $@
index 7eb2d43..23a6fde 100644 (file)
@@ -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 */
index 7a5c0c7..8bf6bee 100644 (file)
@@ -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 }
   }
 };
index f59cde3..6f89919 100644 (file)
@@ -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: "" }
   }
 };
index bf2cede..1859422 100644 (file)
@@ -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" }
   }
 };
index 248e2eb..5d68a89 100644 (file)
@@ -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" }
   }
 };
index 15bf15a..6fb5e3e 100644 (file)
@@ -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 }
   }
 };
index b180b6e..675052a 100644 (file)
@@ -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
index be3c6bc..f65140f 100644 (file)
@@ -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 (file)
index ad1075e..0000000
+++ /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 (file)
index f06964e..0000000
+++ /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 (file)
index 65dfb33..0000000
+++ /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 (file)
index 5f60a44..0000000
+++ /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 (file)
index 20941bc..0000000
+++ /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 (file)
index 1dc442a..0000000
+++ /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;
-}
index 245dcf8..af081e7 100644 (file)
@@ -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;
index 8684f23..911477b 100644 (file)
@@ -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));
+}
index 2384d17..4b7dcc5 100644 (file)
@@ -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));
 }
index 7e29c97..68f9c7a 100644 (file)
@@ -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 (file)
index e7a1e97..0000000
+++ /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 (file)
index 56ec1a2..0000000
+++ /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 (file)
index 5958a9c..0000000
+++ /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 */
index 4199bf7..a3049a5 100644 (file)
@@ -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 (file)
index d977822..0000000
+++ /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 (file)
index 20e4f0f..0000000
+++ /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 (file)
index daf56bc..0000000
+++ /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 (file)
index 842e5ef..0000000
+++ /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 (file)
index 2683eb2..0000000
+++ /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 (file)
index 93f4bc4..0000000
+++ /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 (file)
index 0000000..8e00103
--- /dev/null
@@ -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 (file)
index 0000000..93326d0
--- /dev/null
@@ -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 (file)
index 0000000..2b71821
--- /dev/null
@@ -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 (file)
index 0000000..2e2f63b
--- /dev/null
@@ -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 (file)
index 0000000..222d468
--- /dev/null
@@ -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 (file)
index 0000000..6405465
--- /dev/null
@@ -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
similarity index 93%
rename from locale/ctypedump.c
rename to locale/programs/ctypedump.c
index e00f3e0..2a67534 100644 (file)
@@ -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 (file)
index 0000000..0f3bcbc
--- /dev/null
@@ -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 (file)
index 0000000..c1cc8e5
--- /dev/null
@@ -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 (file)
index 0000000..ebd5054
--- /dev/null
@@ -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 (file)
index 0000000..18e2786
--- /dev/null
@@ -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 (file)
index 0000000..0b5fe2a
--- /dev/null
@@ -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 (file)
index 0000000..2587fac
--- /dev/null
@@ -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 (file)
index 0000000..e4a1305
--- /dev/null
@@ -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 (file)
index 0000000..b78697e
--- /dev/null
@@ -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 */
similarity index 94%
rename from locale/locale.c
rename to locale/programs/locale.c
index fd2e392..4e4ff83 100644 (file)
@@ -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 (file)
index 0000000..a98bac4
--- /dev/null
@@ -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 (file)
index 0000000..3c7676b
--- /dev/null
@@ -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 (file)
index 0000000..85e031c
--- /dev/null
@@ -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 (file)
index 0000000..c892669
--- /dev/null
@@ -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 (file)
index 0000000..1c3cfdc
--- /dev/null
@@ -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 (file)
index 0000000..cb98a5d
--- /dev/null
@@ -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 (file)
index 0000000..e337e96
--- /dev/null
@@ -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 (file)
index 0000000..bff5aa4
--- /dev/null
@@ -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 (file)
index 0000000..3576ce4
--- /dev/null
@@ -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 */
index 509bb4f..70ec6eb 100644 (file)
@@ -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 (file)
index 1227920..0000000
+++ /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 (file)
index 0000000..5a9bcd7
--- /dev/null
@@ -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)
index c48c0f3..b12041c 100644 (file)
@@ -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);
+}
+\f
+/* 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);
index 749dce4..95ceb1a 100644 (file)
@@ -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_ */
index 2ac0b2f..0fc3d7b 100644 (file)
@@ -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:
 
index 5cf60f1..009bdee 100644 (file)
@@ -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);
index 02230f1..60785d8 100644 (file)
@@ -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);
index 9dee89f..13e9f0d 100644 (file)
@@ -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;
 }
index e40ae1c..7dce9c1 100644 (file)
@@ -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 (file)
index 0000000..e0c84c3
--- /dev/null
@@ -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 (file)
index 0000000..bef38a1
--- /dev/null
@@ -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 (file)
index 0000000..041548b
--- /dev/null
@@ -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 (file)
index 0000000..bf3de17
--- /dev/null
@@ -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 (file)
index 0000000..fd15599
--- /dev/null
@@ -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 (file)
index 0000000..b5ac890
--- /dev/null
@@ -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 (file)
index 0000000..afe47a9
--- /dev/null
@@ -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 (file)
index 0000000..36db3b9
--- /dev/null
@@ -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 (file)
index 0000000..7e90e2b
--- /dev/null
@@ -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  */