Jelajahi Sumber

Added several tests for locale support (8 bit and multibyte UTF-8)

Basically all tests have been taken from glibc. For testing multibyte encoding
EUC_JP parts have been commented out and added new section for UTF-8
that is the only multibyte  codeset currently supported on uCLibc.

Some tests are still failing due to unsupported/missing features, other have been
fixed.

Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono@st.com>
Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
Carmelo Amoroso 16 tahun lalu
induk
melakukan
a691312d87

+ 31 - 0
test/locale/Makefile

@@ -0,0 +1,31 @@
+# uClibc locale tests
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#	 tst_mbtowc tst_strcoll tst_strfmon tst_strxfrm    \
+
+TESTS := bug-iconv-trans bug-usesetlocale collate-test dump-ctype \
+	 gen-unicode-ctype show-ucs-data tst-ctype \
+	 tst-digits tst-fmon tst-langinfo tst-leaks tst-mbswcs1 \
+	 tst-mbswcs2 tst-mbswcs3 tst-mbswcs4 tst-mbswcs5 tst-mbswcs6 \
+	 tst_nl_langinfo tst-numeric tst-rpmatch tst-setlocale \
+	 tst-sscanf tst-strfmon1 tst-trans tst-wctype tst-xlocale1 \
+	 tst-xlocale2 xfrm-test
+
+
+# NOTE: For now disabled some tests that are known not build
+TESTS_DISABLED := tst-ctype tst-fmon tst-leaks tst-rpmatch tst-strfmon1
+
+ifneq ($(UCLIBC_HAS_XLOCALE),y)
+TESTS_DISABLED += bug-usesetlocale tst-xlocale1 tst-xlocale2 xfrm-test tst-C-locale
+endif
+
+include ../Test.mak
+
+DODIFF_rint     := 1
+
+EXTRA_CFLAGS    := -D__USE_GNU -fno-builtin
+
+OPTS_dump-ctype = C
+OPTS_tst-ctype = < tst-ctype-de_DE.ISO-8859-1.in
+OPTS_tst-langinfo = < tst-langinfo.input
+
+EXTRA_CLEAN := C

+ 68 - 0
test/locale/bug-iconv-trans.c

@@ -0,0 +1,68 @@
+#include <iconv.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+main (void)
+{
+  iconv_t cd;
+  const char str[] = "ÄäÖöÜüß";
+  const char expected[] = "AEaeOEoeUEuess";
+  char *inptr = (char *) str;
+  size_t inlen = strlen (str) + 1;
+  char outbuf[500];
+  char *outptr = outbuf;
+  size_t outlen = sizeof (outbuf);
+  int result = 0;
+  size_t n;
+
+  if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL)
+    {
+      puts ("setlocale failed");
+      return 1;
+    }
+
+  cd = iconv_open ("ANSI_X3.4-1968//TRANSLIT", "ISO-8859-1");
+  if (cd == (iconv_t) -1)
+    {
+      puts ("iconv_open failed");
+      return 1;
+    }
+
+  n = iconv (cd, &inptr, &inlen, &outptr, &outlen);
+  if (n != 7)
+    {
+      if (n == (size_t) -1)
+	printf ("iconv() returned error: %m\n");
+      else
+	printf ("iconv() returned %Zd, expected 7\n", n);
+      result = 1;
+    }
+  if (inlen != 0)
+    {
+      puts ("not all input consumed");
+      result = 1;
+    }
+  else if (inptr - str != strlen (str) + 1)
+    {
+      printf ("inptr wrong, advanced by %td\n", inptr - str);
+      result = 1;
+    }
+  if (memcmp (outbuf, expected, sizeof (expected)) != 0)
+    {
+      printf ("result wrong: \"%.*s\", expected: \"%s\"\n",
+	      (int) (sizeof (outbuf) - outlen), outbuf, expected);
+      result = 1;
+    }
+  else if (outlen != sizeof (outbuf) - sizeof (expected))
+    {
+      printf ("outlen wrong: %Zd, expected %Zd\n", outlen,
+	      sizeof (outbuf) - 15);
+      result = 1;
+    }
+  else
+    printf ("output is \"%s\" which is OK\n", outbuf);
+
+  return result;
+}

+ 38 - 0
test/locale/bug-usesetlocale.c

@@ -0,0 +1,38 @@
+/* Test case for setlocale vs uselocale (LC_GLOBAL_LOCALE) bug.  */
+
+#define _GNU_SOURCE 1
+#include <locale.h>
+#include <stdio.h>
+#include <ctype.h>
+
+static int
+do_test (void)
+{
+  __locale_t loc_new, loc_old;
+
+  int first = !!isalpha(0xE4);
+
+  setlocale (LC_ALL, "de_DE");
+
+  int global_de = !!isalpha(0xE4);
+
+  loc_new = newlocale (1 << LC_ALL, "C", 0);
+  loc_old = uselocale (loc_new);
+
+  int used_c = !!isalpha(0xE4);
+
+  uselocale (loc_old);
+
+  int used_global = !!isalpha(0xE4);
+
+  printf ("started %d, after setlocale %d\n", first, global_de);
+  printf ("after uselocale %d, after LC_GLOBAL_LOCALE %d\n",
+	  used_c, used_global);
+
+  freelocale (loc_new);
+  return !(used_c == first && used_global == global_de);
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "test-skeleton.c"

+ 133 - 0
test/locale/collate-test.c

@@ -0,0 +1,133 @@
+/* Test collation function using real data.
+   Copyright (C) 1997, 1999, 2000, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <ctype.h>
+#include <error.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+struct lines
+{
+  char *key;
+  char *line;
+};
+
+static int xstrcoll (const void *, const void *);
+
+int
+main (int argc, char *argv[])
+{
+  int result = 0;
+  size_t nstrings, nstrings_max;
+  struct lines *strings;
+  char *line = NULL;
+  size_t len = 0;
+  size_t n;
+
+  if (argc < 2)
+    error (1, 0, "usage: %s <random seed>", argv[0]);
+
+  setlocale (LC_ALL, "");
+
+  nstrings_max = 100;
+  nstrings = 0;
+  strings = (struct lines *) malloc (nstrings_max * sizeof (struct lines));
+  if (strings == NULL)
+    {
+      perror (argv[0]);
+      exit (1);
+    }
+
+  while (1)
+    {
+      int l;
+      if (getline (&line, &len, stdin) < 0)
+	break;
+
+      if (nstrings == nstrings_max)
+	{
+	  strings = (struct lines *) realloc (strings,
+					      (nstrings_max *= 2)
+					       * sizeof (*strings));
+	  if (strings == NULL)
+	    {
+	      perror (argv[0]);
+	      exit (1);
+	    }
+	}
+      strings[nstrings].line = strdup (line);
+      l = strcspn (line, ":(;");
+      while (l > 0 && isspace (line[l - 1]))
+	--l;
+      strings[nstrings].key = strndup (line, l);
+      ++nstrings;
+    }
+  free (line);
+
+  /* First shuffle.  */
+  srandom (atoi (argv[1]));
+  for (n = 0; n < 10 * nstrings; ++n)
+    {
+      int r1, r2, r;
+      size_t idx1 = random () % nstrings;
+      size_t idx2 = random () % nstrings;
+      struct lines tmp = strings[idx1];
+      strings[idx1] = strings[idx2];
+      strings[idx2] = tmp;
+
+      /* While we are at it a first little test.  */
+      r1 = strcoll (strings[idx1].key, strings[idx2].key);
+      r2 = strcoll (strings[idx2].key, strings[idx1].key);
+      r = r1 * r2;
+
+      if (r > 0 || (r == 0 && r1 != 0) || (r == 0 && r2 != 0))
+	printf ("`%s' and `%s' collate wrong: %d vs. %d\n",
+		strings[idx1].key, strings[idx2].key, r1, r2);
+    }
+
+  /* Now sort.  */
+  qsort (strings, nstrings, sizeof (struct lines), xstrcoll);
+
+  /* Print the result.  */
+  for (n = 0; n < nstrings; ++n)
+    {
+      fputs (strings[n].line, stdout);
+      free (strings[n].line);
+      free (strings[n].key);
+    }
+  free (strings);
+
+  return result;
+}
+
+
+static int
+xstrcoll (ptr1, ptr2)
+     const void *ptr1;
+     const void *ptr2;
+{
+  const struct lines *l1 = (const struct lines *) ptr1;
+  const struct lines *l2 = (const struct lines *) ptr2;
+
+  return strcoll (l1->key, l2->key);
+}

+ 164 - 0
test/locale/dump-ctype.c

@@ -0,0 +1,164 @@
+/* Dump the character classes and character maps of a locale to a bunch
+   of individual files which can be processed with diff, sed etc.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Bruno Haible <haible@clisp.cons.org>, 2000.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Usage example:
+     $ dump-ctype de_DE.UTF-8
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <wctype.h>
+#include <locale.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+static const char *program_name = "dump-ctype";
+static const char *locale;
+
+static const char *class_names[] =
+  {
+    "alnum", "alpha", "blank", "cntrl", "digit", "graph", "lower",
+    "print", "punct", "space", "upper", "xdigit"
+  };
+
+static const char *map_names[] =
+  {
+    "tolower", "toupper", "totitle"
+  };
+
+static void dump_class (const char *class_name)
+{
+  wctype_t class;
+  FILE *f;
+  unsigned int ch;
+
+  class = wctype (class_name);
+  if (class == (wctype_t) 0)
+    {
+      fprintf (stderr, "%s %s: noexistent class %s\n", program_name,
+	       locale, class_name);
+      return;
+    }
+
+  f = fopen (class_name, "w");
+  if (f == NULL)
+    {
+      fprintf (stderr, "%s %s: cannot open file %s/%s\n", program_name,
+	       locale, locale, class_name);
+      exit (1);
+    }
+
+  for (ch = 0; ch < 0x10000; ch++)
+    if (iswctype (ch, class))
+      fprintf (f, "0x%04X\n", ch);
+
+  if (ferror (f) || fclose (f))
+    {
+      fprintf (stderr, "%s %s: I/O error on file %s/%s\n", program_name,
+	       locale, locale, class_name);
+      exit (1);
+    }
+}
+
+static void dump_map (const char *map_name)
+{
+  wctrans_t map;
+  FILE *f;
+  unsigned int ch;
+
+  map = wctrans (map_name);
+  if (map == (wctrans_t) 0)
+    {
+      fprintf (stderr, "%s %s: noexistent map %s\n", program_name,
+	       locale, map_name);
+      return;
+    }
+
+  f = fopen (map_name, "w");
+  if (f == NULL)
+    {
+      fprintf (stderr, "%s %s: cannot open file %s/%s\n", program_name,
+	       locale, locale, map_name);
+      exit (1);
+    }
+
+  for (ch = 0; ch < 0x10000; ch++)
+    if (towctrans (ch, map) != ch)
+      fprintf (f, "0x%04X\t0x%04X\n", ch, towctrans (ch, map));
+
+  if (ferror (f) || fclose (f))
+    {
+      fprintf (stderr, "%s %s: I/O error on file %s/%s\n", program_name,
+	       locale, locale, map_name);
+      exit (1);
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  size_t i;
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "Usage: dump-ctype locale\n");
+      exit (1);
+    }
+  locale = argv[1];
+
+  if (setlocale (LC_ALL, locale) == NULL)
+    {
+      fprintf (stderr, "%s: setlocale cannot switch to locale %s\n",
+	       program_name, locale);
+      exit (1);
+    }
+
+  if (mkdir (locale, 0777) < 0)
+    {
+      char buf[100];
+      int save_errno = errno;
+
+      sprintf (buf, "%s: cannot create directory %s", program_name, locale);
+      errno = save_errno;
+      perror (buf);
+      exit (1);
+    }
+
+  if (chdir (locale) < 0)
+    {
+      char buf[100];
+      int save_errno = errno;
+
+      sprintf (buf, "%s: cannot chdir to %s", program_name, locale);
+      errno = save_errno;
+      perror (buf);
+      exit (1);
+    }
+
+  for (i = 0; i < sizeof (class_names) / sizeof (class_names[0]); i++)
+    dump_class (class_names[i]);
+
+  for (i = 0; i < sizeof (map_names) / sizeof (map_names[0]); i++)
+    dump_map (map_names[i]);
+
+  return 0;
+}

+ 785 - 0
test/locale/gen-unicode-ctype.c

@@ -0,0 +1,785 @@
+/* Generate a Unicode conforming LC_CTYPE category from a UnicodeData file.
+   Copyright (C) 2000-2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Bruno Haible <haible@clisp.cons.org>, 2000.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Usage example:
+     $ gen-unicode /usr/local/share/Unidata/UnicodeData.txt 3.1
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <time.h>
+
+/* This structure represents one line in the UnicodeData.txt file.  */
+struct unicode_attribute
+{
+  const char *name;           /* Character name */
+  const char *category;       /* General category */
+  const char *combining;      /* Canonical combining classes */
+  const char *bidi;           /* Bidirectional category */
+  const char *decomposition;  /* Character decomposition mapping */
+  const char *decdigit;       /* Decimal digit value */
+  const char *digit;          /* Digit value */
+  const char *numeric;        /* Numeric value */
+  int mirrored;               /* mirrored */
+  const char *oldname;        /* Old Unicode 1.0 name */
+  const char *comment;        /* Comment */
+  unsigned int upper;         /* Uppercase mapping */
+  unsigned int lower;         /* Lowercase mapping */
+  unsigned int title;         /* Titlecase mapping */
+};
+
+/* Missing fields are represented with "" for strings, and NONE for
+   characters.  */
+#define NONE (~(unsigned int)0)
+
+/* The entire contents of the UnicodeData.txt file.  */
+struct unicode_attribute unicode_attributes [0x110000];
+
+/* Stores in unicode_attributes[i] the values from the given fields.  */
+static void
+fill_attribute (unsigned int i,
+		const char *field1, const char *field2,
+		const char *field3, const char *field4,
+		const char *field5, const char *field6,
+		const char *field7, const char *field8,
+		const char *field9, const char *field10,
+		const char *field11, const char *field12,
+		const char *field13, const char *field14)
+{
+  struct unicode_attribute * uni;
+
+  if (i >= 0x110000)
+    {
+      fprintf (stderr, "index too large\n");
+      exit (1);
+    }
+  if (strcmp (field2, "Cs") == 0)
+    /* Surrogates are UTF-16 artefacts, not real characters. Ignore them.  */
+    return;
+  uni = &unicode_attributes[i];
+  /* Copy the strings.  */
+  uni->name          = strdup (field1);
+  uni->category      = (field2[0] == '\0' ? "" : strdup (field2));
+  uni->combining     = (field3[0] == '\0' ? "" : strdup (field3));
+  uni->bidi          = (field4[0] == '\0' ? "" : strdup (field4));
+  uni->decomposition = (field5[0] == '\0' ? "" : strdup (field5));
+  uni->decdigit      = (field6[0] == '\0' ? "" : strdup (field6));
+  uni->digit         = (field7[0] == '\0' ? "" : strdup (field7));
+  uni->numeric       = (field8[0] == '\0' ? "" : strdup (field8));
+  uni->mirrored      = (field9[0] == 'Y');
+  uni->oldname       = (field10[0] == '\0' ? "" : strdup (field10));
+  uni->comment       = (field11[0] == '\0' ? "" : strdup (field11));
+  uni->upper = (field12[0] =='\0' ? NONE : strtoul (field12, NULL, 16));
+  uni->lower = (field13[0] =='\0' ? NONE : strtoul (field13, NULL, 16));
+  uni->title = (field14[0] =='\0' ? NONE : strtoul (field14, NULL, 16));
+}
+
+/* Maximum length of a field in the UnicodeData.txt file.  */
+#define FIELDLEN 120
+
+/* Reads the next field from STREAM.  The buffer BUFFER has size FIELDLEN.
+   Reads up to (but excluding) DELIM.
+   Returns 1 when a field was successfully read, otherwise 0.  */
+static int
+getfield (FILE *stream, char *buffer, int delim)
+{
+  int count = 0;
+  int c;
+
+  for (; (c = getc (stream)), (c != EOF && c != delim); )
+    {
+      /* The original unicode.org UnicodeData.txt file happens to have
+	 CR/LF line terminators.  Silently convert to LF.  */
+      if (c == '\r')
+	continue;
+
+      /* Put c into the buffer.  */
+      if (++count >= FIELDLEN - 1)
+	{
+	  fprintf (stderr, "field too long\n");
+	  exit (1);
+	}
+      *buffer++ = c;
+    }
+
+  if (c == EOF)
+    return 0;
+
+  *buffer = '\0';
+  return 1;
+}
+
+/* Stores in unicode_attributes[] the entire contents of the UnicodeData.txt
+   file.  */
+static void
+fill_attributes (const char *unicodedata_filename)
+{
+  unsigned int i, j;
+  FILE *stream;
+  char field0[FIELDLEN];
+  char field1[FIELDLEN];
+  char field2[FIELDLEN];
+  char field3[FIELDLEN];
+  char field4[FIELDLEN];
+  char field5[FIELDLEN];
+  char field6[FIELDLEN];
+  char field7[FIELDLEN];
+  char field8[FIELDLEN];
+  char field9[FIELDLEN];
+  char field10[FIELDLEN];
+  char field11[FIELDLEN];
+  char field12[FIELDLEN];
+  char field13[FIELDLEN];
+  char field14[FIELDLEN];
+  int lineno = 0;
+
+  for (i = 0; i < 0x110000; i++)
+    unicode_attributes[i].name = NULL;
+
+  stream = fopen (unicodedata_filename, "r");
+  if (stream == NULL)
+    {
+      fprintf (stderr, "error during fopen of '%s'\n", unicodedata_filename);
+      exit (1);
+    }
+
+  for (;;)
+    {
+      int n;
+
+      lineno++;
+      n = getfield (stream, field0, ';');
+      n += getfield (stream, field1, ';');
+      n += getfield (stream, field2, ';');
+      n += getfield (stream, field3, ';');
+      n += getfield (stream, field4, ';');
+      n += getfield (stream, field5, ';');
+      n += getfield (stream, field6, ';');
+      n += getfield (stream, field7, ';');
+      n += getfield (stream, field8, ';');
+      n += getfield (stream, field9, ';');
+      n += getfield (stream, field10, ';');
+      n += getfield (stream, field11, ';');
+      n += getfield (stream, field12, ';');
+      n += getfield (stream, field13, ';');
+      n += getfield (stream, field14, '\n');
+      if (n == 0)
+	break;
+      if (n != 15)
+	{
+	  fprintf (stderr, "short line in'%s':%d\n",
+		   unicodedata_filename, lineno);
+	  exit (1);
+	}
+      i = strtoul (field0, NULL, 16);
+      if (field1[0] == '<'
+	  && strlen (field1) >= 9
+	  && !strcmp (field1 + strlen(field1) - 8, ", First>"))
+	{
+	  /* Deal with a range. */
+	  lineno++;
+	  n = getfield (stream, field0, ';');
+	  n += getfield (stream, field1, ';');
+	  n += getfield (stream, field2, ';');
+	  n += getfield (stream, field3, ';');
+	  n += getfield (stream, field4, ';');
+	  n += getfield (stream, field5, ';');
+	  n += getfield (stream, field6, ';');
+	  n += getfield (stream, field7, ';');
+	  n += getfield (stream, field8, ';');
+	  n += getfield (stream, field9, ';');
+	  n += getfield (stream, field10, ';');
+	  n += getfield (stream, field11, ';');
+	  n += getfield (stream, field12, ';');
+	  n += getfield (stream, field13, ';');
+	  n += getfield (stream, field14, '\n');
+	  if (n != 15)
+	    {
+	      fprintf (stderr, "missing end range in '%s':%d\n",
+		       unicodedata_filename, lineno);
+	      exit (1);
+	    }
+	  if (!(field1[0] == '<'
+		&& strlen (field1) >= 8
+		&& !strcmp (field1 + strlen (field1) - 7, ", Last>")))
+	    {
+	      fprintf (stderr, "missing end range in '%s':%d\n",
+		       unicodedata_filename, lineno);
+	      exit (1);
+	    }
+	  field1[strlen (field1) - 7] = '\0';
+	  j = strtoul (field0, NULL, 16);
+	  for (; i <= j; i++)
+	    fill_attribute (i, field1+1, field2, field3, field4, field5,
+			       field6, field7, field8, field9, field10,
+			       field11, field12, field13, field14);
+	}
+      else
+	{
+	  /* Single character line */
+	  fill_attribute (i, field1, field2, field3, field4, field5,
+			     field6, field7, field8, field9, field10,
+			     field11, field12, field13, field14);
+	}
+    }
+  if (ferror (stream) || fclose (stream))
+    {
+      fprintf (stderr, "error reading from '%s'\n", unicodedata_filename);
+      exit (1);
+    }
+}
+
+/* Character mappings.  */
+
+static unsigned int
+to_upper (unsigned int ch)
+{
+  if (unicode_attributes[ch].name != NULL
+      && unicode_attributes[ch].upper != NONE)
+    return unicode_attributes[ch].upper;
+  else
+    return ch;
+}
+
+static unsigned int
+to_lower (unsigned int ch)
+{
+  if (unicode_attributes[ch].name != NULL
+      && unicode_attributes[ch].lower != NONE)
+    return unicode_attributes[ch].lower;
+  else
+    return ch;
+}
+
+static unsigned int
+to_title (unsigned int ch)
+{
+  if (unicode_attributes[ch].name != NULL
+      && unicode_attributes[ch].title != NONE)
+    return unicode_attributes[ch].title;
+  else
+    return ch;
+}
+
+/* Character class properties.  */
+
+static bool
+is_upper (unsigned int ch)
+{
+  return (to_lower (ch) != ch);
+}
+
+static bool
+is_lower (unsigned int ch)
+{
+  return (to_upper (ch) != ch)
+	 /* <U00DF> is lowercase, but without simple to_upper mapping.  */
+	 || (ch == 0x00DF);
+}
+
+static bool
+is_alpha (unsigned int ch)
+{
+  return (unicode_attributes[ch].name != NULL
+	  && ((unicode_attributes[ch].category[0] == 'L'
+	       /* Theppitak Karoonboonyanan <thep@links.nectec.or.th> says
+		  <U0E2F>, <U0E46> should belong to is_punct.  */
+	       && (ch != 0x0E2F) && (ch != 0x0E46))
+	      /* Theppitak Karoonboonyanan <thep@links.nectec.or.th> says
+		 <U0E31>, <U0E34>..<U0E3A>, <U0E47>..<U0E4E> are is_alpha.  */
+	      || (ch == 0x0E31)
+	      || (ch >= 0x0E34 && ch <= 0x0E3A)
+	      || (ch >= 0x0E47 && ch <= 0x0E4E)
+	      /* Avoid warning for <U0345>.  */
+	      || (ch == 0x0345)
+	      /* Avoid warnings for <U2160>..<U217F>.  */
+	      || (unicode_attributes[ch].category[0] == 'N'
+		  && unicode_attributes[ch].category[1] == 'l')
+	      /* Avoid warnings for <U24B6>..<U24E9>.  */
+	      || (unicode_attributes[ch].category[0] == 'S'
+		  && unicode_attributes[ch].category[1] == 'o'
+		  && strstr (unicode_attributes[ch].name, " LETTER ")
+		     != NULL)
+	      /* Consider all the non-ASCII digits as alphabetic.
+		 ISO C 99 forbids us to have them in category "digit",
+		 but we want iswalnum to return true on them.  */
+	      || (unicode_attributes[ch].category[0] == 'N'
+		  && unicode_attributes[ch].category[1] == 'd'
+		  && !(ch >= 0x0030 && ch <= 0x0039))));
+}
+
+static bool
+is_digit (unsigned int ch)
+{
+#if 0
+  return (unicode_attributes[ch].name != NULL
+	  && unicode_attributes[ch].category[0] == 'N'
+	  && unicode_attributes[ch].category[1] == 'd');
+  /* Note: U+0BE7..U+0BEF and U+1369..U+1371 are digit systems without
+     a zero.  Must add <0> in front of them by hand.  */
+#else
+  /* SUSV2 gives us some freedom for the "digit" category, but ISO C 99
+     takes it away:
+     7.25.2.1.5:
+        The iswdigit function tests for any wide character that corresponds
+        to a decimal-digit character (as defined in 5.2.1).
+     5.2.1:
+        the 10 decimal digits 0 1 2 3 4 5 6 7 8 9
+   */
+  return (ch >= 0x0030 && ch <= 0x0039);
+#endif
+}
+
+static bool
+is_outdigit (unsigned int ch)
+{
+  return (ch >= 0x0030 && ch <= 0x0039);
+}
+
+static bool
+is_blank (unsigned int ch)
+{
+  return (ch == 0x0009 /* '\t' */
+	  /* Category Zs without mention of "<noBreak>" */
+	  || (unicode_attributes[ch].name != NULL
+	      && unicode_attributes[ch].category[0] == 'Z'
+	      && unicode_attributes[ch].category[1] == 's'
+	      && !strstr (unicode_attributes[ch].decomposition, "<noBreak>")));
+}
+
+static bool
+is_space (unsigned int ch)
+{
+  /* Don't make U+00A0 a space. Non-breaking space means that all programs
+     should treat it like a punctuation character, not like a space. */
+  return (ch == 0x0020 /* ' ' */
+	  || ch == 0x000C /* '\f' */
+	  || ch == 0x000A /* '\n' */
+	  || ch == 0x000D /* '\r' */
+	  || ch == 0x0009 /* '\t' */
+	  || ch == 0x000B /* '\v' */
+	  /* Categories Zl, Zp, and Zs without mention of "<noBreak>" */
+	  || (unicode_attributes[ch].name != NULL
+	      && unicode_attributes[ch].category[0] == 'Z'
+	      && (unicode_attributes[ch].category[1] == 'l'
+		  || unicode_attributes[ch].category[1] == 'p'
+		  || (unicode_attributes[ch].category[1] == 's'
+		      && !strstr (unicode_attributes[ch].decomposition,
+				  "<noBreak>")))));
+}
+
+static bool
+is_cntrl (unsigned int ch)
+{
+  return (unicode_attributes[ch].name != NULL
+	  && (!strcmp (unicode_attributes[ch].name, "<control>")
+	      /* Categories Zl and Zp */
+	      || (unicode_attributes[ch].category[0] == 'Z'
+		  && (unicode_attributes[ch].category[1] == 'l'
+		      || unicode_attributes[ch].category[1] == 'p'))));
+}
+
+static bool
+is_xdigit (unsigned int ch)
+{
+#if 0
+  return is_digit (ch)
+	 || (ch >= 0x0041 && ch <= 0x0046)
+	 || (ch >= 0x0061 && ch <= 0x0066);
+#else
+  /* SUSV2 gives us some freedom for the "xdigit" category, but ISO C 99
+     takes it away:
+     7.25.2.1.12:
+        The iswxdigit function tests for any wide character that corresponds
+        to a hexadecimal-digit character (as defined in 6.4.4.1).
+     6.4.4.1:
+        hexadecimal-digit: one of 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
+   */
+  return (ch >= 0x0030 && ch <= 0x0039)
+	 || (ch >= 0x0041 && ch <= 0x0046)
+	 || (ch >= 0x0061 && ch <= 0x0066);
+#endif
+}
+
+static bool
+is_graph (unsigned int ch)
+{
+  return (unicode_attributes[ch].name != NULL
+	  && strcmp (unicode_attributes[ch].name, "<control>")
+	  && !is_space (ch));
+}
+
+static bool
+is_print (unsigned int ch)
+{
+  return (unicode_attributes[ch].name != NULL
+	  && strcmp (unicode_attributes[ch].name, "<control>")
+	  /* Categories Zl and Zp */
+	  && !(unicode_attributes[ch].name != NULL
+	       && unicode_attributes[ch].category[0] == 'Z'
+	       && (unicode_attributes[ch].category[1] == 'l'
+		   || unicode_attributes[ch].category[1] == 'p')));
+}
+
+static bool
+is_punct (unsigned int ch)
+{
+#if 0
+  return (unicode_attributes[ch].name != NULL
+	  && unicode_attributes[ch].category[0] == 'P');
+#else
+  /* The traditional POSIX definition of punctuation is every graphic,
+     non-alphanumeric character.  */
+  return (is_graph (ch) && !is_alpha (ch) && !is_digit (ch));
+#endif
+}
+
+static bool
+is_combining (unsigned int ch)
+{
+  /* Up to Unicode 3.0.1 we took the Combining property from the PropList.txt
+     file. In 3.0.1 it was identical to the union of the general categories
+     "Mn", "Mc", "Me". In Unicode 3.1 this property has been dropped from the
+     PropList.txt file, so we take the latter definition.  */
+  return (unicode_attributes[ch].name != NULL
+	  && unicode_attributes[ch].category[0] == 'M'
+	  && (unicode_attributes[ch].category[1] == 'n'
+	      || unicode_attributes[ch].category[1] == 'c'
+	      || unicode_attributes[ch].category[1] == 'e'));
+}
+
+static bool
+is_combining_level3 (unsigned int ch)
+{
+  return is_combining (ch)
+	 && !(unicode_attributes[ch].combining[0] != '\0'
+	      && unicode_attributes[ch].combining[0] != '0'
+	      && strtoul (unicode_attributes[ch].combining, NULL, 10) >= 200);
+}
+
+/* Return the UCS symbol string for a Unicode character.  */
+static const char *
+ucs_symbol (unsigned int i)
+{
+  static char buf[11+1];
+
+  sprintf (buf, (i < 0x10000 ? "<U%04X>" : "<U%08X>"), i);
+  return buf;
+}
+
+/* Return the UCS symbol range string for a Unicode characters interval.  */
+static const char *
+ucs_symbol_range (unsigned int low, unsigned int high)
+{
+  static char buf[24+1];
+
+  strcpy (buf, ucs_symbol (low));
+  strcat (buf, "..");
+  strcat (buf, ucs_symbol (high));
+  return buf;
+}
+
+/* Output a character class (= property) table.  */
+
+static void
+output_charclass (FILE *stream, const char *classname,
+		  bool (*func) (unsigned int))
+{
+  char table[0x110000];
+  unsigned int i;
+  bool need_semicolon;
+  const int max_column = 75;
+  int column;
+
+  for (i = 0; i < 0x110000; i++)
+    table[i] = (int) func (i);
+
+  fprintf (stream, "%s ", classname);
+  need_semicolon = false;
+  column = 1000;
+  for (i = 0; i < 0x110000; )
+    {
+      if (!table[i])
+	i++;
+      else
+	{
+	  unsigned int low, high;
+	  char buf[25];
+
+	  low = i;
+	  do
+	    i++;
+	  while (i < 0x110000 && table[i]);
+	  high = i - 1;
+
+	  if (low == high)
+	    strcpy (buf, ucs_symbol (low));
+	  else
+	    strcpy (buf, ucs_symbol_range (low, high));
+
+	  if (need_semicolon)
+	    {
+	      fprintf (stream, ";");
+	      column++;
+	    }
+
+	  if (column + strlen (buf) > max_column)
+	    {
+	      fprintf (stream, "/\n   ");
+	      column = 3;
+	    }
+
+	  fprintf (stream, "%s", buf);
+	  column += strlen (buf);
+	  need_semicolon = true;
+	}
+    }
+  fprintf (stream, "\n");
+}
+
+/* Output a character mapping table.  */
+
+static void
+output_charmap (FILE *stream, const char *mapname,
+		unsigned int (*func) (unsigned int))
+{
+  char table[0x110000];
+  unsigned int i;
+  bool need_semicolon;
+  const int max_column = 75;
+  int column;
+
+  for (i = 0; i < 0x110000; i++)
+    table[i] = (func (i) != i);
+
+  fprintf (stream, "%s ", mapname);
+  need_semicolon = false;
+  column = 1000;
+  for (i = 0; i < 0x110000; i++)
+    if (table[i])
+      {
+	char buf[25+1];
+
+	strcpy (buf, "(");
+	strcat (buf, ucs_symbol (i));
+	strcat (buf, ",");
+	strcat (buf, ucs_symbol (func (i)));
+	strcat (buf, ")");
+
+	if (need_semicolon)
+	  {
+	    fprintf (stream, ";");
+	    column++;
+	  }
+
+	if (column + strlen (buf) > max_column)
+	  {
+	    fprintf (stream, "/\n   ");
+	    column = 3;
+	  }
+
+	fprintf (stream, "%s", buf);
+	column += strlen (buf);
+	need_semicolon = true;
+      }
+  fprintf (stream, "\n");
+}
+
+/* Output the width table.  */
+
+static void
+output_widthmap (FILE *stream)
+{
+}
+
+/* Output the tables to the given file.  */
+
+static void
+output_tables (const char *filename, const char *version)
+{
+  FILE *stream;
+  unsigned int ch;
+
+  stream = fopen (filename, "w");
+  if (stream == NULL)
+    {
+      fprintf (stderr, "cannot open '%s' for writing\n", filename);
+      exit (1);
+    }
+
+  fprintf (stream, "escape_char /\n");
+  fprintf (stream, "comment_char %%\n");
+  fprintf (stream, "\n");
+  fprintf (stream, "%% Generated automatically by gen-unicode-ctype for Unicode %s.\n",
+	   version);
+  fprintf (stream, "\n");
+
+  fprintf (stream, "LC_IDENTIFICATION\n");
+  fprintf (stream, "title     \"Unicode %s FDCC-set\"\n", version);
+  fprintf (stream, "source    \"UnicodeData.txt, PropList.txt\"\n");
+  fprintf (stream, "address   \"\"\n");
+  fprintf (stream, "contact   \"\"\n");
+  fprintf (stream, "email     \"bug-glibc-locales@gnu.org\"\n");
+  fprintf (stream, "tel       \"\"\n");
+  fprintf (stream, "fax       \"\"\n");
+  fprintf (stream, "language  \"\"\n");
+  fprintf (stream, "territory \"Earth\"\n");
+  fprintf (stream, "revision  \"%s\"\n", version);
+  {
+    time_t now;
+    char date[11];
+    now = time (NULL);
+    strftime (date, sizeof (date), "%Y-%m-%d", gmtime (&now));
+    fprintf (stream, "date      \"%s\"\n", date);
+  }
+  fprintf (stream, "category  \"unicode:2001\";LC_CTYPE\n");
+  fprintf (stream, "END LC_IDENTIFICATION\n");
+  fprintf (stream, "\n");
+
+  /* Verifications. */
+  for (ch = 0; ch < 0x110000; ch++)
+    {
+      /* toupper restriction: "Only characters specified for the keywords
+	 lower and upper shall be specified.  */
+      if (to_upper (ch) != ch && !(is_lower (ch) || is_upper (ch)))
+	fprintf (stderr,
+		 "%s is not upper|lower but toupper(0x%04X) = 0x%04X\n",
+		 ucs_symbol (ch), ch, to_upper (ch));
+
+      /* tolower restriction: "Only characters specified for the keywords
+	 lower and upper shall be specified.  */
+      if (to_lower (ch) != ch && !(is_lower (ch) || is_upper (ch)))
+	fprintf (stderr,
+		 "%s is not upper|lower but tolower(0x%04X) = 0x%04X\n",
+		 ucs_symbol (ch), ch, to_lower (ch));
+
+      /* alpha restriction: "Characters classified as either upper or lower
+	 shall automatically belong to this class.  */
+      if ((is_lower (ch) || is_upper (ch)) && !is_alpha (ch))
+	fprintf (stderr, "%s is upper|lower but not alpha\n", ucs_symbol (ch));
+
+      /* alpha restriction: "No character specified for the keywords cntrl,
+	 digit, punct or space shall be specified."  */
+      if (is_alpha (ch) && is_cntrl (ch))
+	fprintf (stderr, "%s is alpha and cntrl\n", ucs_symbol (ch));
+      if (is_alpha (ch) && is_digit (ch))
+	fprintf (stderr, "%s is alpha and digit\n", ucs_symbol (ch));
+      if (is_alpha (ch) && is_punct (ch))
+	fprintf (stderr, "%s is alpha and punct\n", ucs_symbol (ch));
+      if (is_alpha (ch) && is_space (ch))
+	fprintf (stderr, "%s is alpha and space\n", ucs_symbol (ch));
+
+      /* space restriction: "No character specified for the keywords upper,
+	 lower, alpha, digit, graph or xdigit shall be specified."
+	 upper, lower, alpha already checked above.  */
+      if (is_space (ch) && is_digit (ch))
+	fprintf (stderr, "%s is space and digit\n", ucs_symbol (ch));
+      if (is_space (ch) && is_graph (ch))
+	fprintf (stderr, "%s is space and graph\n", ucs_symbol (ch));
+      if (is_space (ch) && is_xdigit (ch))
+	fprintf (stderr, "%s is space and xdigit\n", ucs_symbol (ch));
+
+      /* cntrl restriction: "No character specified for the keywords upper,
+	 lower, alpha, digit, punct, graph, print or xdigit shall be
+	 specified."  upper, lower, alpha already checked above.  */
+      if (is_cntrl (ch) && is_digit (ch))
+	fprintf (stderr, "%s is cntrl and digit\n", ucs_symbol (ch));
+      if (is_cntrl (ch) && is_punct (ch))
+	fprintf (stderr, "%s is cntrl and punct\n", ucs_symbol (ch));
+      if (is_cntrl (ch) && is_graph (ch))
+	fprintf (stderr, "%s is cntrl and graph\n", ucs_symbol (ch));
+      if (is_cntrl (ch) && is_print (ch))
+	fprintf (stderr, "%s is cntrl and print\n", ucs_symbol (ch));
+      if (is_cntrl (ch) && is_xdigit (ch))
+	fprintf (stderr, "%s is cntrl and xdigit\n", ucs_symbol (ch));
+
+      /* punct restriction: "No character specified for the keywords upper,
+	 lower, alpha, digit, cntrl, xdigit or as the <space> character shall
+	 be specified."  upper, lower, alpha, cntrl already checked above.  */
+      if (is_punct (ch) && is_digit (ch))
+	fprintf (stderr, "%s is punct and digit\n", ucs_symbol (ch));
+      if (is_punct (ch) && is_xdigit (ch))
+	fprintf (stderr, "%s is punct and xdigit\n", ucs_symbol (ch));
+      if (is_punct (ch) && (ch == 0x0020))
+	fprintf (stderr, "%s is punct\n", ucs_symbol (ch));
+
+      /* graph restriction: "No character specified for the keyword cntrl
+	 shall be specified."  Already checked above.  */
+
+      /* print restriction: "No character specified for the keyword cntrl
+	 shall be specified."  Already checked above.  */
+
+      /* graph - print relation: differ only in the <space> character.
+	 How is this possible if there are more than one space character?!
+	 I think susv2/xbd/locale.html should speak of "space characters",
+	 not "space character".  */
+      if (is_print (ch) && !(is_graph (ch) || /* ch == 0x0020 */ is_space (ch)))
+	fprintf (stderr,
+		 "%s is print but not graph|<space>\n", ucs_symbol (ch));
+      if (!is_print (ch) && (is_graph (ch) || ch == 0x0020))
+	fprintf (stderr,
+		 "%s is graph|<space> but not print\n", ucs_symbol (ch));
+    }
+
+  fprintf (stream, "LC_CTYPE\n");
+  output_charclass (stream, "upper", is_upper);
+  output_charclass (stream, "lower", is_lower);
+  output_charclass (stream, "alpha", is_alpha);
+  output_charclass (stream, "digit", is_digit);
+  output_charclass (stream, "outdigit", is_outdigit);
+  output_charclass (stream, "blank", is_blank);
+  output_charclass (stream, "space", is_space);
+  output_charclass (stream, "cntrl", is_cntrl);
+  output_charclass (stream, "punct", is_punct);
+  output_charclass (stream, "xdigit", is_xdigit);
+  output_charclass (stream, "graph", is_graph);
+  output_charclass (stream, "print", is_print);
+  output_charclass (stream, "class \"combining\";", is_combining);
+  output_charclass (stream, "class \"combining_level3\";", is_combining_level3);
+  output_charmap (stream, "toupper", to_upper);
+  output_charmap (stream, "tolower", to_lower);
+  output_charmap (stream, "map \"totitle\";", to_title);
+  output_widthmap (stream);
+  fprintf (stream, "END LC_CTYPE\n");
+
+  if (ferror (stream) || fclose (stream))
+    {
+      fprintf (stderr, "error writing to '%s'\n", filename);
+      exit (1);
+    }
+}
+
+int
+main (int argc, char * argv[])
+{
+  if (argc != 3)
+    {
+      fprintf (stderr, "Usage: %s UnicodeData.txt version\n", argv[0]);
+      exit (1);
+    }
+
+  fill_attributes (argv[1]);
+
+  output_tables ("unicode", argv[2]);
+
+  return 0;
+}

+ 62 - 0
test/locale/show-ucs-data.c

@@ -0,0 +1,62 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+int
+main (int argc, char *argv[])
+{
+  int n;
+  char *line = NULL;
+  size_t len = 0;
+
+  for (n = 1; n < argc; ++n)
+    {
+      FILE *fp = fopen (argv[n], "r");
+      if (fp == NULL)
+	continue;
+
+      while (! feof (fp))
+	{
+	  ssize_t cnt = getline (&line, &len, fp);
+	  char *runp;
+	  if (cnt <= 0)
+	    break;
+
+	  runp = line;
+	  do
+	    {
+	      if (runp[0] == '<' && runp[1] == 'U' && isxdigit (runp[2])
+		  && isxdigit (runp[3]) && isxdigit (runp[4])
+		  && isxdigit (runp[5]) && runp[6] == '>')
+		{
+		  unsigned int val = strtoul (runp + 2, NULL, 16);
+
+		  //putchar ('<');
+		  if (val < 128)
+		    putchar (val);
+		  else if (val < 0x800)
+		    {
+		      putchar (0xc0 | (val >> 6));
+		      putchar (0x80 | (val & 0x3f));
+		    }
+		  else
+		    {
+		      putchar (0xe0 | (val >> 12));
+		      putchar (0x80 | ((val >> 6) & 0x3f));
+		      putchar (0x80 | (val & 0x3f));
+		    }
+		  //putchar ('>');
+		  runp += 7;
+		}
+	      else
+		putchar (*runp++);
+	    }
+	  while (runp < &line[cnt]);
+	}
+
+      fclose (fp);
+    }
+
+  return 0;
+}

+ 498 - 0
test/locale/tst-C-locale.c

@@ -0,0 +1,498 @@
+/* Tests of C and POSIX locale contents.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <ctype.h>
+#include <langinfo.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+
+static int
+run_test (const char *locname)
+{
+  struct lconv *lc;
+  const char *str;
+  const wchar_t *wstr;
+  int result = 0;
+  locale_t loc;
+
+  /* ISO C stuff.  */
+  lc = localeconv ();
+  if (lc == NULL)
+    {
+      printf ("localeconv failed for locale %s\n", locname);
+      result = 1;
+    }
+  else
+    {
+#define STRTEST(name, exp) \
+      do								      \
+	if (strcmp (lc->name, exp) != 0)				      \
+	  {								      \
+	    printf (#name " in locale %s wrong (is \"%s\", should be \"%s\")\n",\
+		    locname, lc->name, exp);				      \
+	    result = 1;							      \
+	  }								      \
+      while (0)
+      STRTEST (decimal_point, ".");
+      STRTEST (thousands_sep, "");
+      STRTEST (grouping, "");
+      STRTEST (mon_decimal_point, "");
+      STRTEST (mon_thousands_sep, "");
+      STRTEST (mon_grouping, "");
+      STRTEST (positive_sign, "");
+      STRTEST (negative_sign, "");
+      STRTEST (currency_symbol, "");
+      STRTEST (int_curr_symbol, "");
+
+#define CHARTEST(name, exp) \
+      do								      \
+	if (lc->name != exp)						      \
+	  {								      \
+	    printf (#name " in locale %s wrong (is %d, should be %d)\n",      \
+		    locname, lc->name, CHAR_MAX);			      \
+	    result = 1;							      \
+	  }								      \
+      while (0)
+      CHARTEST (frac_digits, CHAR_MAX);
+      CHARTEST (p_cs_precedes, CHAR_MAX);
+      CHARTEST (n_cs_precedes, CHAR_MAX);
+      CHARTEST (p_sep_by_space, CHAR_MAX);
+      CHARTEST (n_sep_by_space, CHAR_MAX);
+      CHARTEST (p_sign_posn, CHAR_MAX);
+      CHARTEST (n_sign_posn, CHAR_MAX);
+      CHARTEST (int_frac_digits, CHAR_MAX);
+      CHARTEST (int_p_cs_precedes, CHAR_MAX);
+      CHARTEST (int_n_cs_precedes, CHAR_MAX);
+      CHARTEST (int_p_sep_by_space, CHAR_MAX);
+      CHARTEST (int_n_sep_by_space, CHAR_MAX);
+      CHARTEST (int_p_sign_posn, CHAR_MAX);
+      CHARTEST (int_n_sign_posn, CHAR_MAX);
+    }
+
+#undef STRTEST
+#define STRTEST(name, exp) \
+  str = nl_langinfo (name);						      \
+  if (strcmp (str, exp) != 0)						      \
+    {									      \
+      printf ("nl_langinfo(" #name ") in locale %s wrong "		      \
+	      "(is \"%s\", should be \"%s\")\n", locname, str, exp);	      \
+      result = 1;							      \
+    }
+#define WSTRTEST(name, exp) \
+  wstr = (wchar_t *) nl_langinfo (name);				      \
+  if (wcscmp (wstr, exp) != 0)						      \
+    {									      \
+      printf ("nl_langinfo(" #name ") in locale %s wrong "		      \
+	      "(is \"%S\", should be \"%S\")\n", locname, wstr, exp);	      \
+      result = 1;							      \
+    }
+
+  /* Unix stuff.  */
+  STRTEST (ABDAY_1, "Sun");
+  STRTEST (ABDAY_2, "Mon");
+  STRTEST (ABDAY_3, "Tue");
+  STRTEST (ABDAY_4, "Wed");
+  STRTEST (ABDAY_5, "Thu");
+  STRTEST (ABDAY_6, "Fri");
+  STRTEST (ABDAY_7, "Sat");
+  STRTEST (DAY_1, "Sunday");
+  STRTEST (DAY_2, "Monday");
+  STRTEST (DAY_3, "Tuesday");
+  STRTEST (DAY_4, "Wednesday");
+  STRTEST (DAY_5, "Thursday");
+  STRTEST (DAY_6, "Friday");
+  STRTEST (DAY_7, "Saturday");
+  STRTEST (ABMON_1, "Jan");
+  STRTEST (ABMON_2, "Feb");
+  STRTEST (ABMON_3, "Mar");
+  STRTEST (ABMON_4, "Apr");
+  STRTEST (ABMON_5, "May");
+  STRTEST (ABMON_6, "Jun");
+  STRTEST (ABMON_7, "Jul");
+  STRTEST (ABMON_8, "Aug");
+  STRTEST (ABMON_9, "Sep");
+  STRTEST (ABMON_10, "Oct");
+  STRTEST (ABMON_11, "Nov");
+  STRTEST (ABMON_12, "Dec");
+  STRTEST (MON_1, "January");
+  STRTEST (MON_2, "February");
+  STRTEST (MON_3, "March");
+  STRTEST (MON_4, "April");
+  STRTEST (MON_5, "May");
+  STRTEST (MON_6, "June");
+  STRTEST (MON_7, "July");
+  STRTEST (MON_8, "August");
+  STRTEST (MON_9, "September");
+  STRTEST (MON_10, "October");
+  STRTEST (MON_11, "November");
+  STRTEST (MON_12, "December");
+  STRTEST (AM_STR, "AM");
+  STRTEST (PM_STR, "PM");
+  STRTEST (D_T_FMT, "%a %b %e %H:%M:%S %Y");
+  STRTEST (D_FMT, "%m/%d/%y");
+  STRTEST (T_FMT, "%H:%M:%S");
+  STRTEST (T_FMT_AMPM, "%I:%M:%S %p");
+  STRTEST (ERA, "");
+  STRTEST (ERA_D_FMT, "");
+  STRTEST (ERA_T_FMT, "");
+  STRTEST (ERA_D_T_FMT, "");
+  STRTEST (ALT_DIGITS, "");
+
+  STRTEST (RADIXCHAR, ".");
+  STRTEST (THOUSEP, "");
+
+  STRTEST (YESEXPR, "^[yY]");
+  STRTEST (NOEXPR, "^[nN]");
+
+  /* Extensions.  */
+  WSTRTEST (_NL_WABDAY_1, L"Sun");
+  WSTRTEST (_NL_WABDAY_2, L"Mon");
+  WSTRTEST (_NL_WABDAY_3, L"Tue");
+  WSTRTEST (_NL_WABDAY_4, L"Wed");
+  WSTRTEST (_NL_WABDAY_5, L"Thu");
+  WSTRTEST (_NL_WABDAY_6, L"Fri");
+  WSTRTEST (_NL_WABDAY_7, L"Sat");
+  WSTRTEST (_NL_WDAY_1, L"Sunday");
+  WSTRTEST (_NL_WDAY_2, L"Monday");
+  WSTRTEST (_NL_WDAY_3, L"Tuesday");
+  WSTRTEST (_NL_WDAY_4, L"Wednesday");
+  WSTRTEST (_NL_WDAY_5, L"Thursday");
+  WSTRTEST (_NL_WDAY_6, L"Friday");
+  WSTRTEST (_NL_WDAY_7, L"Saturday");
+  WSTRTEST (_NL_WABMON_1, L"Jan");
+  WSTRTEST (_NL_WABMON_2, L"Feb");
+  WSTRTEST (_NL_WABMON_3, L"Mar");
+  WSTRTEST (_NL_WABMON_4, L"Apr");
+  WSTRTEST (_NL_WABMON_5, L"May");
+  WSTRTEST (_NL_WABMON_6, L"Jun");
+  WSTRTEST (_NL_WABMON_7, L"Jul");
+  WSTRTEST (_NL_WABMON_8, L"Aug");
+  WSTRTEST (_NL_WABMON_9, L"Sep");
+  WSTRTEST (_NL_WABMON_10, L"Oct");
+  WSTRTEST (_NL_WABMON_11, L"Nov");
+  WSTRTEST (_NL_WABMON_12, L"Dec");
+  WSTRTEST (_NL_WMON_1, L"January");
+  WSTRTEST (_NL_WMON_2, L"February");
+  WSTRTEST (_NL_WMON_3, L"March");
+  WSTRTEST (_NL_WMON_4, L"April");
+  WSTRTEST (_NL_WMON_5, L"May");
+  WSTRTEST (_NL_WMON_6, L"June");
+  WSTRTEST (_NL_WMON_7, L"July");
+  WSTRTEST (_NL_WMON_8, L"August");
+  WSTRTEST (_NL_WMON_9, L"September");
+  WSTRTEST (_NL_WMON_10, L"October");
+  WSTRTEST (_NL_WMON_11, L"November");
+  WSTRTEST (_NL_WMON_12, L"December");
+  WSTRTEST (_NL_WAM_STR, L"AM");
+  WSTRTEST (_NL_WPM_STR, L"PM");
+  WSTRTEST (_NL_WD_T_FMT, L"%a %b %e %H:%M:%S %Y");
+  WSTRTEST (_NL_WD_FMT, L"%m/%d/%y");
+  WSTRTEST (_NL_WT_FMT, L"%H:%M:%S");
+  WSTRTEST (_NL_WT_FMT_AMPM, L"%I:%M:%S %p");
+  WSTRTEST (_NL_WERA_D_FMT, L"");
+  WSTRTEST (_NL_WERA_T_FMT, L"");
+  WSTRTEST (_NL_WERA_D_T_FMT, L"");
+  WSTRTEST (_NL_WALT_DIGITS, L"");
+
+  STRTEST (_DATE_FMT, "%a %b %e %H:%M:%S %Z %Y");
+  WSTRTEST (_NL_W_DATE_FMT, L"%a %b %e %H:%M:%S %Z %Y");
+
+  STRTEST (INT_CURR_SYMBOL, "");
+  STRTEST (CURRENCY_SYMBOL, "");
+  STRTEST (MON_DECIMAL_POINT, "");
+  STRTEST (MON_THOUSANDS_SEP, "");
+  STRTEST (MON_GROUPING, "");
+  STRTEST (POSITIVE_SIGN, "");
+  STRTEST (NEGATIVE_SIGN, "");
+  STRTEST (GROUPING, "");
+
+  STRTEST (YESSTR, "");
+  STRTEST (NOSTR, "");
+
+  /* Test the new locale mechanisms.  */
+  loc = newlocale (LC_ALL_MASK, locname, NULL);
+  if (loc == NULL)
+    {
+      printf ("cannot create locale object for locale %s\n", locname);
+      result = 1;
+    }
+  else
+    {
+      int c;
+
+#undef STRTEST
+#define STRTEST(name, exp) \
+      str = nl_langinfo_l (name, loc);				      \
+      if (strcmp (str, exp) != 0)					      \
+	{								      \
+	  printf ("nl_langinfo_l(" #name ") in locale %s wrong "	      \
+		  "(is \"%s\", should be \"%s\")\n", locname, str, exp);      \
+	  result = 1;							      \
+	}
+#undef WSTRTEST
+#define WSTRTEST(name, exp) \
+      wstr = (wchar_t *) nl_langinfo_l (name, loc);			      \
+      if (wcscmp (wstr, exp) != 0)					      \
+	{								      \
+	  printf ("nl_langinfo_l(" #name ") in locale %s wrong "	      \
+		  "(is \"%S\", should be \"%S\")\n", locname, wstr, exp);     \
+	  result = 1;							      \
+	}
+
+      /* Unix stuff.  */
+      STRTEST (ABDAY_1, "Sun");
+      STRTEST (ABDAY_2, "Mon");
+      STRTEST (ABDAY_3, "Tue");
+      STRTEST (ABDAY_4, "Wed");
+      STRTEST (ABDAY_5, "Thu");
+      STRTEST (ABDAY_6, "Fri");
+      STRTEST (ABDAY_7, "Sat");
+      STRTEST (DAY_1, "Sunday");
+      STRTEST (DAY_2, "Monday");
+      STRTEST (DAY_3, "Tuesday");
+      STRTEST (DAY_4, "Wednesday");
+      STRTEST (DAY_5, "Thursday");
+      STRTEST (DAY_6, "Friday");
+      STRTEST (DAY_7, "Saturday");
+      STRTEST (ABMON_1, "Jan");
+      STRTEST (ABMON_2, "Feb");
+      STRTEST (ABMON_3, "Mar");
+      STRTEST (ABMON_4, "Apr");
+      STRTEST (ABMON_5, "May");
+      STRTEST (ABMON_6, "Jun");
+      STRTEST (ABMON_7, "Jul");
+      STRTEST (ABMON_8, "Aug");
+      STRTEST (ABMON_9, "Sep");
+      STRTEST (ABMON_10, "Oct");
+      STRTEST (ABMON_11, "Nov");
+      STRTEST (ABMON_12, "Dec");
+      STRTEST (MON_1, "January");
+      STRTEST (MON_2, "February");
+      STRTEST (MON_3, "March");
+      STRTEST (MON_4, "April");
+      STRTEST (MON_5, "May");
+      STRTEST (MON_6, "June");
+      STRTEST (MON_7, "July");
+      STRTEST (MON_8, "August");
+      STRTEST (MON_9, "September");
+      STRTEST (MON_10, "October");
+      STRTEST (MON_11, "November");
+      STRTEST (MON_12, "December");
+      STRTEST (AM_STR, "AM");
+      STRTEST (PM_STR, "PM");
+      STRTEST (D_T_FMT, "%a %b %e %H:%M:%S %Y");
+      STRTEST (D_FMT, "%m/%d/%y");
+      STRTEST (T_FMT, "%H:%M:%S");
+      STRTEST (T_FMT_AMPM, "%I:%M:%S %p");
+      STRTEST (ERA, "");
+      STRTEST (ERA_D_FMT, "");
+      STRTEST (ERA_T_FMT, "");
+      STRTEST (ERA_D_T_FMT, "");
+      STRTEST (ALT_DIGITS, "");
+
+      STRTEST (RADIXCHAR, ".");
+      STRTEST (THOUSEP, "");
+
+      STRTEST (YESEXPR, "^[yY]");
+      STRTEST (NOEXPR, "^[nN]");
+
+      /* Extensions.  */
+      WSTRTEST (_NL_WABDAY_1, L"Sun");
+      WSTRTEST (_NL_WABDAY_2, L"Mon");
+      WSTRTEST (_NL_WABDAY_3, L"Tue");
+      WSTRTEST (_NL_WABDAY_4, L"Wed");
+      WSTRTEST (_NL_WABDAY_5, L"Thu");
+      WSTRTEST (_NL_WABDAY_6, L"Fri");
+      WSTRTEST (_NL_WABDAY_7, L"Sat");
+      WSTRTEST (_NL_WDAY_1, L"Sunday");
+      WSTRTEST (_NL_WDAY_2, L"Monday");
+      WSTRTEST (_NL_WDAY_3, L"Tuesday");
+      WSTRTEST (_NL_WDAY_4, L"Wednesday");
+      WSTRTEST (_NL_WDAY_5, L"Thursday");
+      WSTRTEST (_NL_WDAY_6, L"Friday");
+      WSTRTEST (_NL_WDAY_7, L"Saturday");
+      WSTRTEST (_NL_WABMON_1, L"Jan");
+      WSTRTEST (_NL_WABMON_2, L"Feb");
+      WSTRTEST (_NL_WABMON_3, L"Mar");
+      WSTRTEST (_NL_WABMON_4, L"Apr");
+      WSTRTEST (_NL_WABMON_5, L"May");
+      WSTRTEST (_NL_WABMON_6, L"Jun");
+      WSTRTEST (_NL_WABMON_7, L"Jul");
+      WSTRTEST (_NL_WABMON_8, L"Aug");
+      WSTRTEST (_NL_WABMON_9, L"Sep");
+      WSTRTEST (_NL_WABMON_10, L"Oct");
+      WSTRTEST (_NL_WABMON_11, L"Nov");
+      WSTRTEST (_NL_WABMON_12, L"Dec");
+      WSTRTEST (_NL_WMON_1, L"January");
+      WSTRTEST (_NL_WMON_2, L"February");
+      WSTRTEST (_NL_WMON_3, L"March");
+      WSTRTEST (_NL_WMON_4, L"April");
+      WSTRTEST (_NL_WMON_5, L"May");
+      WSTRTEST (_NL_WMON_6, L"June");
+      WSTRTEST (_NL_WMON_7, L"July");
+      WSTRTEST (_NL_WMON_8, L"August");
+      WSTRTEST (_NL_WMON_9, L"September");
+      WSTRTEST (_NL_WMON_10, L"October");
+      WSTRTEST (_NL_WMON_11, L"November");
+      WSTRTEST (_NL_WMON_12, L"December");
+      WSTRTEST (_NL_WAM_STR, L"AM");
+      WSTRTEST (_NL_WPM_STR, L"PM");
+      WSTRTEST (_NL_WD_T_FMT, L"%a %b %e %H:%M:%S %Y");
+      WSTRTEST (_NL_WD_FMT, L"%m/%d/%y");
+      WSTRTEST (_NL_WT_FMT, L"%H:%M:%S");
+      WSTRTEST (_NL_WT_FMT_AMPM, L"%I:%M:%S %p");
+      WSTRTEST (_NL_WERA_D_FMT, L"");
+      WSTRTEST (_NL_WERA_T_FMT, L"");
+      WSTRTEST (_NL_WERA_D_T_FMT, L"");
+      WSTRTEST (_NL_WALT_DIGITS, L"");
+
+      STRTEST (_DATE_FMT, "%a %b %e %H:%M:%S %Z %Y");
+      WSTRTEST (_NL_W_DATE_FMT, L"%a %b %e %H:%M:%S %Z %Y");
+
+      STRTEST (INT_CURR_SYMBOL, "");
+      STRTEST (CURRENCY_SYMBOL, "");
+      STRTEST (MON_DECIMAL_POINT, "");
+      STRTEST (MON_THOUSANDS_SEP, "");
+      STRTEST (MON_GROUPING, "");
+      STRTEST (POSITIVE_SIGN, "");
+      STRTEST (NEGATIVE_SIGN, "");
+      STRTEST (GROUPING, "");
+
+      STRTEST (YESSTR, "");
+      STRTEST (NOSTR, "");
+
+      /* Character class tests.  */
+      for (c = 0; c < 128; ++c)
+	{
+#define CLASSTEST(name) \
+	  if (is##name (c) != is##name##_l (c, loc))			      \
+	    {								      \
+	      printf ("is%s('\\%o') != is%s_l('\\%o')\n",		      \
+		      #name, c, #name, c);				      \
+	      result = 1;						      \
+	    }
+	  CLASSTEST (alnum);
+	  CLASSTEST (alpha);
+	  CLASSTEST (blank);
+	  CLASSTEST (cntrl);
+	  CLASSTEST (digit);
+	  CLASSTEST (lower);
+	  CLASSTEST (graph);
+	  CLASSTEST (print);
+	  CLASSTEST (punct);
+	  CLASSTEST (space);
+	  CLASSTEST (upper);
+	  CLASSTEST (xdigit);
+
+	  /* Character mapping tests.  */
+#define MAPTEST(name) \
+	  if (to##name (c) != to##name##_l (c, loc))			      \
+	    {								      \
+	      printf ("to%s('\\%o') != to%s_l('\\%o'): '\\%o' vs '\\%o'\n", \
+		      #name, c, #name, c,				      \
+		      to##name (c), to##name##_l (c, loc));		      \
+	      result = 1;						      \
+	    }
+	  MAPTEST (lower);
+	  MAPTEST (upper);
+	}
+
+      /* Character class tests, this time for wide characters.  Note that
+	 this only works because we know that the internal encoding is
+	 UCS4.  */
+      for (c = 0; c < 128; ++c)
+	{
+#undef CLASSTEST
+#define CLASSTEST(name) \
+	  if (isw##name (c) != isw##name##_l (c, loc))		      \
+	    {								      \
+	      printf ("isw%s('\\%o') != isw%s_l('\\%o')\n",		      \
+		      #name, c, #name, c);				      \
+	      result = 1;						      \
+	    }
+	  CLASSTEST (alnum);
+	  CLASSTEST (alpha);
+	  CLASSTEST (blank);
+	  CLASSTEST (cntrl);
+	  CLASSTEST (digit);
+	  CLASSTEST (lower);
+	  CLASSTEST (graph);
+	  CLASSTEST (print);
+	  CLASSTEST (punct);
+	  CLASSTEST (space);
+	  CLASSTEST (upper);
+	  CLASSTEST (xdigit);
+
+	  /* Character mapping tests.  Note that
+	     this only works because we know that the internal encoding is
+	     UCS4.  */
+#undef MAPTEST
+#define MAPTEST(name) \
+	  if (tow##name (c) != tow##name##_l (c, loc))		      \
+	    {								      \
+	      printf ("tow%s('\\%o') != tow%s_l('\\%o'): '\\%o' vs '\\%o'\n",\
+		      #name, c, #name, c,				      \
+		      tow##name (c), tow##name##_l (c, loc));		      \
+	      result = 1;						      \
+	    }
+	  MAPTEST (lower);
+	  MAPTEST (upper);
+	}
+
+      freelocale (loc);
+    }
+
+  return result;
+}
+
+
+static int
+do_test (void)
+{
+  int result;
+
+  /* First use the name "C".  */
+  if (setlocale (LC_ALL, "C") == NULL)
+    {
+      puts ("cannot set C locale");
+      result = 1;
+    }
+  else
+    result = run_test ("C");
+
+  /* Then the name "POSIX".  */
+  if (setlocale (LC_ALL, "POSIX") == NULL)
+    {
+      puts ("cannot set POSIX locale");
+      result = 1;
+    }
+  else
+    result |= run_test ("POSIX");
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 56 - 0
test/locale/tst-ctype-de_DE.ISO-8859-1.in

@@ -0,0 +1,56 @@
+lower   嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        000000000000000000000100000000000000000000000000
+lower   倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        000000000000000111111111111111111111111011111111
+upper   嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        000000000000000000000000000000001111111111111111
+upper   倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        111111101111111000000000000000000000000000000000
+alpha   嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        000000000010000000000100001000001111111111111111
+alpha   倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        111111101111111111111111111111111111111011111111
+digit   嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        000000000000000000000000000000000000000000000000
+digit   倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        000000000000000000000000000000000000000000000000
+xdigit  嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        000000000000000000000000000000000000000000000000
+xdigit  倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        000000000000000000000000000000000000000000000000
+space   嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        000000000000000000000000000000000000000000000000
+space   倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        000000000000000000000000000000000000000000000000
+print   嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        111111111111111111111111111111111111111111111111
+print   倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        111111111111111111111111111111111111111111111111
+graph   嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        111111111111111111111111111111111111111111111111
+graph   倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        111111111111111111111111111111111111111111111111
+blank   嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        000000000000000000000000000000000000000000000000
+blank   倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        000000000000000000000000000000000000000000000000
+cntrl   嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        000000000000000000000000000000000000000000000000
+cntrl   倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        000000000000000000000000000000000000000000000000
+punct   嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        111111111101111111111011110111110000000000000000
+punct   倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        000000010000000000000000000000000000000100000000
+alnum   嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        000000000010000000000100001000001111111111111111
+alnum   倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        111111101111111111111111111111111111111011111111
+tolower 嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        嵗╯丰戍貝物洎悖停眾斯須號獄播噶颬睼麧緗鴇膹擨闀
+tolower 倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        貘覷鏷囆矙𡜍𦶠𤨒颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+toupper 嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+        嵗╯丰戍貝物洎悖停眾斯須號獄播噶擱藏霰匸�帊昅恘
+toupper 倳眑婭笫崷窙嗲睧颬睼麧緗鴇膹擨闀貘覷鏷禴矙𡜍𦶠�
+        倳眑婭笫崷窙嗲睧擱藏霰匸�帊昅恘倳眑婭翋崷窙嗲�

+ 447 - 0
test/locale/tst-ctype.c

@@ -0,0 +1,447 @@
+/* Copyright (C) 2000,02, 05 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gnu.org>, 2000.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <ctype.h>
+#include <locale.h>
+#include <langinfo.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static const char lower[] = "abcdefghijklmnopqrstuvwxyz";
+static const char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static const char digits[] = "0123456789";
+static const char cntrl[] = "\
+\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\
+\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ";
+
+
+static struct classes
+{
+  const char *name;
+  int mask;
+} classes[] =
+{
+#define ENTRY(name) { #name, _IS##name }
+  ENTRY (upper),
+  ENTRY (lower),
+  ENTRY (alpha),
+  ENTRY (digit),
+  ENTRY (xdigit),
+  ENTRY (space),
+  ENTRY (print),
+  ENTRY (graph),
+  ENTRY (blank),
+  ENTRY (cntrl),
+  ENTRY (punct),
+  ENTRY (alnum)
+};
+#define nclasses (sizeof (classes) / sizeof (classes[0]))
+
+
+#define FAIL(str, args...) \
+  {									      \
+    printf ("      " str "\n", ##args);					      \
+    ++errors;								      \
+  }
+
+
+int
+main (void)
+{
+  const char *cp;
+  const char *cp2;
+  int errors = 0;
+  char *inpline = NULL;
+  size_t inplinelen = 0;
+  char *resline = NULL;
+  size_t reslinelen = 0;
+  size_t n;
+
+  setlocale (LC_ALL, "");
+
+  printf ("Testing the ctype data of the `%s' locale\n",
+	  setlocale (LC_CTYPE, NULL));
+
+#if 0
+  /* Just for debugging.  */
+
+  /* Contents of the class array.  */
+  printf ("\
+upper = %04x  lower = %04x  alpha = %04x  digit = %04x  xdigit = %04x\n\
+space = %04x  print = %04x  graph = %04x  blank = %04x  cntrl  = %04x\n\
+punct = %04x  alnum = %04x\n",
+	  _ISupper, _ISlower, _ISalpha, _ISdigit, _ISxdigit,
+	  _ISspace, _ISprint, _ISgraph, _ISblank, _IScntrl,
+	  _ISpunct, _ISalnum);
+
+  while (n < 256)
+    {
+      if (n % 8 == 0)
+	printf ("%02x: ", n);
+      printf ("%04x%s", __ctype_b[n], (n + 1) % 8 == 0 ? "\n" : " ");
+      ++n;
+    }
+#endif
+
+  puts ("  Test of ASCII character range\n    special NUL byte handling");
+  if (isupper ('\0'))
+    FAIL ("isupper ('\\0') is true");
+  if (islower ('\0'))
+    FAIL ("islower ('\\0') is true");
+  if (isalpha ('\0'))
+    FAIL ("isalpha ('\\0') is true");
+  if (isdigit ('\0'))
+    FAIL ("isdigit ('\\0') is true");
+  if (isxdigit ('\0'))
+    FAIL ("isxdigit ('\\0') is true");
+  if (isspace ('\0'))
+    FAIL ("isspace ('\\0') is true");
+  if (isprint ('\0'))
+    FAIL ("isprint ('\\0') is true");
+  if (isgraph ('\0'))
+    FAIL ("isgraph ('\\0') is true");
+  if (isblank ('\0'))
+    FAIL ("isblank ('\\0') is true");
+  if (! iscntrl ('\0'))
+    FAIL ("iscntrl ('\\0') not true");
+  if (ispunct ('\0'))
+    FAIL ("ispunct ('\\0') is true");
+  if (isalnum ('\0'))
+    FAIL ("isalnum ('\\0') is true");
+
+  puts ("    islower()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (! islower (*cp))
+      FAIL ("islower ('%c') not true", *cp);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (islower (*cp))
+      FAIL ("islower ('%c') is true", *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (islower (*cp))
+      FAIL ("islower ('%c') is true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if (islower (*cp))
+      FAIL ("islower ('\\x%02x') is true", *cp);
+
+  puts ("    isupper()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (isupper (*cp))
+      FAIL ("isupper ('%c') is true", *cp);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (! isupper (*cp))
+      FAIL ("isupper ('%c') not true", *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (isupper (*cp))
+      FAIL ("isupper ('%c') is true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if (isupper (*cp))
+      FAIL ("isupper ('\\x%02x') is true", *cp);
+
+  puts ("    isalpha()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (! isalpha (*cp))
+      FAIL ("isalpha ('%c') not true", *cp);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (! isalpha (*cp))
+      FAIL ("isalpha ('%c') not true", *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (isalpha (*cp))
+      FAIL ("isalpha ('%c') is true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if (isalpha (*cp))
+      FAIL ("isalpha ('\\x%02x') is true", *cp);
+
+  puts ("    isdigit()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (isdigit (*cp))
+      FAIL ("isdigit ('%c') is true", *cp);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (isdigit (*cp))
+      FAIL ("isdigit ('%c') is true", *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (! isdigit (*cp))
+      FAIL ("isdigit ('%c') not true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if (isdigit (*cp))
+      FAIL ("isdigit ('\\x%02x') is true", *cp);
+
+  puts ("    isxdigit()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if ((! isxdigit (*cp) && cp - lower < 6)
+	|| (isxdigit (*cp) && cp - lower >= 6))
+      FAIL ("isxdigit ('%c') %s true", *cp, cp - upper < 6 ? "not" : "is");
+  for (cp = upper; *cp != '\0'; ++cp)
+    if ((! isxdigit (*cp) && cp - upper < 6)
+	|| (isxdigit (*cp) && cp - upper >= 6))
+      FAIL ("isxdigit ('%c') %s true", *cp, cp - upper < 6 ? "not" : "is");
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (! isxdigit (*cp))
+      FAIL ("isxdigit ('%c') not true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if (isxdigit (*cp))
+      FAIL ("isxdigit ('\\x%02x') is true", *cp);
+
+  puts ("    isspace()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (isspace (*cp))
+      FAIL ("isspace ('%c') is true", *cp);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (isspace (*cp))
+      FAIL ("isspace ('%c') is true", *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (isspace (*cp))
+      FAIL ("isspace ('%c') is true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if ((isspace (*cp) && ((*cp < '\x09' || *cp > '\x0d') && *cp != ' '))
+	|| (! isspace (*cp)
+	    && ((*cp >= '\x09' && *cp <= '\x0d') || *cp == ' ')))
+      FAIL ("isspace ('\\x%02x') %s true", *cp,
+	    (*cp < '\x09' || *cp > '\x0d') ? "is" : "not");
+
+  puts ("    isprint()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (! isprint (*cp))
+      FAIL ("isprint ('%c') not true", *cp);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (! isprint (*cp))
+      FAIL ("isprint ('%c') not true", *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (! isprint (*cp))
+      FAIL ("isprint ('%c') not true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if ((isprint (*cp) && *cp != ' ')
+	|| (! isprint (*cp) && *cp == ' '))
+      FAIL ("isprint ('\\x%02x') is true", *cp);
+
+  puts ("    isgraph()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (! isgraph (*cp))
+      FAIL ("isgraph ('%c') not true", *cp);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (! isgraph (*cp))
+      FAIL ("isgraph ('%c') not true", *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (! isgraph (*cp))
+      FAIL ("isgraph ('%c') not true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if (isgraph (*cp))
+      FAIL ("isgraph ('\\x%02x') is true", *cp);
+
+  puts ("    isblank()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (isblank (*cp))
+      FAIL ("isblank ('%c') is true", *cp);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (isblank (*cp))
+      FAIL ("isblank ('%c') is true", *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (isblank (*cp))
+      FAIL ("isblank ('%c') is true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if ((isblank (*cp) && *cp != '\x09' && *cp != ' ')
+	|| (! isblank (*cp) && (*cp == '\x09' || *cp == ' ')))
+      FAIL ("isblank ('\\x%02x') %s true", *cp, *cp != '\x09' ? "is" : "not");
+
+  puts ("    iscntrl()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (iscntrl (*cp))
+      FAIL ("iscntrl ('%c') is true", *cp);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (iscntrl (*cp))
+      FAIL ("iscntrl ('%c') is true", *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (iscntrl (*cp))
+      FAIL ("iscntrl ('%c') is true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if ((iscntrl (*cp) && *cp == ' ')
+	|| (! iscntrl (*cp) && *cp != ' '))
+      FAIL ("iscntrl ('\\x%02x') not true", *cp);
+
+  puts ("    ispunct()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (ispunct (*cp))
+      FAIL ("ispunct ('%c') is true", *cp);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (ispunct (*cp))
+      FAIL ("ispunct ('%c') is true", *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (ispunct (*cp))
+      FAIL ("ispunct ('%c') is true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if (ispunct (*cp))
+      FAIL ("ispunct ('\\x%02x') is true", *cp);
+
+  puts ("    isalnum()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (! isalnum (*cp))
+      FAIL ("isalnum ('%c') not true", *cp);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (! isalnum (*cp))
+      FAIL ("isalnum ('%c') not true", *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (! isalnum (*cp))
+      FAIL ("isalnum ('%c') not true", *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if (isalnum (*cp))
+      FAIL ("isalnum ('\\x%02x') is true", *cp);
+
+
+  puts ("    tolower()");
+  for (cp = lower; *cp != '\0'; ++cp)
+    if (tolower (*cp) != *cp)
+      FAIL ("tolower ('%c') != '%c'", *cp, *cp);
+  for (cp = upper, cp2 = lower; *cp != '\0'; ++cp, ++cp2)
+    if (tolower (*cp) != *cp2)
+      FAIL ("tolower ('%c') != '%c'", *cp, *cp2);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (tolower (*cp) != *cp)
+      FAIL ("tolower ('%c') != '%c'", *cp, *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if (tolower (*cp) != *cp)
+      FAIL ("tolower ('\\x%02x') != '\\x%02x'", *cp, *cp);
+
+  puts ("    toupper()");
+  for (cp = lower, cp2 = upper; *cp != '\0'; ++cp, ++cp2)
+    if (toupper (*cp) != *cp2)
+      FAIL ("toupper ('%c') != '%c'", *cp, *cp2);
+  for (cp = upper; *cp != '\0'; ++cp)
+    if (toupper (*cp) != *cp)
+      FAIL ("toupper ('%c') != '%c'", *cp, *cp);
+  for (cp = digits; *cp != '\0'; ++cp)
+    if (toupper (*cp) != *cp)
+      FAIL ("toupper ('%c') != '%c'", *cp, *cp);
+  for (cp = cntrl; *cp != '\0'; ++cp)
+    if (toupper (*cp) != *cp)
+      FAIL ("toupper ('\\x%02x') != '\\x%02x'", *cp, *cp);
+
+
+  /* Now some locale specific tests.  */
+  while (! feof (stdin))
+    {
+      unsigned char *inp;
+      unsigned char *resp;
+
+      if (getline (&inpline, &inplinelen, stdin) <= 0
+	  || getline (&resline, &reslinelen, stdin) <= 0)
+	break;
+
+      inp = (unsigned char *) strchr (inpline, '\n');
+      if (inp != NULL)
+	*inp = '\0';
+      resp = (unsigned char *) strchr (resline, '\n');
+      if (resp != NULL)
+	*resp = '\0';
+
+      inp = (unsigned char *) inpline;
+      while (*inp != ' ' && *inp != '\t' && *inp && *inp != '\n'
+	     && *inp != '\0')
+	++inp;
+
+      if (*inp == '\0')
+	{
+	  printf ("line \"%s\" is without content\n", inpline);
+	  continue;
+	}
+      *inp++ = '\0';
+      while (*inp == ' ' || *inp == '\t')
+	++inp;
+
+      /* Try all classes.  */
+      for (n = 0; n < nclasses; ++n)
+	if (strcmp (inpline, classes[n].name) == 0)
+	  break;
+
+      resp = (unsigned char *) resline;
+      while (*resp == ' ' || *resp == '\t')
+	++resp;
+
+      if (strlen ((char *) inp) != strlen ((char *) resp))
+	{
+	  printf ("lines \"%.20s\"... and \"%.20s\" have not the same length\n",
+		  inp, resp);
+	  continue;
+	}
+
+      if (n < nclasses)
+	{
+	  if (strspn ((char *) resp, "01") != strlen ((char *) resp))
+	    {
+	      printf ("result string \"%s\" malformed\n", resp);
+	      continue;
+	    }
+
+	  printf ("  Locale-specific tests for `%s'\n", inpline);
+
+	  while (*inp != '\0' && *inp != '\n')
+	    {
+	      if (((__ctype_b[(unsigned int) *inp] & classes[n].mask) != 0)
+		  != (*resp != '0'))
+		{
+		  printf ("    is%s('%c' = '\\x%02x') %s true\n", inpline,
+			  *inp, *inp, *resp == '1' ? "not" : "is");
+		  ++errors;
+		}
+	      ++inp;
+	      ++resp;
+	    }
+	}
+      else if (strcmp (inpline, "tolower") == 0)
+	{
+	  while (*inp != '\0')
+	    {
+	      if (tolower (*inp) != *resp)
+		{
+		  printf ("    tolower('%c' = '\\x%02x') != '%c'\n",
+			  *inp, *inp, *resp);
+		  ++errors;
+		}
+	      ++inp;
+	      ++resp;
+	    }
+	}
+      else if (strcmp (inpline, "toupper") == 0)
+	{
+	  while (*inp != '\0')
+	    {
+	      if (toupper (*inp) != *resp)
+		{
+		  printf ("    toupper('%c' = '\\x%02x') != '%c'\n",
+			  *inp, *inp, *resp);
+		  ++errors;
+		}
+	      ++inp;
+	      ++resp;
+	    }
+	}
+      else
+	printf ("\"%s\": unknown class or map\n", inpline);
+    }
+
+
+  if (errors != 0)
+    {
+      printf ("  %d error%s for `%s' locale\n\n\n", errors,
+	      errors == 1 ? "" : "s", setlocale (LC_ALL, NULL));
+      return 1;
+    }
+
+  printf ("  No errors for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
+  return 0;
+}

+ 249 - 0
test/locale/tst-digits.c

@@ -0,0 +1,249 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gnu.org>, 2000.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <ctype.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <sys/types.h>
+
+
+#define ZERO  "\xe2\x82\x80"
+#define ONE   "\xe2\x82\x81"
+#define TWO   "\xe2\x82\x82"
+#define THREE "\xe2\x82\x83"
+#define FOUR  "\xe2\x82\x84"
+#define FIVE  "\xe2\x82\x85"
+#define SIX   "\xe2\x82\x86"
+#define SEVEN "\xe2\x82\x87"
+#define EIGHT "\xe2\x82\x88"
+#define NINE  "\xe2\x82\x89"
+
+static struct printf_int_test
+{
+  int n;
+  const char *format;
+  const char *expected;
+} printf_int_tests[] =
+{
+  {       0, "%I'10d", "       " ZERO },
+  {       1, "%I'10d", "       " ONE },
+  {       2, "%I'10d", "       " TWO },
+  {       3, "%I'10d", "       " THREE },
+  {       4, "%I'10d", "       " FOUR },
+  {       5, "%I'10d", "       " FIVE },
+  {       6, "%I'10d", "       " SIX },
+  {       7, "%I'10d", "       " SEVEN },
+  {       8, "%I'10d", "       " EIGHT },
+  {       9, "%I'10d", "       " NINE },
+  {      11, "%I'10d", "    " ONE ONE },
+  {      12, "%I'10d", "    " ONE TWO },
+  {     123, "%I10d",  " " ONE TWO THREE },
+  {     123, "%I'10d", " " ONE TWO THREE },
+  {    1234, "%I10d",  ONE TWO THREE FOUR },
+  {    1234, "%I'10d", ONE "," TWO THREE FOUR },
+  {   12345, "%I'10d", ONE TWO "," THREE FOUR FIVE },
+  {  123456, "%I'10d", ONE TWO THREE "," FOUR FIVE SIX },
+  { 1234567, "%I'10d", ONE "," TWO THREE FOUR "," FIVE SIX SEVEN }
+};
+#define nprintf_int_tests \
+  (sizeof (printf_int_tests) / sizeof (printf_int_tests[0]))
+
+#define WZERO  L"\x2080"
+#define WONE   L"\x2081"
+#define WTWO   L"\x2082"
+#define WTHREE L"\x2083"
+#define WFOUR  L"\x2084"
+#define WFIVE  L"\x2085"
+#define WSIX   L"\x2086"
+#define WSEVEN L"\x2087"
+#define WEIGHT L"\x2088"
+#define WNINE  L"\x2089"
+
+static struct wprintf_int_test
+{
+  int n;
+  const wchar_t *format;
+  const wchar_t *expected;
+} wprintf_int_tests[] =
+{
+  {       0, L"%I'10d", L"         " WZERO },
+  {       1, L"%I'10d", L"         " WONE },
+  {       2, L"%I'10d", L"         " WTWO },
+  {       3, L"%I'10d", L"         " WTHREE },
+  {       4, L"%I'10d", L"         " WFOUR },
+  {       5, L"%I'10d", L"         " WFIVE },
+  {       6, L"%I'10d", L"         " WSIX },
+  {       7, L"%I'10d", L"         " WSEVEN },
+  {       8, L"%I'10d", L"         " WEIGHT },
+  {       9, L"%I'10d", L"         " WNINE },
+  {      11, L"%I'10d", L"        " WONE WONE },
+  {      12, L"%I'10d", L"        " WONE WTWO },
+  {     123, L"%I10d",  L"       " WONE WTWO WTHREE },
+  {     123, L"%I'10d", L"       " WONE WTWO WTHREE },
+  {    1234, L"%I10d",  L"      " WONE WTWO WTHREE WFOUR },
+  {    1234, L"%I'10d", L"     " WONE L"," WTWO WTHREE WFOUR },
+  {   12345, L"%I'10d", L"    " WONE WTWO L"," WTHREE WFOUR WFIVE },
+  {  123456, L"%I'10d", L"   " WONE WTWO WTHREE L"," WFOUR WFIVE WSIX },
+  { 1234567, L"%I'10d", L" " WONE L"," WTWO WTHREE WFOUR L"," WFIVE WSIX WSEVEN }
+};
+#define nwprintf_int_tests \
+  (sizeof (wprintf_int_tests) / sizeof (wprintf_int_tests[0]))
+
+
+int
+main (void)
+{
+  int cnt;
+  int failures;
+  int status;
+
+  if (setlocale (LC_ALL, "test7") == NULL)
+    {
+      puts ("cannot set locale `test7'");
+      exit (1);
+    }
+  printf ("CODESET = \"%s\"\n", nl_langinfo (CODESET));
+
+  /* First: printf tests.  */
+  failures = 0;
+  for (cnt = 0; cnt < (int) nprintf_int_tests; ++cnt)
+    {
+      char buf[100];
+      ssize_t n;
+
+      n = snprintf (buf, sizeof buf, printf_int_tests[cnt].format,
+		    printf_int_tests[cnt].n);
+
+      printf ("%3d: got \"%s\", expected \"%s\"",
+	      cnt, buf, printf_int_tests[cnt].expected);
+
+      if (n != (ssize_t) strlen (printf_int_tests[cnt].expected)
+	  || strcmp (buf, printf_int_tests[cnt].expected) != 0)
+	{
+	  puts ("  -> FAILED");
+	  ++failures;
+	}
+      else
+	puts ("  -> OK");
+    }
+
+  printf ("%d failures in printf tests\n", failures);
+  status = failures != 0;
+
+  /* wprintf tests.  */
+  failures = 0;
+  for (cnt = 0; cnt < (int) nwprintf_int_tests; ++cnt)
+    {
+      wchar_t buf[100];
+      ssize_t n;
+
+      n = swprintf (buf, sizeof buf / sizeof (buf[0]),
+		    wprintf_int_tests[cnt].format,
+		    wprintf_int_tests[cnt].n);
+
+      printf ("%3d: got \"%ls\", expected \"%ls\"",
+	      cnt, buf, wprintf_int_tests[cnt].expected);
+
+      if (n != (ssize_t) wcslen (wprintf_int_tests[cnt].expected)
+	  || wcscmp (buf, wprintf_int_tests[cnt].expected) != 0)
+	{
+	  puts ("  -> FAILED");
+	  ++failures;
+	}
+      else
+	puts ("  -> OK");
+    }
+
+  printf ("%d failures in wprintf tests\n", failures);
+  status = failures != 0;
+
+  /* ctype tests.  This makes sure that the multibyte chracter digit
+     representations are not handle in this table.  */
+  failures = 0;
+  for (cnt = 0; cnt < 256; ++cnt)
+    if (cnt >= '0' && cnt <= '9')
+      {
+	if (! isdigit (cnt))
+	  {
+	    printf ("isdigit ('%c') == 0\n", cnt);
+	    ++failures;
+	  }
+      }
+    else
+      {
+	if (isdigit (cnt))
+	  {
+	    printf ("isdigit (%d) != 0\n", cnt);
+	    ++failures;
+	  }
+      }
+
+  printf ("%d failures in ctype tests\n", failures);
+  status = failures != 0;
+
+  /* wctype tests.  This makes sure the second set of digits is also
+     recorded.  */
+  failures = 0;
+  for (cnt = 0; cnt < 256; ++cnt)
+    if (cnt >= '0' && cnt <= '9')
+      {
+	if (! iswdigit (cnt))
+	  {
+	    printf ("iswdigit (L'%c') == 0\n", cnt);
+	    ++failures;
+	  }
+      }
+    else
+      {
+	if (iswdigit (cnt))
+	  {
+	    printf ("iswdigit (%d) != 0\n", cnt);
+	    ++failures;
+	  }
+      }
+
+  for (cnt = 0x2070; cnt < 0x2090; ++cnt)
+    if (cnt >= 0x2080 && cnt <= 0x2089)
+      {
+	if (! iswdigit (cnt))
+	  {
+	    printf ("iswdigit (U%04X) == 0\n", cnt);
+	    ++failures;
+	  }
+      }
+    else
+      {
+	if (iswdigit (cnt))
+	  {
+	    printf ("iswdigit (U%04X) != 0\n", cnt);
+	    ++failures;
+	  }
+      }
+
+  printf ("%d failures in wctype tests\n", failures);
+  status = failures != 0;
+
+  return status;
+}

+ 68 - 0
test/locale/tst-fmon.c

@@ -0,0 +1,68 @@
+/* Testing the implementation of strfmon(3).
+   Copyright (C) 1996, 1997, 2000, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jochen Hein <jochen.hein@delphi.central.de>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <locale.h>
+#include <monetary.h>
+#include <string.h>
+#include <stdlib.h>
+
+/*
+  test-strfmon gets called with three parameters:
+   - the locale
+   - the format-string to be used
+   - the actual number to be formatted
+   - the expected string
+   If the test passes, test-strfmon terminates with returncode 0,
+   otherwise with 1
+*/
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+#define EXIT_SETLOCALE 2
+#define EXIT_STRFMON 3
+
+int
+main (int argc, char *argv[])
+{
+  char *s = malloc (201);
+
+  if (setlocale (LC_MONETARY, argv[1]) == NULL)
+    {
+      fprintf (stderr, "setlocale(LC_MONETARY, \"%s\"): %m\n", argv[1]);
+      exit (EXIT_SETLOCALE);
+    }
+
+  if (strfmon (s, 200, argv[2], (double) atof (argv[3])) == -1)
+    {
+      perror ("strfmon");
+      exit (EXIT_STRFMON);
+    }
+
+  if (strcmp (s, argv[4]) != 0)
+    {
+      printf ("\
+Locale: \"%s\" Format: \"%s\" Value: \"%s\" Received: \"%s\" Expected: \"%s\" => %s\n",
+	      argv[1], argv[2], argv[3], s, argv[4],
+	      strcmp (s, argv[4]) != 0 ? "false" : "correct");
+      exit (EXIT_FAILURE);
+    }
+
+  return EXIT_SUCCESS;
+}

+ 284 - 0
test/locale/tst-langinfo.c

@@ -0,0 +1,284 @@
+/* Test program for nl_langinfo() function.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <langinfo.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+
+
+struct map
+{
+  const char *str;
+  int val;
+} map[] =
+{
+#define VAL(name) { #name, name }
+  VAL (ABDAY_1),
+  VAL (ABDAY_2),
+  VAL (ABDAY_3),
+  VAL (ABDAY_4),
+  VAL (ABDAY_5),
+  VAL (ABDAY_6),
+  VAL (ABDAY_7),
+  VAL (ABMON_1),
+  VAL (ABMON_10),
+  VAL (ABMON_11),
+  VAL (ABMON_12),
+  VAL (ABMON_2),
+  VAL (ABMON_3),
+  VAL (ABMON_4),
+  VAL (ABMON_5),
+  VAL (ABMON_6),
+  VAL (ABMON_7),
+  VAL (ABMON_8),
+  VAL (ABMON_9),
+  VAL (ALT_DIGITS),
+  VAL (AM_STR),
+  VAL (CRNCYSTR),
+  VAL (CURRENCY_SYMBOL),
+  VAL (DAY_1),
+  VAL (DAY_2),
+  VAL (DAY_3),
+  VAL (DAY_4),
+  VAL (DAY_5),
+  VAL (DAY_6),
+  VAL (DAY_7),
+  VAL (DECIMAL_POINT),
+  VAL (D_FMT),
+  VAL (D_T_FMT),
+  VAL (ERA),
+  VAL (ERA_D_FMT),
+  VAL (ERA_D_T_FMT),
+  VAL (ERA_T_FMT),
+  VAL (ERA_YEAR),
+  VAL (FRAC_DIGITS),
+  VAL (GROUPING),
+  VAL (INT_CURR_SYMBOL),
+  VAL (INT_FRAC_DIGITS),
+  VAL (MON_1),
+  VAL (MON_10),
+  VAL (MON_11),
+  VAL (MON_12),
+  VAL (MON_2),
+  VAL (MON_3),
+  VAL (MON_4),
+  VAL (MON_5),
+  VAL (MON_6),
+  VAL (MON_7),
+  VAL (MON_8),
+  VAL (MON_9),
+  VAL (MON_DECIMAL_POINT),
+  VAL (MON_GROUPING),
+  VAL (MON_THOUSANDS_SEP),
+  VAL (NEGATIVE_SIGN),
+  VAL (NOEXPR),
+  VAL (NOSTR),
+  VAL (N_CS_PRECEDES),
+  VAL (N_SEP_BY_SPACE),
+  VAL (N_SIGN_POSN),
+  VAL (PM_STR),
+  VAL (POSITIVE_SIGN),
+  VAL (P_CS_PRECEDES),
+  VAL (P_SEP_BY_SPACE),
+  VAL (P_SIGN_POSN),
+  VAL (RADIXCHAR),
+  VAL (THOUSANDS_SEP),
+  VAL (THOUSEP),
+  VAL (T_FMT),
+  VAL (T_FMT_AMPM),
+  VAL (YESEXPR),
+  VAL (YESSTR)
+};
+
+
+static int
+map_paramstr (const char *str)
+{
+  int low = 0;
+  int high = sizeof (map) / sizeof (map[0]);
+
+  while (low < high)
+    {
+      int med = (low + high) / 2;
+      int cmpres;
+
+      cmpres = strcmp (str, map[med].str);
+      if (cmpres == 0)
+	return map[med].val;
+      else if (cmpres > 0)
+	low = med + 1;
+      else
+	high = med;
+    }
+
+  return -1;
+}
+
+
+#ifdef DEBUG
+# define REASON(str) printf ("\"%s\" ignored: %s\n", buf, str)
+#else
+# define REASON(str)
+#endif
+
+int
+main (void)
+{
+  int result = 0;
+
+  while (! feof (stdin))
+    {
+      char buf[1000];
+      char *rp;
+      char *locale;
+      char *paramstr;
+      char *expected;
+      char *actual;
+      int param;
+
+      if (fgets (buf, sizeof (buf), stdin) == NULL)
+	break;
+
+      /* Split the fields.   There are three is them:
+	 1. locale
+	 2. langinfo() parameter
+	 3. expected result; this can be a string with white space etc.
+      */
+      rp = buf;
+      while (*rp == ' ' || *rp == '\t')
+	++rp;
+
+      if  (*rp == '#')
+	{
+	  /* It's a comment line.  Ignore it.  */
+	  REASON ("comment");
+	  continue;
+	}
+      locale = rp;
+
+      while (*rp != '\0' && *rp != ' ' && *rp != '\t' && *rp != '\n')
+	++rp;
+      if (*rp == '\0' || *rp == '\n')
+	{
+	  /* Incomplete line.  */
+	  REASON ("incomplete line");
+	  continue;
+	}
+      *rp++ = '\0';
+
+      while (*rp == ' ' || *rp == '\t')
+	++rp;
+      paramstr = rp;
+
+      while (*rp != '\0' && *rp != ' ' && *rp != '\t' && *rp != '\n')
+	++rp;
+      if (*rp == '\0' || *rp == '\n')
+	{
+	  /* Incomplete line.  */
+	  REASON ("incomplete line");
+	  continue;
+	}
+      *rp++ = '\0';
+
+      while (*rp == ' ' || *rp == '\t')
+	++rp;
+
+      if (*rp == '"')
+	{
+	  char *wp;
+
+	  expected = wp = ++rp;
+	  while (*rp != '"' && *rp != '\n' && *rp != '\0')
+	    {
+	      if (*rp == '\\')
+		{
+		  ++rp;
+		  if (*rp == '\0')
+		    break;
+		  if (*rp >= '0' && *rp <= '9')
+		    {
+		      int val = *rp - '0';
+		      if (rp[1] >= '0' && rp[1] <= '9')
+			{
+			  ++rp;
+			  val *= 10;
+			  val += *rp - '0';
+			  if (rp[1] >= '0' && rp[1] <= '9')
+			    {
+			      ++rp;
+			      val *= 10;
+			      val += *rp - '0';
+			    }
+			}
+		      *rp = val;
+		    }
+		}
+	      *wp++ = *rp++;
+	    }
+
+	  if (*rp != '"')
+	    {
+	      REASON ("missing '\"'");
+	      continue;
+	    }
+
+	  *wp = '\0';
+	}
+      else
+	{
+	  expected = rp;
+	  while (*rp != '\0' && *rp != '\n')
+	    ++rp;
+	  *rp = '\0';
+	}
+
+      param = map_paramstr (paramstr);
+      if (param == -1)
+	{
+	  /* Invalid parameter.  */
+	  REASON ("invalid parameter");
+	  continue;
+	}
+
+      /* Set the locale and check whether it worked.  */
+      printf ("LC_ALL=%s nl_langinfo(%s)", locale, paramstr);
+      setlocale (LC_ALL, locale);
+      if (strcmp (locale, setlocale (LC_ALL, NULL)) != 0)
+	{
+	  puts (": failed to set locale");
+	  result = 1;
+	  continue;
+	}
+
+      actual = nl_langinfo (param);
+      printf (" = \"%s\", ", actual);
+
+      if (strcmp (actual, expected) == 0)
+	puts ("OK");
+      else
+	{
+	  printf ("FAILED (expected: %s)\n", expected);
+	  result = 1;
+	}
+    }
+
+  return result;
+}

+ 303 - 0
test/locale/tst-langinfo.input

@@ -0,0 +1,303 @@
+#! /bin/sh
+# Input file for tst-langinfo.
+# Copyright (C) 2000, 2001, 2003 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 Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 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
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+
+# Run the test program.
+# Only decimal numerical escape sequences allowed in strings.
+C                    ABDAY_1     Sun
+C                    ABDAY_2     Mon
+C                    ABDAY_3     Tue
+C                    ABDAY_4     Wed
+C                    ABDAY_5     Thu
+C                    ABDAY_6     Fri
+C                    ABDAY_7     Sat
+C                    DAY_1       Sunday
+C                    DAY_2       Monday
+C                    DAY_3       Tuesday
+C                    DAY_4       Wednesday
+C                    DAY_5       Thursday
+C                    DAY_6       Friday
+C                    DAY_7       Saturday
+C                    ABMON_1     Jan
+C                    ABMON_2     Feb
+C                    ABMON_3     Mar
+C                    ABMON_4     Apr
+C                    ABMON_5     May
+C                    ABMON_6     Jun
+C                    ABMON_7     Jul
+C                    ABMON_8     Aug
+C                    ABMON_9     Sep
+C                    ABMON_10    Oct
+C                    ABMON_11    Nov
+C                    ABMON_12    Dec
+C                    MON_1       January
+C                    MON_2       February
+C                    MON_3       March
+C                    MON_4       April
+C                    MON_5       May
+C                    MON_6       June
+C                    MON_7       July
+C                    MON_8       August
+C                    MON_9       September
+C                    MON_10      October
+C                    MON_11      November
+C                    MON_12      December
+C                    AM_STR      AM
+C                    PM_STR      PM
+C                    D_T_FMT     "%a %b %e %H:%M:%S %Y"
+C                    D_FMT       "%m/%d/%y"
+C                    T_FMT       "%H:%M:%S"
+C                    T_FMT_AMPM  "%I:%M:%S %p"
+C                    ABDAY_1     Sun
+C                    ABDAY_2     Mon
+C                    ABDAY_3     Tue
+C                    ABDAY_4     Wed
+C                    ABDAY_5     Thu
+C                    ABDAY_6     Fri
+C                    ABDAY_7     Sat
+C                    DAY_1       Sunday
+C                    DAY_2       Monday
+C                    DAY_3       Tuesday
+C                    DAY_4       Wednesday
+C                    DAY_5       Thursday
+C                    DAY_6       Friday
+C                    DAY_7       Saturday
+C                    RADIXCHAR   .
+C                    THOUSEP     ""
+C                    YESEXPR     ^[yY]
+C                    NOEXPR      ^[nN]
+en_US.ISO-8859-1     ABMON_1     Jan
+en_US.ISO-8859-1     ABMON_2     Feb
+en_US.ISO-8859-1     ABMON_3     Mar
+en_US.ISO-8859-1     ABMON_4     Apr
+en_US.ISO-8859-1     ABMON_5     May
+en_US.ISO-8859-1     ABMON_6     Jun
+en_US.ISO-8859-1     ABMON_7     Jul
+en_US.ISO-8859-1     ABMON_8     Aug
+en_US.ISO-8859-1     ABMON_9     Sep
+en_US.ISO-8859-1     ABMON_10    Oct
+en_US.ISO-8859-1     ABMON_11    Nov
+en_US.ISO-8859-1     ABMON_12    Dec
+en_US.ISO-8859-1     MON_1       January
+en_US.ISO-8859-1     MON_2       February
+en_US.ISO-8859-1     MON_3       March
+en_US.ISO-8859-1     MON_4       April
+en_US.ISO-8859-1     MON_5       May
+en_US.ISO-8859-1     MON_6       June
+en_US.ISO-8859-1     MON_7       July
+en_US.ISO-8859-1     MON_8       August
+en_US.ISO-8859-1     MON_9       September
+en_US.ISO-8859-1     MON_10      October
+en_US.ISO-8859-1     MON_11      November
+en_US.ISO-8859-1     MON_12      December
+en_US.ISO-8859-1     AM_STR      AM
+en_US.ISO-8859-1     PM_STR      PM
+en_US.ISO-8859-1     D_T_FMT     "%a %d %b %Y %r %Z"
+en_US.ISO-8859-1     D_FMT       "%m/%d/%Y"
+en_US.ISO-8859-1     T_FMT       "%r"
+en_US.ISO-8859-1     T_FMT_AMPM  "%I:%M:%S %p"
+en_US.ISO-8859-1     RADIXCHAR   .
+en_US.ISO-8859-1     THOUSEP     ,
+en_US.ISO-8859-1     YESEXPR     ^[yY].*
+en_US.ISO-8859-1     NOEXPR      ^[nN].*
+de_DE.ISO-8859-1     ABDAY_1     So
+de_DE.ISO-8859-1     ABDAY_2     Mo
+de_DE.ISO-8859-1     ABDAY_3     Di
+de_DE.ISO-8859-1     ABDAY_4     Mi
+de_DE.ISO-8859-1     ABDAY_5     Do
+de_DE.ISO-8859-1     ABDAY_6     Fr
+de_DE.ISO-8859-1     ABDAY_7     Sa
+de_DE.ISO-8859-1     DAY_1       Sonntag
+de_DE.ISO-8859-1     DAY_2       Montag
+de_DE.ISO-8859-1     DAY_3       Dienstag
+de_DE.ISO-8859-1     DAY_4       Mittwoch
+de_DE.ISO-8859-1     DAY_5       Donnerstag
+de_DE.ISO-8859-1     DAY_6       Freitag
+de_DE.ISO-8859-1     DAY_7       Samstag
+de_DE.ISO-8859-1     ABMON_1     Jan
+de_DE.ISO-8859-1     ABMON_2     Feb
+de_DE.ISO-8859-1     ABMON_3     Mär
+de_DE.ISO-8859-1     ABMON_4     Apr
+de_DE.ISO-8859-1     ABMON_5     Mai
+de_DE.ISO-8859-1     ABMON_6     Jun
+de_DE.ISO-8859-1     ABMON_7     Jul
+de_DE.ISO-8859-1     ABMON_8     Aug
+de_DE.ISO-8859-1     ABMON_9     Sep
+de_DE.ISO-8859-1     ABMON_10    Okt
+de_DE.ISO-8859-1     ABMON_11    Nov
+de_DE.ISO-8859-1     ABMON_12    Dez
+de_DE.ISO-8859-1     MON_1       Januar
+de_DE.ISO-8859-1     MON_2       Februar
+de_DE.ISO-8859-1     MON_3       März
+de_DE.ISO-8859-1     MON_4       April
+de_DE.ISO-8859-1     MON_5       Mai
+de_DE.ISO-8859-1     MON_6       Juni
+de_DE.ISO-8859-1     MON_7       Juli
+de_DE.ISO-8859-1     MON_8       August
+de_DE.ISO-8859-1     MON_9       September
+de_DE.ISO-8859-1     MON_10      Oktober
+de_DE.ISO-8859-1     MON_11      November
+de_DE.ISO-8859-1     MON_12      Dezember
+de_DE.ISO-8859-1     D_T_FMT     "%a %d %b %Y %T %Z"
+de_DE.ISO-8859-1     D_FMT       "%d.%m.%Y"
+de_DE.ISO-8859-1     T_FMT       "%T"
+de_DE.ISO-8859-1     RADIXCHAR   ,
+de_DE.ISO-8859-1     THOUSEP     .
+de_DE.ISO-8859-1     YESEXPR     ^[jJyY].*
+de_DE.ISO-8859-1     NOEXPR      ^[nN].*
+de_DE.UTF-8          ABDAY_1     So
+de_DE.UTF-8          ABDAY_2     Mo
+de_DE.UTF-8          ABDAY_3     Di
+de_DE.UTF-8          ABDAY_4     Mi
+de_DE.UTF-8          ABDAY_5     Do
+de_DE.UTF-8          ABDAY_6     Fr
+de_DE.UTF-8          ABDAY_7     Sa
+de_DE.UTF-8          DAY_1       Sonntag
+de_DE.UTF-8          DAY_2       Montag
+de_DE.UTF-8          DAY_3       Dienstag
+de_DE.UTF-8          DAY_4       Mittwoch
+de_DE.UTF-8          DAY_5       Donnerstag
+de_DE.UTF-8          DAY_6       Freitag
+de_DE.UTF-8          DAY_7       Samstag
+de_DE.UTF-8          ABMON_1     Jan
+de_DE.UTF-8          ABMON_2     Feb
+de_DE.UTF-8          ABMON_3     Mär
+de_DE.UTF-8          ABMON_4     Apr
+de_DE.UTF-8          ABMON_5     Mai
+de_DE.UTF-8          ABMON_6     Jun
+de_DE.UTF-8          ABMON_7     Jul
+de_DE.UTF-8          ABMON_8     Aug
+de_DE.UTF-8          ABMON_9     Sep
+de_DE.UTF-8          ABMON_10    Okt
+de_DE.UTF-8          ABMON_11    Nov
+de_DE.UTF-8          ABMON_12    Dez
+de_DE.UTF-8          MON_1       Januar
+de_DE.UTF-8          MON_2       Februar
+de_DE.UTF-8          MON_3       März
+de_DE.UTF-8          MON_4       April
+de_DE.UTF-8          MON_5       Mai
+de_DE.UTF-8          MON_6       Juni
+de_DE.UTF-8          MON_7       Juli
+de_DE.UTF-8          MON_8       August
+de_DE.UTF-8          MON_9       September
+de_DE.UTF-8          MON_10      Oktober
+de_DE.UTF-8          MON_11      November
+de_DE.UTF-8          MON_12      Dezember
+de_DE.UTF-8          D_T_FMT     "%a %d %b %Y %T %Z"
+de_DE.UTF-8          D_FMT       "%d.%m.%Y"
+de_DE.UTF-8          T_FMT       "%T"
+de_DE.UTF-8          RADIXCHAR   ,
+de_DE.UTF-8          THOUSEP     .
+de_DE.UTF-8          YESEXPR     ^[jJyY].*
+de_DE.UTF-8          NOEXPR      ^[nN].*
+fr_FR.ISO-8859-1     ABDAY_1     dim
+fr_FR.ISO-8859-1     ABDAY_2     lun
+fr_FR.ISO-8859-1     ABDAY_3     mar
+fr_FR.ISO-8859-1     ABDAY_4     mer
+fr_FR.ISO-8859-1     ABDAY_5     jeu
+fr_FR.ISO-8859-1     ABDAY_6     ven
+fr_FR.ISO-8859-1     ABDAY_7     sam
+fr_FR.ISO-8859-1     DAY_1       dimanche
+fr_FR.ISO-8859-1     DAY_2       lundi
+fr_FR.ISO-8859-1     DAY_3       mardi
+fr_FR.ISO-8859-1     DAY_4       mercredi
+fr_FR.ISO-8859-1     DAY_5       jeudi
+fr_FR.ISO-8859-1     DAY_6       vendredi
+fr_FR.ISO-8859-1     DAY_7       samedi
+fr_FR.ISO-8859-1     ABMON_1     jan
+fr_FR.ISO-8859-1     ABMON_2     fév
+fr_FR.ISO-8859-1     ABMON_3     mar
+fr_FR.ISO-8859-1     ABMON_4     avr
+fr_FR.ISO-8859-1     ABMON_5     mai
+fr_FR.ISO-8859-1     ABMON_6     jun
+fr_FR.ISO-8859-1     ABMON_7     jui
+fr_FR.ISO-8859-1     ABMON_8     aoû
+fr_FR.ISO-8859-1     ABMON_9     sep
+fr_FR.ISO-8859-1     ABMON_10    oct
+fr_FR.ISO-8859-1     ABMON_11    nov
+fr_FR.ISO-8859-1     ABMON_12    déc
+fr_FR.ISO-8859-1     MON_1       janvier
+fr_FR.ISO-8859-1     MON_2       février
+fr_FR.ISO-8859-1     MON_3       mars
+fr_FR.ISO-8859-1     MON_4       avril
+fr_FR.ISO-8859-1     MON_5       mai
+fr_FR.ISO-8859-1     MON_6       juin
+fr_FR.ISO-8859-1     MON_7       juillet
+fr_FR.ISO-8859-1     MON_8       août
+fr_FR.ISO-8859-1     MON_9       septembre
+fr_FR.ISO-8859-1     MON_10      octobre
+fr_FR.ISO-8859-1     MON_11      novembre
+fr_FR.ISO-8859-1     MON_12      décembre
+fr_FR.ISO-8859-1     D_T_FMT     "%a %d %b %Y %T %Z"
+fr_FR.ISO-8859-1     D_FMT       "%d.%m.%Y"
+fr_FR.ISO-8859-1     T_FMT       "%T"
+fr_FR.ISO-8859-1     RADIXCHAR   ,
+fr_FR.ISO-8859-1     THOUSEP     ""
+fr_FR.ISO-8859-1     YESEXPR     ^[oOyY].*
+fr_FR.ISO-8859-1     NOEXPR      ^[nN].*
+ja_JP.EUC-JP         ABDAY_1     Æü
+ja_JP.EUC-JP         ABDAY_2     ·î
+ja_JP.EUC-JP         ABDAY_3     ²Ð
+ja_JP.EUC-JP         ABDAY_4     ¿å
+ja_JP.EUC-JP         ABDAY_5     ÌÚ
+ja_JP.EUC-JP         ABDAY_6     ¶â
+ja_JP.EUC-JP         ABDAY_7     ÅÚ
+ja_JP.EUC-JP         DAY_1       ÆüÍËÆü
+ja_JP.EUC-JP         DAY_2       ·îÍËÆü
+ja_JP.EUC-JP         DAY_3       ²ÐÍËÆü
+ja_JP.EUC-JP         DAY_4       ¿åÍËÆü
+ja_JP.EUC-JP         DAY_5       ÌÚÍËÆü
+ja_JP.EUC-JP         DAY_6       ¶âÍËÆü
+ja_JP.EUC-JP         DAY_7       ÅÚÍËÆü
+ja_JP.EUC-JP         ABMON_1     " 1·î"
+ja_JP.EUC-JP         ABMON_2     " 2·î"
+ja_JP.EUC-JP         ABMON_3     " 3·î"
+ja_JP.EUC-JP         ABMON_4     " 4·î"
+ja_JP.EUC-JP         ABMON_5     " 5·î"
+ja_JP.EUC-JP         ABMON_6     " 6·î"
+ja_JP.EUC-JP         ABMON_7     " 7·î"
+ja_JP.EUC-JP         ABMON_8     " 8·î"
+ja_JP.EUC-JP         ABMON_9     " 9·î"
+ja_JP.EUC-JP         ABMON_10    "10·î"
+ja_JP.EUC-JP         ABMON_11    "11·î"
+ja_JP.EUC-JP         ABMON_12    "12·î"
+ja_JP.EUC-JP         MON_1       "1·î"
+ja_JP.EUC-JP         MON_2       "2·î"
+ja_JP.EUC-JP         MON_3       "3·î"
+ja_JP.EUC-JP         MON_4       "4·î"
+ja_JP.EUC-JP         MON_5       "5·î"
+ja_JP.EUC-JP         MON_6       "6·î"
+ja_JP.EUC-JP         MON_7       "7·î"
+ja_JP.EUC-JP         MON_8       "8·î"
+ja_JP.EUC-JP         MON_9       "9·î"
+ja_JP.EUC-JP         MON_10      "10·î"
+ja_JP.EUC-JP         MON_11      "11·î"
+ja_JP.EUC-JP         MON_12      "12·î"
+ja_JP.EUC-JP         T_FMT_AMPM  "%p%I»þ%Mʬ%SÉÃ"
+ja_JP.EUC-JP         ERA_D_FMT   "%EY%m·î%dÆü"
+ja_JP.EUC-JP         ERA_D_T_FMT "%EY%m·î%dÆü %H»þ%Mʬ%SÉÃ"
+ja_JP.EUC-JP         RADIXCHAR   .
+ja_JP.EUC-JP         THOUSEP     ,
+ja_JP.EUC-JP         YESEXPR     ^([yY£ù£Ù]|¤Ï¤¤|¥Ï¥¤)
+ja_JP.EUC-JP         NOEXPR      ^([nN£î£Î]|¤¤¤¤¤¨|¥¤¥¤¥¨)
+# Is CRNCYSTR supposed to be the national or international sign?
+# ja_JP.EUC-JP         CRNCYSTR    JPY
+ja_JP.EUC-JP         CODESET     EUC-JP

+ 18 - 0
test/locale/tst-leaks.c

@@ -0,0 +1,18 @@
+#include <locale.h>
+#include <mcheck.h>
+
+int
+main (void)
+{
+  int cnt;
+
+  mtrace ();
+
+  for (cnt = 0; cnt < 100; ++cnt)
+    {
+      setlocale (LC_ALL, "de_DE.ISO-8859-1");
+      setlocale (LC_ALL, "de_DE.UTF-8");
+    }
+
+  return 0;
+}

+ 63 - 0
test/locale/tst-mbswcs1.c

@@ -0,0 +1,63 @@
+/* Test restarting behaviour of mbrtowc.
+   Copyright (C) 2000, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Bruno Haible <haible@ilog.fr>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <locale.h>
+
+#define show(expr, nexp, wcexp) \
+  n = expr;								  \
+  printf (#expr " -> %Zd", n);						  \
+  printf (", wc = %lu", (unsigned long int) wc);			  \
+  if (n != (size_t) nexp || wc != wcexp)				  \
+    {									  \
+      printf (", expected %Zd and %lu", nexp, (unsigned long int) wcexp); \
+      result = 1;							  \
+    }									  \
+  putc ('\n', stdout)
+
+int
+main (void)
+{
+  const unsigned char buf[6] = { 0x25,  0xe2, 0x82, 0xac,  0xce, 0xbb };
+  mbstate_t state;
+  wchar_t wc = 42;
+  size_t n;
+  int result = 0;
+  const char *used_locale;
+
+  setlocale (LC_CTYPE, "de_DE.UTF-8");
+  /* Double check.  */
+  used_locale = setlocale (LC_CTYPE, NULL);
+  printf ("used locale: \"%s\"\n", used_locale);
+  result = strcmp (used_locale, "de_DE.UTF-8");
+
+  memset (&state, '\0', sizeof (state));
+
+  show (mbrtowc (&wc, (const char *) buf + 0, 1, &state), 1, 37);
+  show (mbrtowc (&wc, (const char *) buf + 1, 1, &state), -2, 37);
+  show (mbrtowc (&wc, (const char *) buf + 2, 3, &state), 2, 8364);
+  show (mbrtowc (&wc, (const char *) buf + 4, 1, &state), -2, 8364);
+  show (mbrtowc (&wc, (const char *) buf + 5, 1, &state), 1, 955);
+  show (mbrtowc (&wc, (const char *) buf + 5, 1, &state), -1, 955);
+
+  return result;
+}

+ 65 - 0
test/locale/tst-mbswcs2.c

@@ -0,0 +1,65 @@
+/* Test restarting behaviour of mbsnrtowcs.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Bruno Haible <haible@ilog.fr>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <locale.h>
+
+#define show(expr, nexp, wcexp, end) \
+  n = expr;								\
+  printf (#expr " -> %Zd", n);						\
+  printf (", wc = %lu, src = buf+%d", (unsigned long int) wc,		\
+	  src - (const char *) buf);					\
+  if (n != (size_t) nexp || wc != wcexp || src != (const char *) (end))	\
+    {									\
+      printf (", expected %Zd and %lu and buf+%d", nexp,		\
+	      (unsigned long int) wcexp, (end) - buf);			\
+      result = 1;							\
+    }									\
+  putc ('\n', stdout)
+
+int
+main (void)
+{
+  unsigned char buf[6] = { 0x25,  0xe2, 0x82, 0xac,  0xce, 0xbb };
+  mbstate_t state;
+  const char *src;
+  wchar_t wc = 42;
+  size_t n;
+  int result = 0;
+  const char *used_locale;
+
+  setlocale (LC_CTYPE,"de_DE.UTF-8");
+  /* Double check.  */
+  used_locale = setlocale (LC_CTYPE, NULL);
+  printf ("used locale: \"%s\"\n", used_locale);
+  result = strcmp (used_locale, "de_DE.UTF-8");
+
+  memset (&state, '\0', sizeof (state));
+
+  src = (const char *) buf;
+  show (mbsnrtowcs (&wc, &src, 1, 1, &state), 1, 37, buf + 1);
+  show (mbsnrtowcs (&wc, &src, 3, 1, &state), 1, 8364, buf + 4);
+  show (mbsnrtowcs (&wc, &src, 1, 1, &state), 0, 8364, buf + 5);
+  show (mbsnrtowcs (&wc, &src, 1, 1, &state), 1, 955, buf + 6);
+
+  return result;
+}

+ 76 - 0
test/locale/tst-mbswcs3.c

@@ -0,0 +1,76 @@
+/* Test restarting behaviour of wcsrtombs.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Bruno Haible <haible@ilog.fr>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <locale.h>
+
+#define show(expr, nexp, srcexp, bufexp) \
+  {									\
+    size_t res = expr;							\
+    printf (#expr " -> %Zd", res);					\
+    dst += res;								\
+    printf (", src = srcbuf+%td, dst = buf+%td",			\
+	    src - srcbuf, dst - (char *) buf);				\
+    if (res != nexp || src != (srcexp) || dst != (char *) (bufexp))	\
+      {									\
+	printf (", expected %Zd and srcbuf+%td and buf+%td", nexp,	\
+		(srcexp) - srcbuf, (bufexp) - (unsigned char *) buf);	\
+	result = 1;							\
+      }									\
+    putc ('\n', stdout);						\
+  }
+
+int
+main (void)
+{
+  unsigned char buf[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+  const unsigned char bufcheck[6] = { 0x25, 0xe2, 0x82, 0xac, 0xce, 0xbb };
+  const wchar_t srcbuf[4] = { 0x25, 0x20ac, 0x03bb, 0 };
+  mbstate_t state;
+  const wchar_t *src;
+  char *dst;
+  int result = 0;
+  const char *used_locale;
+
+  setlocale (LC_CTYPE, "de_DE.UTF-8");
+  /* Double check.  */
+  used_locale = setlocale (LC_CTYPE, NULL);
+  printf ("used locale: \"%s\"\n", used_locale);
+  result = strcmp (used_locale, "de_DE.UTF-8");
+
+  memset (&state, '\0', sizeof (state));
+
+  src = srcbuf;
+  dst = (char *) buf;
+  show (wcsrtombs (dst, &src, 1, &state), 1, srcbuf + 1, buf + 1);
+  show (wcsrtombs (dst, &src, 1, &state), 0, srcbuf + 1, buf + 1);
+  show (wcsrtombs (dst, &src, 4, &state), 3, srcbuf + 2, buf + 4);
+  show (wcsrtombs (dst, &src, 2, &state), 2, srcbuf + 3, buf + 6);
+
+  if (memcmp (buf, bufcheck, 6))
+    {
+      puts ("wrong results");
+      result = 1;
+    }
+
+  return result;
+}

+ 63 - 0
test/locale/tst-mbswcs4.c

@@ -0,0 +1,63 @@
+/* Test restarting behaviour of mbsrtowcs.
+   Copyright (C) 2000 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 Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <locale.h>
+
+#define show(expr, nexp, wcexp, end) \
+  n = expr;								\
+  printf (#expr " -> %Zd", n);						\
+  printf (", wc = %lu, src = buf+%d", (unsigned long int) wc,		\
+	  src - (const char *) buf);					\
+  if (n != (size_t) nexp || wc != wcexp || src != (const char *) (end))	\
+    {									\
+      printf (", expected %Zd and %lu and buf+%d", nexp,		\
+	      (unsigned long int) wcexp, (end) - buf);			\
+      result = 1;							\
+    }									\
+  putc ('\n', stdout)
+
+int
+main (void)
+{
+  unsigned char buf[6] = { 0x25,  0xe2, 0x82, 0xac,  0xce, 0xbb };
+  mbstate_t state;
+  const char *src;
+  wchar_t wc = 42;
+  size_t n;
+  int result = 0;
+  const char *used_locale;
+
+  setlocale (LC_CTYPE,"de_DE.UTF-8");
+  /* Double check.  */
+  used_locale = setlocale (LC_CTYPE, NULL);
+  printf ("used locale: \"%s\"\n", used_locale);
+  result = strcmp (used_locale, "de_DE.UTF-8");
+
+  memset (&state, '\0', sizeof (state));
+
+  src = (const char *) buf;
+  show (mbsrtowcs (&wc, &src, 1, &state), 1, 37, buf + 1);
+  show (mbsrtowcs (&wc, &src, 1, &state), 1, 8364, buf + 4);
+  show (mbsrtowcs (&wc, &src, 1, &state), 1, 955, buf + 6);
+
+  return result;
+}

+ 75 - 0
test/locale/tst-mbswcs5.c

@@ -0,0 +1,75 @@
+/* Test restarting behaviour of wcrtomb.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Bruno Haible <haible@ilog.fr>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <locale.h>
+
+#define show(expr, nexp, bufexp) \
+  {									\
+    size_t res = expr;							\
+    printf (#expr " -> %Zd", res);					\
+    dst += res;								\
+    printf (", dst = buf+%td", dst - (char *) buf);			\
+    if (res != nexp || dst != (char *) (bufexp))			\
+      {									\
+	printf (", expected %Zd and buf+%td", nexp,			\
+		(bufexp) - (unsigned char *) buf);			\
+	result = 1;							\
+      }									\
+    putc ('\n', stdout);						\
+  }
+
+int
+main (void)
+{
+  unsigned char buf[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+  const unsigned char bufcheck[7] = { 0x25, 0xe2, 0x82, 0xac, 0xce, 0xbb, 0 };
+  const wchar_t srcbuf[4] = { 0x25, 0x20ac, 0x03bb, 0 };
+  mbstate_t state;
+  const wchar_t *src;
+  char *dst;
+  int result = 0;
+  const char *used_locale;
+
+  setlocale (LC_CTYPE, "de_DE.UTF-8");
+  /* Double check.  */
+  used_locale = setlocale (LC_CTYPE, NULL);
+  printf ("used locale: \"%s\"\n", used_locale);
+  result = strcmp (used_locale, "de_DE.UTF-8");
+
+  memset (&state, '\0', sizeof (state));
+
+  src = srcbuf;
+  dst = (char *) buf;
+  show (wcrtomb (dst, *src++, &state), 1, buf + 1);
+  show (wcrtomb (dst, *src++, &state), 3, buf + 4);
+  show (wcrtomb (dst, *src++, &state), 2, buf + 6);
+  show (wcrtomb (dst, *src, &state), 1, buf + 7);
+
+  if (memcmp (buf, bufcheck, 7))
+    {
+      puts ("wrong results");
+      result = 1;
+    }
+
+  return result;
+}

+ 74 - 0
test/locale/tst-mbswcs6.c

@@ -0,0 +1,74 @@
+/* Test for invalid input to wcrtomb.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+
+static int
+do_test (const char *loc)
+{
+  char buf[100];
+  size_t n;
+  mbstate_t state;
+  const char *nloc;
+  int res;
+
+  nloc = setlocale (LC_ALL, loc);
+  if (nloc == NULL)
+    {
+      printf ("could not set locale \"%s\"\n", loc);
+      return 1;
+    }
+  printf ("new locale: %s\n", nloc);
+
+  memset (&state, '\0', sizeof (state));
+  errno = 0;
+  n = wcrtomb (buf, (wchar_t) -15l, &state);
+
+  printf ("n = %zd, errno = %d (%s)\n", n, errno, strerror (errno));
+
+  res = n != (size_t) -1 || errno != EILSEQ;
+  if (res)
+    puts ("*** FAIL");
+  putchar ('\n');
+
+  return res;
+}
+
+
+int
+main (void)
+{
+  int res;
+
+  res = do_test ("C");
+  res |= do_test ("de_DE.ISO-8859-1");
+  res |= do_test ("de_DE.UTF-8");
+  res |= do_test ("en_US.ISO-8859-1");
+  res |= do_test ("ja_JP.UTF-8");
+  res |= do_test ("hr_HR.ISO-8859-2");
+  //res |= do_test ("ru_RU.KOI8-R");
+
+  return res;
+}

+ 74 - 0
test/locale/tst-numeric.c

@@ -0,0 +1,74 @@
+/* Testing the implementation of LC_NUMERIC and snprintf().
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Petter Reinholdtsen <pere@hungry.com>, 2003
+
+   Based on tst-fmon.c by Jochen Hein <jochen.hein@delphi.central.de>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <locale.h>
+#include <string.h>
+#include <stdlib.h>
+
+/*
+  test-numeric gets called with three parameters:
+   - the locale
+   - the format-string to be used
+   - the actual number to be formatted
+   - the expected string
+   If the test passes, test-numeric terminates with returncode 0,
+   otherwise with 1
+*/
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+#define EXIT_SETLOCALE 2
+#define EXIT_SNPRINTF 3
+
+int
+main (int argc, char *argv[])
+{
+  char *s = malloc (201);
+  double val;
+
+  /* Make sure to read the value before setting of the locale, as
+     strtod() is locale-dependent. */
+  val = strtod (argv[3], NULL);
+
+  if (setlocale (LC_ALL, argv[1]) == NULL)
+    {
+      fprintf (stderr, "setlocale(LC_ALL, \"%s\"): %m\n", argv[1]);
+      exit (EXIT_SETLOCALE);
+    }
+
+  if (snprintf (s, 200, argv[2], val) == -1)
+    {
+      perror ("snprintf");
+      exit (EXIT_SNPRINTF);
+    }
+
+  if (strcmp (s, argv[4]) != 0)
+    {
+      printf ("\
+locale: \"%s\", format: \"%s\", expected: \"%s\", got: \"%s\" => %s\n",
+	      argv[1], argv[2], argv[4], s,
+	      strcmp (s, argv[4]) != 0 ? "false" : "correct");
+      exit (EXIT_FAILURE);
+    }
+
+  return EXIT_SUCCESS;
+}

+ 37 - 0
test/locale/tst-rpmatch.c

@@ -0,0 +1,37 @@
+/* Test program for rpmatch function.
+   Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jochen Hein <jochen.hein@delphi.central.de>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (int argc, char* argv[])
+{
+  setlocale (LC_ALL, argv[1]);
+
+  if (rpmatch (argv[2]) != atol (argv[3]))
+    {
+      fprintf (stderr,"Failed: Locale %s, String %s, Exp: %s, got %d\n",
+	       argv[1], argv[2], argv[3], rpmatch (argv[2]));
+      exit (EXIT_FAILURE);
+    }
+  return EXIT_SUCCESS;
+}

+ 25 - 0
test/locale/tst-setlocale.c

@@ -0,0 +1,25 @@
+/* Test case by Jakub Jelinek <jakub@redhat.com>.  */
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+main (void)
+{
+  char q[30];
+  char *s;
+
+  setlocale (LC_ALL, "");
+  printf ("after setlocale (LC_ALL, \"\"): %s\n", setlocale(LC_NUMERIC, NULL));
+
+  strcpy (q, "de_DE.UTF-8");
+  setlocale (LC_NUMERIC, q);
+  printf ("after setlocale (LC_NUMERIC, \"%s\"): %s\n",
+	  q, setlocale(LC_NUMERIC, NULL));
+
+  strcpy (q, "de_DE.ISO-8859-1");
+  s = setlocale (LC_NUMERIC, NULL);
+  printf ("after overwriting string: %s\n", s);
+
+  return strcmp (s, "de_DE.UTF-8") != 0;
+}

+ 56 - 0
test/locale/tst-sscanf.c

@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <locale.h>
+#include <assert.h>
+
+#define P0 "\xDB\xB0"
+#define P1 "\xDB\xB1"
+#define P2 "\xDB\xB2"
+#define P3 "\xDB\xB3"
+#define P4 "\xDB\xB4"
+#define P5 "\xDB\xB5"
+#define P6 "\xDB\xB6"
+#define P7 "\xDB\xB7"
+#define P8 "\xDB\xB8"
+#define P9 "\xDB\xB9"
+#define PD "\xd9\xab"
+#define PT "\xd9\xac"
+
+static int
+check_sscanf (const char *s, const char *format, const float n)
+{
+  float f;
+
+  if (sscanf (s, format, &f) != 1)
+    {
+      printf ("nothing found for \"%s\"\n", s);
+      return 1;
+    }
+  if (f != n)
+    {
+      printf ("got %f expected %f from \"%s\"\n", f, n, s);
+      return 1;
+    }
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  if (setlocale (LC_ALL, "fa_IR.UTF-8") == NULL)
+    {
+      puts ("cannot set fa_IR locale");
+      return 1;
+    }
+
+  int r = check_sscanf (P3 PD P1 P4, "%I8f", 3.14);
+  r |= check_sscanf (P3 PT P1 P4 P5, "%I'f", 3145);
+  r |= check_sscanf (P3 PD P1 P4 P1 P5 P9, "%If", 3.14159);
+  r |= check_sscanf ("-" P3 PD P1 P4 P1 P5, "%If", -3.1415);
+  r |= check_sscanf ("+" PD P1 P4 P1 P5, "%If", +.1415);
+  r |= check_sscanf (P3 PD P1 P4 P1 P5 "e+" P2, "%Ie", 3.1415e+2);
+
+  return r;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 42 - 0
test/locale/tst-strfmon1.c

@@ -0,0 +1,42 @@
+#include <monetary.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+
+static const struct
+{
+  const char *locale;
+  const char *expected;
+} tests[] =
+  {
+    { "de_DE.ISO-8859-1", "|-12,34 EUR|-12,34|" },
+    { "da_DK.ISO-8859-1", "|kr -12,34|-12,34|" },
+    { "zh_TW.EUC-TW", "|-NT$12.34|-12.34|" },
+    { "sv_SE.ISO-8859-1", "|-12,34 kr|-12,34|" }
+  };
+#define ntests (sizeof (tests) / sizeof (tests[0]))
+
+
+static int
+do_test (void)
+{
+  int res = 0;
+  for (int i = 0; i < ntests; ++i)
+    {
+      char buf[500];
+      if (setlocale (LC_ALL, tests[i].locale) == NULL)
+	{
+	  printf ("failed to set locale %s\n", tests[i].locale);
+	  res = 1;
+	  continue;
+	}
+      strfmon (buf, sizeof (buf), "|%n|%!n|", -12.34, -12.34);
+      int fail = strcmp (buf, tests[i].expected) != 0;
+      printf ("%s%s\n", buf, fail ? " *** FAIL ***" : "");
+      res |= fail;
+    }
+  return res;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 71 - 0
test/locale/tst-trans.c

@@ -0,0 +1,71 @@
+/* Test program for user-defined character maps.
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+int
+main (void)
+{
+  char buf[30];
+  wchar_t wbuf[30];
+  wctrans_t t;
+  wint_t wch;
+  int errors = 0;
+  int len;
+
+  setlocale (LC_ALL, "");
+
+  t = wctrans ("test");
+  if (t == (wctrans_t) 0)
+    {
+      puts ("locale data files probably not loaded");
+      exit (1);
+    }
+
+  wch = towctrans (L'A', t);
+  printf ("towctrans (L'A', t) = %c\n", wch);
+  if (wch != L'B')
+    errors = 1;
+
+  wch = towctrans (L'B', t);
+  printf ("towctrans (L'B', t) = %c\n", wch);
+  if (wch != L'C')
+    errors = 1;
+
+  /* Test the output digit handling.  */
+  swprintf (wbuf, sizeof (wbuf) / sizeof (wbuf[0]), L"%Id", 0x499602D2);
+  errors |= wcscmp (wbuf, L"bcdefghija") != 0;
+  len = wcslen (wbuf);
+  errors |= len != 10;
+  printf ("len = %d, wbuf = L\"%ls\"\n", len, wbuf);
+
+  snprintf (buf, sizeof buf, "%Id", 0x499602D2);
+  errors |= strcmp (buf, "bcdefghija") != 0;
+  len = strlen (buf);
+  errors |= len != 10;
+  printf ("len = %d, buf = \"%s\"\n", len, buf);
+
+  return errors;
+}

+ 144 - 0
test/locale/tst-wctype.c

@@ -0,0 +1,144 @@
+/* Test program for iswctype() function in ja_JP locale.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <error.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+
+int
+main (void)
+{
+  wctype_t wct;
+  wchar_t buf[1000];
+  int result = 1;
+
+  setlocale (LC_ALL, "");
+  wprintf (L"locale = %s\n", setlocale (LC_CTYPE, NULL));
+
+  wct = wctype ("jhira");
+  if (wct == 0)
+    error (EXIT_FAILURE, 0, "jhira: no such character class");
+
+  if (fgetws (buf, sizeof (buf) / sizeof (buf[0]), stdin) != NULL)
+    {
+      int n;
+
+      wprintf (L"buf[] = \"%ls\"\n", buf);
+
+      result = 0;
+
+      for (n = 0; buf[n] != L'\0'; ++n)
+	{
+	  wprintf (L"jhira(U%04lx = %lc) = %d\n", (long) buf[n], buf[n],
+		   iswctype (buf[n], wct));
+	  result |= ((buf[n] < 0xff && iswctype (buf[n], wct))
+		     || (buf[n] > 0xff && !iswctype (buf[n], wct)));
+	}
+    }
+
+  wct = wctype ("jkata");
+  if (wct == 0)
+    error (EXIT_FAILURE, 0, "jkata: no such character class");
+
+  if (fgetws (buf, sizeof (buf) / sizeof (buf[0]), stdin) != NULL)
+    {
+      int n;
+
+      wprintf (L"buf[] = \"%ls\"\n", buf);
+
+      result = 0;
+
+      for (n = 0; buf[n] != L'\0'; ++n)
+	{
+	  wprintf (L"jkata(U%04lx = %lc) = %d\n", (long) buf[n], buf[n],
+		   iswctype (buf[n], wct));
+	  result |= ((buf[n] < 0xff && iswctype (buf[n], wct))
+		     || (buf[n] > 0xff && !iswctype (buf[n], wct)));
+	}
+    }
+
+  wct = wctype ("jdigit");
+  if (wct == 0)
+    error (EXIT_FAILURE, 0, "jdigit: no such character class");
+
+  if (fgetws (buf, sizeof (buf) / sizeof (buf[0]), stdin) != NULL)
+    {
+      int n;
+
+      wprintf (L"buf[] = \"%ls\"\n", buf);
+
+      result = 0;
+
+      for (n = 0; buf[n] != L'\0'; ++n)
+	{
+	  wprintf (L"jdigit(U%04lx = %lc) = %d\n", (long) buf[n], buf[n],
+		   iswctype (buf[n], wct));
+	  result |= ((buf[n] < 0xff && iswctype (buf[n], wct))
+		     || (buf[n] > 0xff && !iswctype (buf[n], wct)));
+	}
+    }
+
+  wct = wctype ("jspace");
+  if (wct == 0)
+    error (EXIT_FAILURE, 0, "jspace: no such character class");
+
+  if (fgetws (buf, sizeof (buf) / sizeof (buf[0]), stdin) != NULL)
+    {
+      int n;
+
+      wprintf (L"buf[] = \"%ls\"\n", buf);
+
+      result = 0;
+
+      for (n = 0; buf[n] != L'\0'; ++n)
+	{
+	  wprintf (L"jspace(U%04lx = %lc) = %d\n", (long) buf[n], buf[n],
+		   iswctype (buf[n], wct));
+	  result |= ((buf[n] < 0xff && iswctype (buf[n], wct))
+		     || (buf[n] > 0xff && !iswctype (buf[n], wct)));
+	}
+    }
+
+  wct = wctype ("jkanji");
+  if (wct == 0)
+    error (EXIT_FAILURE, 0, "jkanji: no such character class");
+
+  if (fgetws (buf, sizeof (buf) / sizeof (buf[0]), stdin) != NULL)
+    {
+      int n;
+
+      wprintf (L"buf[] = \"%ls\"\n", buf);
+
+      result = 0;
+
+      for (n = 0; buf[n] != L'\0'; ++n)
+	{
+	  wprintf (L"jkanji(U%04lx = %lc) = %d\n", (long) buf[n], buf[n],
+		   iswctype (buf[n], wct));
+	  result |= ((buf[n] < 0xff && iswctype (buf[n], wct))
+		     || (buf[n] > 0xff && !iswctype (buf[n], wct)));
+	}
+    }
+
+  return result;
+}

+ 75 - 0
test/locale/tst-xlocale1.c

@@ -0,0 +1,75 @@
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static struct
+{
+  const char *locale;
+  const char *str1;
+  const char *str2;
+  int result;
+} tests[] =
+  {
+    { "C", "TRANSLIT", "translit", 0 },
+    { "de_DE.ISO-8859-1", "TRANSLIT", "translit", 0 },
+    { "de_DE.ISO-8859-1", "TRANSLIT", "trÄnslit", -1 },
+    { "de_DE.UTF-8", "TRANSLIT", "translit", 0 },
+    { "de_DE.ISO-8859-1", "ä", "Ä", 1 }
+  };
+#define ntests (sizeof (tests) / sizeof (tests[0]))
+
+
+int
+main (void)
+{
+  size_t cnt;
+  int result = 0;
+  locale_t loc = newlocale (1 << LC_ALL, "C", NULL);
+
+  for (cnt = 0; cnt < ntests; ++cnt)
+    {
+      int r;
+
+      if (setlocale (LC_ALL, tests[cnt].locale) == NULL)
+	{
+	  printf ("cannot set locale \"%s\": %m\n", tests[cnt].locale);
+	  result = 1;
+	  continue;
+	}
+
+      printf ("\nstrcasecmp_l (\"%s\", \"%s\", loc)\n",
+	      tests[cnt].str1, tests[cnt].str2);
+
+      r = strcasecmp_l (tests[cnt].str1, tests[cnt].str2, loc);
+      if (tests[cnt].result == 0)
+	{
+	  if (r != 0)
+	    {
+	      printf ("\"%s\" and \"%s\" expected to be the same, result %d\n",
+		      tests[cnt].str1, tests[cnt].str2, r);
+	      result = 1;
+	    }
+	}
+      else if (tests[cnt].result < 0)
+	{
+	  if (r >= 0)
+	    {
+	      printf ("\"%s\" expected to be smaller than \"%s\", result %d\n",
+		      tests[cnt].str1, tests[cnt].str2, r);
+	      result = 1;
+	    }
+	}
+      else
+	{
+	  if (r <= 0)
+	    {
+	      printf ("\"%s\" expected to be larger than \"%s\", result %d\n",
+		      tests[cnt].str1, tests[cnt].str2, r);
+	      result = 1;
+	    }
+	}
+    }
+
+  return result;
+}

+ 64 - 0
test/locale/tst-xlocale2.c

@@ -0,0 +1,64 @@
+#include <ctype.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int do_test (__locale_t l);
+
+int
+main (void)
+{
+  locale_t l;
+  locale_t l2;
+  int result;
+
+  l = newlocale (1 << LC_ALL, "de_DE.ISO-8859-1", NULL);
+  if (l == NULL)
+    {
+      printf ("newlocale failed: %m\n");
+      exit (EXIT_FAILURE);
+    }
+  puts ("Running tests of created locale");
+  result = do_test (l);
+
+  l2 = duplocale (l);
+  if (l2 == NULL)
+    {
+      printf ("duplocale failed: %m\n");
+      exit (EXIT_FAILURE);
+    }
+  freelocale (l);
+  puts ("Running tests of duplicated locale");
+  result |= do_test (l2);
+
+  return result;
+}
+
+
+static const char str[] = "0123456789abcdef ABCDEF ghijklmnopqrstuvwxyzäÄöÖüÜ";
+static const char exd[] = "11111111110000000000000000000000000000000000000000";
+static const char exa[] = "00000000001111110111111011111111111111111111111111";
+static const char exx[] = "11111111111111110111111000000000000000000000000000";
+
+
+static int
+do_test (locale_t l)
+{
+  int result = 0;
+size_t n;
+
+#define DO_TEST(TEST, RES) \
+  for (n = 0; n < sizeof (str) - 1; ++n)				      \
+    if ('0' + (TEST (str[n], l) != 0) != RES[n])			      \
+      {									      \
+	printf ("%s(%c) failed\n", #TEST, str[n]);			      \
+	result = 1;							      \
+      }
+
+  DO_TEST (isdigit_l, exd);
+  DO_TEST (isalpha_l, exa);
+  DO_TEST (isxdigit_l, exx);
+
+  return result;
+}

+ 296 - 0
test/locale/tst_nl_langinfo.c

@@ -0,0 +1,296 @@
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <langinfo.h>
+#include <nl_types.h>
+
+#if !defined(__UCLIBC__) && 0
+#define DO_EXTRA
+#endif
+
+int main(int argc, char **argv)
+{
+	char *l;
+	const unsigned char *x;
+/*  	const unsigned char *y; */
+	const unsigned char *p;
+
+	if (argc > 2) {
+		printf("invalid args\n");
+		return EXIT_FAILURE;
+	}
+	if (argc == 1) {
+		l = "";
+	} else {
+		l = *++argv;
+	}
+
+	if (!(x = setlocale(LC_ALL,l))) {
+		printf("couldn't set locale %s\n", l);
+		return EXIT_FAILURE;
+	}
+
+/*  	printf("\nsetlocale returned:\n  "); */
+/*  	do { */
+/*  		printf("\\x%02x", *x); */
+/*  	} while (*x++); */
+/*  	printf("\n"); */
+
+#ifndef __BCC__
+#define STR(X) #X
+#else
+#define STR(X) __STR(X)
+#endif
+#define __PASTE2(A,B) A.B
+
+#define DO_NL_I(X) \
+	printf( STR(X) " = %d\n", (int) nl_langinfo(X) );
+#define DO_NL_S(X) \
+	printf( STR(X) " = \"%s\"\n", nl_langinfo(X) );
+#define DO_NL_C(X) \
+	printf( STR(X) " = \"\\x%02x\"\n", *((unsigned char *) nl_langinfo(X)) );
+
+	printf("ctype\n");
+
+		DO_NL_S(CODESET);
+#ifdef DO_EXTRA
+		DO_NL_I(_NL_CTYPE_INDIGITS_MB_LEN);
+		DO_NL_S(_NL_CTYPE_INDIGITS0_MB);
+		DO_NL_S(_NL_CTYPE_INDIGITS1_MB);
+		DO_NL_S(_NL_CTYPE_INDIGITS2_MB);
+		DO_NL_S(_NL_CTYPE_INDIGITS3_MB);
+		DO_NL_S(_NL_CTYPE_INDIGITS4_MB);
+		DO_NL_S(_NL_CTYPE_INDIGITS5_MB);
+		DO_NL_S(_NL_CTYPE_INDIGITS6_MB);
+		DO_NL_S(_NL_CTYPE_INDIGITS7_MB);
+		DO_NL_S(_NL_CTYPE_INDIGITS8_MB);
+		DO_NL_S(_NL_CTYPE_INDIGITS9_MB);
+#endif
+		DO_NL_S(_NL_CTYPE_OUTDIGIT0_MB);
+		DO_NL_S(_NL_CTYPE_OUTDIGIT1_MB);
+		DO_NL_S(_NL_CTYPE_OUTDIGIT2_MB);
+		DO_NL_S(_NL_CTYPE_OUTDIGIT3_MB);
+		DO_NL_S(_NL_CTYPE_OUTDIGIT4_MB);
+		DO_NL_S(_NL_CTYPE_OUTDIGIT5_MB);
+		DO_NL_S(_NL_CTYPE_OUTDIGIT6_MB);
+		DO_NL_S(_NL_CTYPE_OUTDIGIT7_MB);
+		DO_NL_S(_NL_CTYPE_OUTDIGIT8_MB);
+		DO_NL_S(_NL_CTYPE_OUTDIGIT9_MB);
+
+
+	printf("numeric\n");
+
+		DO_NL_S(RADIXCHAR);		/* DECIMAL_POINT */
+		DO_NL_S(THOUSEP);		/* THOUSANDS_SEP */
+/*  		DO_NL_S(GROUPING); */
+
+	printf("GROUPING = \"");
+	for (p = (unsigned char *) nl_langinfo(GROUPING) ; *p ; p++) {
+		printf("\\x%02x", *p);
+	}
+	printf("\"\n\n");
+
+	printf("monetary\n");
+
+		DO_NL_S(INT_CURR_SYMBOL);
+		DO_NL_S(CURRENCY_SYMBOL);
+		DO_NL_S(MON_DECIMAL_POINT);
+		DO_NL_S(MON_THOUSANDS_SEP);
+/*  		DO_NL_S(MON_GROUPING); */
+
+	printf("MON_GROUPING = \"");
+	for (p = (unsigned char *) nl_langinfo(MON_GROUPING) ; *p ; p++) {
+		printf("\\x%02x", *p);
+	}
+	printf("\"\n\n");
+
+		DO_NL_S(POSITIVE_SIGN);
+		DO_NL_S(NEGATIVE_SIGN);
+		DO_NL_C(INT_FRAC_DIGITS);
+		DO_NL_C(FRAC_DIGITS);
+		DO_NL_C(P_CS_PRECEDES);
+		DO_NL_C(P_SEP_BY_SPACE);
+		DO_NL_C(N_CS_PRECEDES);
+		DO_NL_C(N_SEP_BY_SPACE);
+		DO_NL_C(P_SIGN_POSN);
+		DO_NL_C(N_SIGN_POSN);
+		DO_NL_C(INT_P_CS_PRECEDES);
+		DO_NL_C(INT_P_SEP_BY_SPACE);
+		DO_NL_C(INT_N_CS_PRECEDES);
+		DO_NL_C(INT_N_SEP_BY_SPACE);
+		DO_NL_C(INT_P_SIGN_POSN);
+		DO_NL_C(INT_N_SIGN_POSN);
+
+		DO_NL_S(CRNCYSTR);		/* CURRENCY_SYMBOL */
+
+
+	printf("time\n");
+
+		DO_NL_S(ABDAY_1);
+		DO_NL_S(ABDAY_2);
+		DO_NL_S(ABDAY_3);
+		DO_NL_S(ABDAY_4);
+		DO_NL_S(ABDAY_5);
+		DO_NL_S(ABDAY_6);
+		DO_NL_S(ABDAY_7);
+
+		DO_NL_S(DAY_1);
+		DO_NL_S(DAY_2);
+		DO_NL_S(DAY_3);
+		DO_NL_S(DAY_4);
+		DO_NL_S(DAY_5);
+		DO_NL_S(DAY_6);
+		DO_NL_S(DAY_7);
+
+		DO_NL_S(ABMON_1);
+		DO_NL_S(ABMON_2);
+		DO_NL_S(ABMON_3);
+		DO_NL_S(ABMON_4);
+		DO_NL_S(ABMON_5);
+		DO_NL_S(ABMON_6);
+		DO_NL_S(ABMON_7);
+		DO_NL_S(ABMON_8);
+		DO_NL_S(ABMON_9);
+		DO_NL_S(ABMON_10);
+		DO_NL_S(ABMON_11);
+		DO_NL_S(ABMON_12);
+
+		DO_NL_S(MON_1);
+		DO_NL_S(MON_2);
+		DO_NL_S(MON_3);
+		DO_NL_S(MON_4);
+		DO_NL_S(MON_5);
+		DO_NL_S(MON_6);
+		DO_NL_S(MON_7);
+		DO_NL_S(MON_8);
+		DO_NL_S(MON_9);
+		DO_NL_S(MON_10);
+		DO_NL_S(MON_11);
+		DO_NL_S(MON_12);
+
+		DO_NL_S(AM_STR);
+		DO_NL_S(PM_STR);
+
+		DO_NL_S(D_T_FMT);
+		DO_NL_S(D_FMT);
+		DO_NL_S(T_FMT);
+		DO_NL_S(T_FMT_AMPM);
+/* 		DO_NL_S(ERA); */
+		{
+		    const char *p = nl_langinfo(ERA);
+		    if (!p || !*p) {
+			printf("ERA = (none)\n");
+		    } else {
+			int i;
+			printf("ERA:\n");
+			for (i=0 ; i < 100 ; i++) {
+			    printf("  %3d: \"%s\"\n", i, p);
+			    while (*p) ++p;
+			    ++p;
+			    if (!*p) break;
+			}
+		    }
+		}
+
+		DO_NL_S(ERA_YEAR);		/* non SuSv3 */
+		DO_NL_S(ERA_D_FMT);
+/* 		DO_NL_S(ALT_DIGITS); */
+		{
+		    const char *p = nl_langinfo(ALT_DIGITS);
+		    if (!p || !*p) {
+			printf("ALT_DIGITS = (none)\n");
+		    } else {
+			int i;
+			printf("ALT_DIGITS:\n");
+			for (i=0 ; i < 100 ; i++) {
+			    printf("  %3d: \"%s\"\n", i, p);
+			    while (*p) ++p;
+			    ++p;
+			}
+		    }
+		}
+		DO_NL_S(ERA_D_T_FMT);
+		DO_NL_S(ERA_T_FMT);
+
+#ifdef DO_EXTRA
+		DO_NL_C(_NL_TIME_WEEK_NDAYS);
+		DO_NL_I(_NL_TIME_WEEK_1STDAY); /* grr... this won't work with 16bit ptrs */
+		DO_NL_C(_NL_TIME_WEEK_1STWEEK);
+		DO_NL_C(_NL_TIME_FIRST_WEEKDAY);
+		DO_NL_C(_NL_TIME_FIRST_WORKDAY);
+		DO_NL_C(_NL_TIME_CAL_DIRECTION);
+		DO_NL_S(_NL_TIME_TIMEZONE);
+		DO_NL_S(_DATE_FMT);
+#endif
+
+	printf("messages\n");
+
+		DO_NL_S(YESEXPR);
+		DO_NL_S(NOEXPR);
+		DO_NL_S(YESSTR);
+		DO_NL_S(NOSTR);
+
+#ifdef DO_EXTRA
+
+	printf("paper\n");
+
+		DO_NL_I(_NL_PAPER_HEIGHT);
+		DO_NL_I(_NL_PAPER_WIDTH);
+
+	printf("name\n");
+
+		DO_NL_S(_NL_NAME_NAME_FMT);
+		DO_NL_S(_NL_NAME_NAME_GEN);
+		DO_NL_S(_NL_NAME_NAME_MR);
+		DO_NL_S(_NL_NAME_NAME_MRS);
+		DO_NL_S(_NL_NAME_NAME_MISS);
+		DO_NL_S(_NL_NAME_NAME_MS);
+
+	printf("address\n");
+
+		DO_NL_S(_NL_ADDRESS_POSTAL_FMT);
+		DO_NL_S(_NL_ADDRESS_COUNTRY_NAME);
+		DO_NL_S(_NL_ADDRESS_COUNTRY_POST);
+		DO_NL_S(_NL_ADDRESS_COUNTRY_AB2);
+		DO_NL_S(_NL_ADDRESS_COUNTRY_AB3);
+		DO_NL_S(_NL_ADDRESS_COUNTRY_CAR);
+		DO_NL_I(_NL_ADDRESS_COUNTRY_NUM);
+		DO_NL_S(_NL_ADDRESS_COUNTRY_ISBN);
+		DO_NL_S(_NL_ADDRESS_LANG_NAME);
+		DO_NL_S(_NL_ADDRESS_LANG_AB);
+		DO_NL_S(_NL_ADDRESS_LANG_TERM);
+		DO_NL_S(_NL_ADDRESS_LANG_LIB);
+
+	printf("telephone\n");
+
+		DO_NL_S(_NL_TELEPHONE_TEL_INT_FMT);
+		DO_NL_S(_NL_TELEPHONE_TEL_DOM_FMT);
+		DO_NL_S(_NL_TELEPHONE_INT_SELECT);
+		DO_NL_S(_NL_TELEPHONE_INT_PREFIX);
+
+	printf("measurement\n");
+
+		DO_NL_C(_NL_MEASUREMENT_MEASUREMENT); /* 1 is metric, 2 is US */
+
+	printf("identification\n");
+
+		DO_NL_S(_NL_IDENTIFICATION_TITLE);
+		DO_NL_S(_NL_IDENTIFICATION_SOURCE);
+		DO_NL_S(_NL_IDENTIFICATION_ADDRESS);
+		DO_NL_S(_NL_IDENTIFICATION_CONTACT);
+		DO_NL_S(_NL_IDENTIFICATION_EMAIL);
+		DO_NL_S(_NL_IDENTIFICATION_TEL);
+		DO_NL_S(_NL_IDENTIFICATION_FAX);
+		DO_NL_S(_NL_IDENTIFICATION_LANGUAGE);
+		DO_NL_S(_NL_IDENTIFICATION_TERRITORY);
+		DO_NL_S(_NL_IDENTIFICATION_AUDIENCE);
+		DO_NL_S(_NL_IDENTIFICATION_APPLICATION);
+		DO_NL_S(_NL_IDENTIFICATION_ABBREVIATION);
+		DO_NL_S(_NL_IDENTIFICATION_REVISION);
+		DO_NL_S(_NL_IDENTIFICATION_DATE);
+		DO_NL_S(_NL_IDENTIFICATION_CATEGORY);
+
+#endif
+
+	return EXIT_SUCCESS;
+}

+ 144 - 0
test/locale/xfrm-test.c

@@ -0,0 +1,144 @@
+/* Test collation function via transformation using real data.
+   Copyright (C) 1997, 1998, 2000, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <ctype.h>
+#include <error.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+struct lines
+{
+  char *xfrm;
+  char *line;
+};
+
+static int xstrcmp (const void *, const void *);
+
+int
+main (int argc, char *argv[])
+{
+  int result = 0;
+  size_t nstrings, nstrings_max;
+  struct lines *strings;
+  char *line = NULL;
+  size_t len = 0;
+  size_t n;
+
+  if (argc < 2)
+    error (1, 0, "usage: %s <random seed>", argv[0]);
+
+  setlocale (LC_ALL, "");
+
+  nstrings_max = 100;
+  nstrings = 0;
+  strings = (struct lines *) malloc (nstrings_max * sizeof (struct lines));
+  if (strings == NULL)
+    {
+      perror (argv[0]);
+      exit (1);
+    }
+
+  while (1)
+    {
+      char saved, *newp;
+      int needed;
+      int l;
+      if (getline (&line, &len, stdin) < 0)
+	break;
+
+      if (nstrings == nstrings_max)
+	{
+	  strings = (struct lines *) realloc (strings,
+					      (nstrings_max *= 2)
+					       * sizeof (*strings));
+	  if (strings == NULL)
+	    {
+	      perror (argv[0]);
+	      exit (1);
+	    }
+	}
+      strings[nstrings].line = strdup (line);
+      l = strcspn (line, ":(;");
+      while (l > 0 && isspace (line[l - 1]))
+	--l;
+
+      saved = line[l];
+      line[l] = '\0';
+      needed = strxfrm (NULL, line, 0);
+      newp = malloc (needed + 1);
+      strxfrm (newp, line, needed + 1);
+      strings[nstrings].xfrm = newp;
+      line[l] = saved;
+      ++nstrings;
+    }
+  free (line);
+
+  /* First shuffle.  */
+  srandom (atoi (argv[1]));
+  for (n = 0; n < 10 * nstrings; ++n)
+    {
+      int r1, r2, r;
+      size_t idx1 = random () % nstrings;
+      size_t idx2 = random () % nstrings;
+      struct lines tmp = strings[idx1];
+      strings[idx1] = strings[idx2];
+      strings[idx2] = tmp;
+
+      /* While we are at it a first little test.  */
+      r1 = strcmp (strings[idx1].xfrm, strings[idx2].xfrm);
+      r2 = strcmp (strings[idx2].xfrm, strings[idx1].xfrm);
+      r = -(r1 ^ r2);
+      if (r)
+	r /= abs (r1 ^ r2);
+
+      if (r < 0 || (r == 0 && (r1 != 0 || r2 != 0))
+	  || (r > 0 && (r1 ^ r2) >= 0))
+	printf ("collate wrong: %d vs. %d\n", r1, r2);
+    }
+
+  /* Now sort.  */
+  qsort (strings, nstrings, sizeof (struct lines), xstrcmp);
+
+  /* Print the result.  */
+  for (n = 0; n < nstrings; ++n)
+    {
+      fputs (strings[n].line, stdout);
+      free (strings[n].line);
+      free (strings[n].xfrm);
+    }
+  free (strings);
+
+  return result;
+}
+
+
+static int
+xstrcmp (ptr1, ptr2)
+     const void *ptr1;
+     const void *ptr2;
+{
+  const struct lines *l1 = (const struct lines *) ptr1;
+  const struct lines *l2 = (const struct lines *) ptr2;
+
+  return strcmp (l1->xfrm, l2->xfrm);
+}