about summary refs log tree commit diff
path: root/intl
diff options
context:
space:
mode:
Diffstat (limited to 'intl')
-rw-r--r--intl/Makefile13
-rw-r--r--intl/dcgettext.c30
-rw-r--r--intl/explodename.c167
-rw-r--r--intl/finddomain.c414
-rw-r--r--intl/gettextP.h28
-rw-r--r--intl/l10nflist.c262
-rw-r--r--intl/loadinfo.h48
-rw-r--r--intl/loadmsgcat.c34
-rw-r--r--intl/locale.alias52
9 files changed, 612 insertions, 436 deletions
diff --git a/intl/Makefile b/intl/Makefile
index 159d1b1534..9d97088d4a 100644
--- a/intl/Makefile
+++ b/intl/Makefile
@@ -21,19 +21,26 @@
 subdir = intl
 headers = libintl.h
 routines = bindtextdom dcgettext dgettext gettext	\
-	   finddomain loadmsgcat localealias textdomain
-distribute = gettext.h gettextP.h hash-string.h
+	   finddomain loadmsgcat localealias textdomain	\
+	   l10nflist explodename
+distribute = gettext.h gettextP.h hash-string.h loadinfo.h locale.alias
+
+install-others = $(localedir)/locale.alias
 
 include ../Rules
 
 CPPFLAGS += -D'GNULOCALEDIR="$(localedir)"' \
-	    -D'LOCALE_ALIAS_PATH="$(localedir):$(nlsdir)"'
+	    -D'LOCALE_ALIAS_PATH="$(localedir):$(i18ndir)"'
+
+$(localedir)/locale.alias: locale.alias
+	$(do-install)
 
 ifdef gettext-srcdir
 
 %.h:: ../gpl2lgpl.sed $(gettext-srcdir)/intl/%.glibc; $(copysrc)
 %.c:: ../gpl2lgpl.sed $(gettext-srcdir)/intl/%.c; $(copysrc)
 %.h:: ../gpl2lgpl.sed $(gettext-srcdir)/intl/%.h; $(copysrc)
+locale.alias:: ../gpl2lgpl.sed $(gettext-srcdir)/misc/locale.alias; $(copysrc)
 
 define copysrc
 sed -f $^ > $@.new
diff --git a/intl/dcgettext.c b/intl/dcgettext.c
index 7d739d32c3..6c8963f720 100644
--- a/intl/dcgettext.c
+++ b/intl/dcgettext.c
@@ -1,8 +1,6 @@
 /* dcgettext.c -- implementation of the dcgettext(3) function
-   Copyright (C) 1995 Free Software Foundation, Inc.
-
-This file is part of the GNU C Library.  Its master source is NOT part of
-the C library, however.  The master source lives in /gd/gnu/lib.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
 
 The GNU C Library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Library General Public License as
@@ -16,8 +14,8 @@ Library General Public License for more details.
 
 You should have received a copy of the GNU Library General Public
 License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
@@ -155,7 +153,7 @@ const char _nl_default_dirname[] = GNULOCALEDIR;
 struct binding *_nl_domain_bindings;
 
 /* Prototypes for local functions.  */
-static char *find_msg PARAMS ((struct loaded_domain *domain,
+static char *find_msg PARAMS ((struct loaded_l10nfile *domain_file,
 			       const char *msgid));
 static const char *category_to_name PARAMS ((int category));
 static const char *guess_category_value PARAMS ((int category,
@@ -180,7 +178,7 @@ DCGETTEXT (domainname, msgid, category)
      const char *msgid;
      int category;
 {
-  struct loaded_domain *domain;
+  struct loaded_l10nfile *domain;
   struct binding *binding;
   const char *categoryname;
   const char *categoryvalue;
@@ -355,18 +353,21 @@ weak_alias (__dcgettext, dcgettext);
 
 
 static char *
-find_msg (domain, msgid)
-     struct loaded_domain *domain;
+find_msg (domain_file, msgid)
+     struct loaded_l10nfile *domain_file;
      const char *msgid;
 {
   size_t top, act, bottom;
+  struct loaded_domain *domain;
 
-  if (domain->decided == 0)
-    _nl_load_domain (domain);
+  if (domain_file->decided == 0)
+    _nl_load_domain (domain_file);
 
-  if (domain->data == NULL)
+  if (domain_file->data == NULL)
     return NULL;
 
+  domain = (struct loaded_domain *) domain_file->data;
+
   /* Locate the MSGID and its translation.  */
   if (domain->hash_size > 2 && domain->hash_tab != NULL)
     {
@@ -439,7 +440,8 @@ find_msg (domain, msgid)
 
 
 /* Return string representation of locale CATEGORY.  */
-static const char *category_to_name (category)
+static const char *
+category_to_name (category)
      int category;
 {
   const char *retval;
diff --git a/intl/explodename.c b/intl/explodename.c
new file mode 100644
index 0000000000..2fd8be014d
--- /dev/null
+++ b/intl/explodename.c
@@ -0,0 +1,167 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "loadinfo.h"
+
+int
+_nl_explode_name (name, language, modifier, territory, codeset,
+		  normalized_codeset, special, sponsor, revision)
+     char *name;
+     const char **language;
+     const char **modifier;
+     const char **territory;
+     const char **codeset;
+     const char **normalized_codeset;
+     const char **special;
+     const char **sponsor;
+     const char **revision;
+{
+  enum { undecided, xpg, cen } syntax;
+  char *cp;
+  int mask;
+  
+  *modifier = NULL;
+  *territory = NULL;
+  *codeset = NULL;
+  *normalized_codeset = NULL;
+  *special = NULL;
+  *sponsor = NULL;
+  *revision = NULL;
+
+  /* Now we determine the single parts of the locale name.  First
+     look for the language.  Termination symbols are `_' and `@' if
+     we use XPG4 style, and `_', `+', and `,' if we use CEN syntax.  */
+  mask = 0;
+  syntax = undecided;
+  *language = cp = name;
+  while (cp[0] != '\0' && cp[0] != '_' && cp[0] != '@'
+	 && cp[0] != '+' && cp[0] != ',')
+    ++cp;
+
+  if (*language == cp)
+    /* This does not make sense: language has to be specified.  Use
+       this entry as it is without exploding.  Perhaps it is an alias.  */
+    cp = strchr (*language, '\0');
+  else if (cp[0] == '_')
+    {
+      /* Next is the territory.  */
+      cp[0] = '\0';
+      *territory = ++cp;
+
+      while (cp[0] != '\0' && cp[0] != '.' && cp[0] != '@'
+	     && cp[0] != '+' && cp[0] != ',' && cp[0] != '_')
+	++cp;
+
+      mask |= TERRITORY;
+
+      if (cp[0] == '.')
+	{
+	  /* Next is the codeset.  */
+	  syntax = xpg;
+	  cp[0] = '\0';
+	  *codeset = ++cp;
+
+	  while (cp[0] != '\0' && cp[0] != '@')
+	    ++cp;
+
+	  mask |= XPG_CODESET;
+
+	  if (*codeset != cp && (*codeset)[0] != '\0')
+	    {
+	      *normalized_codeset = _nl_normalize_codeset (*codeset,
+							   cp - *codeset);
+	      if (strcmp (*codeset, *normalized_codeset) == 0)
+		free ((char *) *normalized_codeset);
+	      else
+		mask |= XPG_NORM_CODESET;
+	    }
+	}
+    }
+
+  if (cp[0] == '@' || (syntax != xpg && cp[0] == '+'))
+    {
+      /* Next is the modifier.  */
+      syntax = cp[0] == '@' ? xpg : cen;
+      cp[0] = '\0';
+      *modifier = ++cp;
+
+      while (syntax == cen && cp[0] != '\0' && cp[0] != '+'
+	     && cp[0] != ',' && cp[0] != '_')
+	++cp;
+
+      mask |= XPG_MODIFIER | CEN_AUDIENCE;
+    }
+
+  if (syntax != xpg && (cp[0] == '+' || cp[0] == ',' || cp[0] == '_'))
+    {
+      syntax = cen;
+
+      if (cp[0] == '+')
+	{
+ 	  /* Next is special application (CEN syntax).  */
+	  cp[0] = '\0';
+	  *special = ++cp;
+
+	  while (cp[0] != '\0' && cp[0] != ',' && cp[0] != '_')
+	    ++cp;
+
+	  mask |= CEN_SPECIAL;
+	}
+
+      if (cp[0] == ',')
+	{
+ 	  /* Next is sponsor (CEN syntax).  */
+	  cp[0] = '\0';
+	  *sponsor = ++cp;
+
+	  while (cp[0] != '\0' && cp[0] != '_')
+	    ++cp;
+
+	  mask |= CEN_SPONSOR;
+	}
+
+      if (cp[0] == '_')
+	{
+ 	  /* Next is revision (CEN syntax).  */
+	  cp[0] = '\0';
+	  *revision = ++cp;
+
+	  mask |= CEN_REVISION;
+	}
+    }
+
+  /* For CEN sytnax values it might be important to have the
+     separator character in the file name, not for XPG syntax.  */
+  if (syntax == xpg)
+    {
+      if (*territory != NULL && (*territory)[0] == '\0')
+	mask &= ~TERRITORY;
+
+      if (*codeset != NULL && (*codeset)[0] == '\0')
+	mask &= ~XPG_CODESET;
+
+      if (*modifier != NULL && (*modifier)[0] == '\0')
+	mask &= ~XPG_MODIFIER;
+    }
+
+  return mask;
+}
diff --git a/intl/finddomain.c b/intl/finddomain.c
index 3ced26fa4b..bb4609e864 100644
--- a/intl/finddomain.c
+++ b/intl/finddomain.c
@@ -1,9 +1,6 @@
 /* finddomain.c -- handle list of needed message catalogs
-   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
-
-This file is part of the GNU C Library.  Its master source is NOT part of
-the C library, however.  The master source lives in /gd/gnu/lib.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
 
 The GNU C Library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Library General Public License as
@@ -17,8 +14,8 @@ Library General Public License for more details.
 
 You should have received a copy of the GNU Library General Public
 License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
@@ -71,39 +68,8 @@ void free ();
 # define stpcpy(dest, src) __stpcpy(dest, src)
 #endif
 
-/* Encoding of locale name parts.  */
-#define CEN_REVISION		1
-#define CEN_SPONSOR		2
-#define CEN_SPECIAL		4
-#define XPG_NORM_CODESET	8
-#define XPG_CODESET		16
-#define TERRITORY		32
-#define CEN_AUDIENCE		64
-#define XPG_MODIFIER		128
-
-#define CEN_SPECIFIC	(CEN_REVISION|CEN_SPONSOR|CEN_SPECIAL|CEN_AUDIENCE)
-#define XPG_SPECIFIC	(XPG_CODESET|XPG_NORM_CODESET|XPG_MODIFIER)
-
-
 /* List of already loaded domains.  */
-static struct loaded_domain *_nl_loaded_domains;
-
-/* Prototypes for local functions.  */
-static struct loaded_domain *make_entry_rec PARAMS ((const char *dirname,
-						     int mask,
-						     const char *language,
-						     const char *territory,
-						     const char *codeset,
-						     const char *normalized_codeset,
-						     const char *modifier,
-						     const char *special,
-						     const char *sponsor,
-						     const char *revision,
-						     const char *domainname,
-						     int do_allocate));
-
-/* Normalize name of selected codeset.  */
-static const char *normalize_codeset PARAMS ((const char *codeset));
+static struct loaded_l10nfile *_nl_loaded_domains;
 
 /* Substitution for systems lacking this function in their C library.  */
 #if !_LIBC && !HAVE_STPCPY
@@ -115,29 +81,25 @@ static char *stpcpy__ PARAMS ((char *dest, const char *src));
 /* Return a data structure describing the message catalog described by
    the DOMAINNAME and CATEGORY parameters with respect to the currently
    established bindings.  */
-struct loaded_domain *
+struct loaded_l10nfile *
 _nl_find_domain (dirname, locale, domainname)
      const char *dirname;
      char *locale;
      const char *domainname;
 {
-  enum { undecided, xpg, cen } syntax;
-  struct loaded_domain *retval;
+  struct loaded_l10nfile *retval;
   const char *language;
-  const char *modifier = NULL;
-  const char *territory = NULL;
-  const char *codeset = NULL;
-  const char *normalized_codeset = NULL;
-  const char *special = NULL;
-  const char *sponsor = NULL;
-  const char *revision = NULL;
-  const char *alias_value = NULL;
-  char *cp;
+  const char *modifier;
+  const char *territory;
+  const char *codeset;
+  const char *normalized_codeset;
+  const char *special;
+  const char *sponsor;
+  const char *revision;
+  const char *alias_value;
   int mask;
 
-  /* CATEGORYVALUE now possibly contains a colon separated list of
-     locales.  Each single locale can consist of up to four recognized
-     parts for the XPG syntax:
+  /* LOCALE can consist of up to four recognized parts for the XPG syntax:
 
 		language[_territory[.codeset]][@modifier]
 
@@ -160,15 +122,16 @@ _nl_find_domain (dirname, locale, domainname)
 
   /* If we have already tested for this locale entry there has to
      be one data set in the list of loaded domains.  */
-  retval = make_entry_rec (dirname, 0, locale, NULL, NULL, NULL, NULL,
-			   NULL, NULL, NULL, domainname, 0);
+  retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
+			       strlen (dirname) + 1, 0, locale, NULL, NULL,
+			       NULL, NULL, NULL, NULL, NULL, domainname, 0);
   if (retval != NULL)
     {
       /* We know something about this locale.  */
       int cnt;
 
       if (retval->decided == 0)
-	_nl_load_domain (retval); /* @@@ */
+	_nl_load_domain (retval);
 
       if (retval->data != NULL)
 	return retval;
@@ -181,8 +144,6 @@ _nl_find_domain (dirname, locale, domainname)
 	  if (retval->successor[cnt]->data != NULL)
 	    break;
 	}
-
-      /* We really found some usable information.  */
       return cnt >= 0 ? retval : NULL;
       /* NOTREACHED */
     }
@@ -204,123 +165,16 @@ _nl_find_domain (dirname, locale, domainname)
   /* Now we determine the single parts of the locale name.  First
      look for the language.  Termination symbols are `_' and `@' if
      we use XPG4 style, and `_', `+', and `,' if we use CEN syntax.  */
-  mask = 0;
-  syntax = undecided;
-  language = cp = locale;
-  while (cp[0] != '\0' && cp[0] != '_' && cp[0] != '@'
-	 && cp[0] != '+' && cp[0] != ',')
-    ++cp;
-
-  if (language == cp)
-    /* This does not make sense: language has to be specified.  Use
-       this entry as it is without exploding.  Perhaps it is an alias.  */
-    cp = strchr (language, '\0');
-  else if (cp[0] == '_')
-    {
-      /* Next is the territory.  */
-      cp[0] = '\0';
-      territory = ++cp;
-
-      while (cp[0] != '\0' && cp[0] != '.' && cp[0] != '@'
-	     && cp[0] != '+' && cp[0] != ',' && cp[0] != '_')
-	++cp;
-
-      mask |= TERRITORY;
-
-      if (cp[0] == '.')
-	{
-	  /* Next is the codeset.  */
-	  syntax = xpg;
-	  cp[0] = '\0';
-	  codeset = ++cp;
-
-	  while (cp[0] != '\0' && cp[0] != '@')
-	    ++cp;
-
-	  mask |= XPG_CODESET;
-
-	  if (codeset != cp && codeset[0] != '\0')
-	    {
-	      normalized_codeset = normalize_codeset (codeset);
-	      if (strcmp (codeset, normalized_codeset) == 0)
-		free ((char *) normalized_codeset);
-	      else
-		mask |= XPG_NORM_CODESET;
-	    }
-	}
-    }
-
-  if (cp[0] == '@' || (syntax != xpg && cp[0] == '+'))
-    {
-      /* Next is the modifier.  */
-      syntax = cp[0] == '@' ? xpg : cen;
-      cp[0] = '\0';
-      modifier = ++cp;
-
-      while (syntax == cen && cp[0] != '\0' && cp[0] != '+'
-	     && cp[0] != ',' && cp[0] != '_')
-	++cp;
-
-      mask |= XPG_MODIFIER | CEN_AUDIENCE;
-    }
-
-  if (syntax != xpg && (cp[0] == '+' || cp[0] == ',' || cp[0] == '_'))
-    {
-      syntax = cen;
-
-      if (cp[0] == '+')
-	{
- 	  /* Next is special application (CEN syntax).  */
-	  cp[0] = '\0';
-	  special = ++cp;
-
-	  while (cp[0] != '\0' && cp[0] != ',' && cp[0] != '_')
-	    ++cp;
-
-	  mask |= CEN_SPECIAL;
-	}
-
-      if (cp[0] == ',')
-	{
- 	  /* Next is sponsor (CEN syntax).  */
-	  cp[0] = '\0';
-	  sponsor = ++cp;
-
-	  while (cp[0] != '\0' && cp[0] != '_')
-	    ++cp;
-
-	  mask |= CEN_SPONSOR;
-	}
-
-      if (cp[0] == '_')
-	{
- 	  /* Next is revision (CEN syntax).  */
-	  cp[0] = '\0';
-	  revision = ++cp;
-
-	  mask |= CEN_REVISION;
-	}
-    }
-
-  /* For CEN sytnax values it might be important to have the
-     separator character in the file name, not for XPG syntax.  */
-  if (syntax == xpg)
-    {
-      if (territory != NULL && territory[0] == '\0')
-	mask &= ~TERRITORY;
-
-      if (codeset != NULL && codeset[0] == '\0')
-	mask &= ~XPG_CODESET;
-
-      if (modifier != NULL && modifier[0] == '\0')
-	mask &= ~XPG_MODIFIER;
-    }
+  mask = _nl_explode_name (locale, &language, &modifier, &territory,
+			   &codeset, &normalized_codeset, &special,
+			   &sponsor, &revision);
 
   /* Create all possible locale entries which might be interested in
      generalzation.  */
-  retval = make_entry_rec (dirname, mask, language, territory, codeset,
-			   normalized_codeset, modifier, special, sponsor,
-			   revision, domainname, 1);
+  retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
+			       strlen (dirname) + 1, mask, language, territory,
+			       codeset, normalized_codeset, modifier, special,
+			       sponsor, revision, domainname, 1);
   if (retval == NULL)
     /* This means we are out of core.  */
     return NULL;
@@ -336,12 +190,7 @@ _nl_find_domain (dirname, locale, domainname)
 	    _nl_load_domain (retval->successor[cnt]);
 	  if (retval->successor[cnt]->data != NULL)
 	    break;
-
-	  /* Signal that locale is not available.  */
-	  retval->successor[cnt] = NULL;
 	}
-      if (retval->successor[cnt] == NULL)
-	retval = NULL;
     }
 
   /* The room for an alias was dynamically allocated.  Free it now.  */
@@ -351,215 +200,6 @@ _nl_find_domain (dirname, locale, domainname)
   return retval;
 }
 
-
-static struct loaded_domain *
-make_entry_rec (dirname, mask, language, territory, codeset,
-		normalized_codeset, modifier, special, sponsor, revision,
-		domain, do_allocate)
-     const char *dirname;
-     int mask;
-     const char *language;
-     const char *territory;
-     const char *codeset;
-     const char *normalized_codeset;
-     const char *modifier;
-     const char *special;
-     const char *sponsor;
-     const char *revision;
-     const char *domain;
-     int do_allocate;
-{
-  char *filename = NULL;
-  struct loaded_domain *last = NULL;
-  struct loaded_domain *retval;
-  char *cp;
-  size_t entries;
-  int cnt;
-
-
-  /* Process the current entry described by the MASK only when it is
-     valid.  Because the mask can have in the first call bits from
-     both syntaces set this is necessary to prevent constructing
-     illegal local names.  */
-  /* FIXME: Rewrite because test is necessary only in first round.  */
-  if ((mask & CEN_SPECIFIC) == 0 || (mask & XPG_SPECIFIC) == 0
-      || ((mask & XPG_CODESET) != 0 && (mask & XPG_NORM_CODESET) != 0))
-    {
-      /* Allocate room for the full file name.  */
-      filename = (char *) malloc (strlen (dirname) + 1
-				  + strlen (language)
-				  + ((mask & TERRITORY) != 0
-				     ? strlen (territory) + 1 : 0)
-				  + ((mask & XPG_CODESET) != 0
-				     ? strlen (codeset) + 1 : 0)
-				  + ((mask & XPG_NORM_CODESET) != 0
-				     ? strlen (normalized_codeset) + 1 : 0)
-				  + ((mask & XPG_MODIFIER) != 0 ?
-				     strlen (modifier) + 1 : 0)
-				  + ((mask & CEN_SPECIAL) != 0
-				     ? strlen (special) + 1 : 0)
-				  + ((mask & CEN_SPONSOR) != 0
-				     ? strlen (sponsor) + 1 : 0)
-				  + ((mask & CEN_REVISION) != 0
-				     ? strlen (revision) + 1 : 0) + 1
-				  + strlen (domain) + 1);
-
-      if (filename == NULL)
-	return NULL;
-
-      retval = NULL;
-      last = NULL;
-
-      /* Construct file name.  */
-      cp = stpcpy (filename, dirname);
-      *cp++ = '/';
-      cp = stpcpy (cp, language);
-
-      if ((mask & TERRITORY) != 0)
-	{
-	  *cp++ = '_';
-	  cp = stpcpy (cp, territory);
-	}
-      if ((mask & XPG_CODESET) != 0)
-	{
-	  *cp++ = '.';
-	  cp = stpcpy (cp, codeset);
-	}
-      if ((mask & XPG_NORM_CODESET) != 0)
-	{
-	  *cp++ = '.';
-	  cp = stpcpy (cp, normalized_codeset);
-	}
-      if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
-	{
-	  /* This component can be part of both syntaces but has different
-	     leading characters.  For CEN we use `+', else `@'.  */
-	  *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
-	  cp = stpcpy (cp, modifier);
-	}
-      if ((mask & CEN_SPECIAL) != 0)
-	{
-	  *cp++ = '+';
-	  cp = stpcpy (cp, special);
-	}
-      if ((mask & CEN_SPONSOR) != 0)
-	{
-	  *cp++ = ',';
-	  cp = stpcpy (cp, sponsor);
-	}
-      if ((mask & CEN_REVISION) != 0)
-	{
-	  *cp++ = '_';
-	  cp = stpcpy (cp, revision);
-	}
-
-      *cp++ = '/';
-      stpcpy (cp, domain);
-
-      /* Look in list of already loaded domains whether it is already
-	 available.  */
-      last = NULL;
-      for (retval = _nl_loaded_domains; retval != NULL; retval = retval->next)
-	if (retval->filename != NULL)
-	  {
-	    int compare = strcmp (retval->filename, filename);
-	    if (compare == 0)
-	      /* We found it!  */
-	      break;
-	    if (compare < 0)
-	      {
-		/* It's not in the list.  */
-		retval = NULL;
-		break;
-	      }
-
-	    last = retval;
-	  }
-
-      if (retval != NULL || do_allocate == 0)
-	{
-	  free (filename);
-	  return retval;
-	}
-    }
-
-  retval = (struct loaded_domain *) malloc (sizeof (*retval));
-  if (retval == NULL)
-    return NULL;
-
-  retval->filename = filename;
-  retval->decided = 0;
-
-  if (last == NULL)
-    {
-      retval->next = _nl_loaded_domains;
-      _nl_loaded_domains = retval;
-    }
-  else
-    {
-      retval->next = last->next;
-      last->next = retval;
-    }
-
-  entries = 0;
-  for (cnt = 254; cnt >= 0; --cnt)
-    if (cnt < mask && (cnt & ~mask) == 0
-	&& ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
-	&& ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
-      retval->successor[entries++] = make_entry_rec (dirname, cnt,
-						     language, territory,
-						     codeset,
-						     normalized_codeset,
-						     modifier, special,
-						     sponsor, revision,
-						     domain, 1);
-  retval->successor[entries] = NULL;
-
-  return retval;
-}
-
-
-static const char *
-normalize_codeset (codeset)
-     const char *codeset;
-{
-  int len = 0;
-  int only_digit = 1;
-  const char *cp;
-  char *retval;
-  char *wp;
-
-  for (cp = codeset; cp[0] != '\0'; ++cp)
-    if (isalnum (cp[0]))
-      {
-	++len;
-
-	if (isalpha (cp[0]))
-	  only_digit = 0;
-      }
-
-  retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
-
-  if (retval != NULL)
-    {
-      if (only_digit)
-	wp = stpcpy (retval, "ISO");
-      else
-	wp = retval;
-
-      for (cp = codeset; cp[0] != '\0'; ++cp)
-	if (isalpha (cp[0]))
-	  *wp++ = toupper (cp[0]);
-	else if (isdigit (cp[0]))
-	  *wp++ = cp[0];
-
-      *wp = '\0';
-    }
-
-  return (const char *) retval;
-}
-
-
 /* @@ begin of epilog @@ */
 
 /* We don't want libintl.a to depend on any other library.  So we
diff --git a/intl/gettextP.h b/intl/gettextP.h
index 34196a0859..c37adaba0f 100644
--- a/intl/gettextP.h
+++ b/intl/gettextP.h
@@ -1,8 +1,6 @@
 /* gettextP.h -- header describing internals of gettext library
-   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
-This file is part of the GNU C Library.  Its master source is NOT part of
-the C library, however.  The master source lives in /gd/gnu/lib.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
 
 The GNU C Library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Library General Public License as
@@ -16,12 +14,14 @@ Library General Public License for more details.
 
 You should have received a copy of the GNU Library General Public
 License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 #ifndef _GETTEXTP_H
 #define _GETTEXTP_H
 
+#include "loadinfo.h"
+
 /* @@ end of prolog @@ */
 
 #ifndef PARAMS
@@ -49,12 +49,6 @@ SWAP (i)
 
 struct loaded_domain
 {
-  struct loaded_domain *next;
-  struct loaded_domain *successor[63];
-
-  const char *filename;
-  int decided;
-
   const char *data;
   int must_swap;
   nls_uint32 nstrings;
@@ -71,12 +65,10 @@ struct binding
   char *dirname;
 };
 
-struct loaded_domain *_nl_find_domain PARAMS ((const char *__dirname,
-					       char *__locale,
-					       const char *__domainname));
-void _nl_load_domain PARAMS ((struct loaded_domain *__domain));
-
-const char *_nl_expand_alias PARAMS ((const char *__name));
+struct loaded_l10nfile *_nl_find_domain PARAMS ((const char *__dirname,
+						 char *__locale,
+						 const char *__domainname));
+void _nl_load_domain PARAMS ((struct loaded_l10nfile *__domain));
 
 /* @@ begin of epilog @@ */
 
diff --git a/intl/l10nflist.c b/intl/l10nflist.c
new file mode 100644
index 0000000000..b0fdf51d73
--- /dev/null
+++ b/intl/l10nflist.c
@@ -0,0 +1,262 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include <argz.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "loadinfo.h"
+
+/* Return number of bits set in X.  */
+static int pop __P ((int x));
+
+static inline int
+pop (x)
+     int x;
+{
+  /* We assume that no more than 16 bits are used.  */
+  x = ((x & ~0x5555) >> 1) + (x & 0x5555);
+  x = ((x & ~0x3333) >> 2) + (x & 0x3333);
+  x = ((x >> 4) + x) & 0x0f0f;
+  x = ((x >> 8) + x) & 0xff;
+
+  return x;
+}
+
+
+struct loaded_l10nfile *
+_nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
+		    territory, codeset, normalized_codeset, modifier, special,
+		    sponsor, revision, filename, do_allocate)
+     struct loaded_l10nfile **l10nfile_list;
+     const char *dirlist;
+     size_t dirlist_len;
+     int mask;
+     const char *language;
+     const char *territory;
+     const char *codeset;
+     const char *normalized_codeset;
+     const char *modifier;
+     const char *special;
+     const char *sponsor;
+     const char *revision;
+     const char *filename;
+     int do_allocate;
+{
+  char *abs_filename;
+  struct loaded_l10nfile *last = NULL;
+  struct loaded_l10nfile *retval;
+  char *cp;
+  size_t entries;
+  int cnt;
+
+  /* Allocate room for the full file name.  */
+  abs_filename = (char *) malloc (dirlist_len
+				  + strlen (language)
+				  + ((mask & TERRITORY) != 0
+				     ? strlen (territory) + 1 : 0)
+				  + ((mask & XPG_CODESET) != 0
+				     ? strlen (codeset) + 1 : 0)
+				  + ((mask & XPG_NORM_CODESET) != 0
+				     ? strlen (normalized_codeset) + 1 : 0)
+				  + (((mask & XPG_MODIFIER) != 0
+				      || (mask & CEN_AUDIENCE) != 0) ?
+				     strlen (modifier) + 1 : 0)
+				  + ((mask & CEN_SPECIAL) != 0
+				     ? strlen (special) + 1 : 0)
+				  + ((mask & CEN_SPONSOR) != 0
+				     ? strlen (sponsor) + 1 : 0)
+				  + ((mask & CEN_REVISION) != 0
+				     ? strlen (revision) + 1 : 0)
+				  + 1 + strlen (filename) + 1);
+
+  if (abs_filename == NULL)
+    return NULL;
+
+  retval = NULL;
+  last = NULL;
+
+  /* Construct file name.  */
+  memcpy (abs_filename, dirlist, dirlist_len);
+  __argz_stringify (abs_filename, dirlist_len, ':');
+  cp = abs_filename + (dirlist_len - 1);
+  *cp++ = '/';
+  cp = stpcpy (cp, language);
+
+  if ((mask & TERRITORY) != 0)
+    {
+      *cp++ = '_';
+      cp = stpcpy (cp, territory);
+    }
+  if ((mask & XPG_CODESET) != 0)
+    {
+      *cp++ = '.';
+      cp = stpcpy (cp, codeset);
+    }
+  if ((mask & XPG_NORM_CODESET) != 0)
+    {
+      *cp++ = '.';
+      cp = stpcpy (cp, normalized_codeset);
+    }
+  if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
+    {
+      /* This component can be part of both syntaces but has different
+	 leading characters.  For CEN we use `+', else `@'.  */
+      *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
+      cp = stpcpy (cp, modifier);
+    }
+  if ((mask & CEN_SPECIAL) != 0)
+    {
+      *cp++ = '+';
+      cp = stpcpy (cp, special);
+    }
+  if ((mask & CEN_SPONSOR) != 0)
+    {
+      *cp++ = ',';
+      cp = stpcpy (cp, sponsor);
+    }
+  if ((mask & CEN_REVISION) != 0)
+    {
+      *cp++ = '_';
+      cp = stpcpy (cp, revision);
+    }
+
+  *cp++ = '/';
+  stpcpy (cp, filename);
+
+  /* Look in list of already loaded domains whether it is already
+     available.  */
+  last = NULL;
+  for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
+    if (retval->filename != NULL)
+      {
+	int compare = strcmp (retval->filename, abs_filename);
+	if (compare == 0)
+	  /* We found it!  */
+	  break;
+	if (compare < 0)
+	  {
+	    /* It's not in the list.  */
+	    retval = NULL;
+	    break;
+	  }
+
+	last = retval;
+      }
+
+  if (retval != NULL || do_allocate == 0)
+    {
+      free (abs_filename);
+      return retval;
+    }
+
+  retval = (struct loaded_l10nfile *)
+    malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
+				* (1 << pop (mask))
+				* sizeof (struct loaded_l10nfile *)));
+  if (retval == NULL)
+    return NULL;
+
+  retval->filename = abs_filename;
+  retval->decided = (__argz_count (dirlist, dirlist_len) != 1
+		     || ((mask & XPG_CODESET) != 0
+			 && (mask & XPG_NORM_CODESET) != 0));
+  retval->data = NULL;
+
+  if (last == NULL)
+    {
+      retval->next = *l10nfile_list;
+      *l10nfile_list = retval;
+    }
+  else
+    {
+      retval->next = last->next;
+      last->next = retval;
+    }
+
+  entries = 0;
+  /* If the DIRLIST is a real list the RETVAL entry correcponds not to
+     a real file.  So we have to use the DIRLIST separation machanism
+     of the inner loop.  */
+  cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
+  for (; cnt >= 0; --cnt)
+    if ((cnt & ~mask) == 0
+	&& ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
+	&& ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
+      {
+	/* Iterate over all elements of the DIRLIST.  */
+	char *dir = NULL;
+
+	while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
+	       != NULL)
+	  retval->successor[entries++]
+	    = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
+				  language, territory, codeset,
+				  normalized_codeset, modifier, special,
+				  sponsor, revision, filename, 1);
+      }
+  retval->successor[entries] = NULL;
+
+  return retval;
+}
+
+/* Normalize codeset name.  There is no standard for the codeset
+   names.  Normalization allows the user to use any of the common
+   names.  */
+const char *
+_nl_normalize_codeset (codeset, name_len)
+     const char *codeset;
+     size_t name_len;
+{
+  int len = 0;
+  int only_digit = 1;
+  char *retval;
+  char *wp;
+  size_t cnt;
+
+  for (cnt = 0; cnt < name_len; ++cnt)
+    if (isalnum (codeset[cnt]))
+      {
+	++len;
+
+	if (isalpha (codeset[cnt]))
+	  only_digit = 0;
+      }
+
+  retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
+
+  if (retval != NULL)
+    {
+      if (only_digit)
+	wp = stpcpy (retval, "ISO");
+      else
+	wp = retval;
+
+      for (cnt = 0; cnt < name_len; ++cnt)
+	if (isalpha (codeset[cnt]))
+	  *wp++ = tolower (codeset[cnt]);
+	else if (isdigit (codeset[cnt]))
+	  *wp++ = codeset[cnt];
+
+      *wp = '\0';
+    }
+
+  return (const char *) retval;
+}
diff --git a/intl/loadinfo.h b/intl/loadinfo.h
new file mode 100644
index 0000000000..00aa1c9d85
--- /dev/null
+++ b/intl/loadinfo.h
@@ -0,0 +1,48 @@
+/* Encoding of locale name parts.  */
+#define CEN_REVISION		1
+#define CEN_SPONSOR		2
+#define CEN_SPECIAL		4
+#define XPG_NORM_CODESET	8
+#define XPG_CODESET		16
+#define TERRITORY		32
+#define CEN_AUDIENCE		64
+#define XPG_MODIFIER		128
+
+#define CEN_SPECIFIC	(CEN_REVISION|CEN_SPONSOR|CEN_SPECIAL|CEN_AUDIENCE)
+#define XPG_SPECIFIC	(XPG_CODESET|XPG_NORM_CODESET|XPG_MODIFIER)
+
+
+struct loaded_l10nfile
+{
+  const char *filename;
+  int decided;
+
+  const void *data;
+
+  struct loaded_l10nfile *next;
+  struct loaded_l10nfile *successor[1];
+};
+
+
+extern const char *_nl_normalize_codeset __P ((const char *codeset,
+					       size_t name_len));
+
+extern struct loaded_l10nfile *
+_nl_make_l10nflist __P ((struct loaded_l10nfile **l10nfile_list,
+			 const char *dirlist, size_t dirlist_len, int mask,
+			 const char *language, const char *territory,
+			 const char *codeset, const char *normalized_codeset,
+			 const char *modifier, const char *special,
+			 const char *sponsor, const char *revision,
+			 const char *filename, int do_allocate));
+
+
+extern const char *_nl_expand_alias __P ((const char *name));
+
+extern int _nl_explode_name __P ((char *name, const char **language,
+				  const char **modifier,
+				  const char **territory,
+				  const char **codeset,
+				  const char **normalized_codeset,
+				  const char **special, const char **sponsor,
+				  const char **revision));
diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c
index 0f5bfd5b9d..1daf72a09f 100644
--- a/intl/loadmsgcat.c
+++ b/intl/loadmsgcat.c
@@ -1,8 +1,6 @@
 /* loadmsgcat.c -- load needed message catalogs
-   Copyright (C) 1995 Software Foundation, Inc.
-
-This file is part of the GNU C Library.  Its master source is NOT part of
-the C library, however.  The master source lives in /gd/gnu/lib.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
 
 The GNU C Library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Library General Public License as
@@ -16,8 +14,8 @@ Library General Public License for more details.
 
 You should have received a copy of the GNU Library General Public
 License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
@@ -65,8 +63,8 @@ int _nl_msg_cat_cntr;
 /* Load the message catalogs specified by FILENAME.  If it is no valid
    message catalog do nothing.  */
 void
-_nl_load_domain (domain)
-     struct loaded_domain *domain;
+_nl_load_domain (domain_file)
+     struct loaded_l10nfile *domain_file;
 {
   int fd;
   struct stat st;
@@ -75,19 +73,20 @@ _nl_load_domain (domain)
     || defined _LIBC
   int use_mmap = 0;
 #endif
+  struct loaded_domain *domain;
 
-  domain->decided = 1;
-  domain->data = NULL;
+  domain_file->decided = 1;
+  domain_file->data = NULL;
 
   /* If the record does not represent a valid locale the FILENAME
      might be NULL.  This can happen when according to the given
      specification the locale file name is different for XPG and CEN
      syntax.  */
-  if (domain->filename == NULL)
+  if (domain_file->filename == NULL)
     return;
 
   /* Try to open the addressed file.  */
-  fd = open (domain->filename, O_RDONLY);
+  fd = open (domain_file->filename, O_RDONLY);
   if (fd == -1)
     return;
 
@@ -160,6 +159,12 @@ _nl_load_domain (domain)
       return;
     }
 
+  domain_file->data
+    = (struct loaded_domain *) malloc (sizeof (struct loaded_domain *));
+  if (domain->data == NULL)
+    return;
+
+  domain = (struct loaded_domain *) domain_file->data;
   domain->data = (char *) data;
   domain->must_swap = data->magic != _MAGIC;
 
@@ -185,11 +190,12 @@ _nl_load_domain (domain)
       else
 #endif
 	free (data);
-      domain->data = NULL;
+      free (domain);
+      domain_file->data = NULL;
       return;
     }
 
   /* Show that one domain is changed.  This might make some cached
-     translation invalid.  */
+     translations invalid.  */
   ++_nl_msg_cat_cntr;
 }
diff --git a/intl/locale.alias b/intl/locale.alias
new file mode 100644
index 0000000000..cf1f6eea83
--- /dev/null
+++ b/intl/locale.alias
@@ -0,0 +1,52 @@
+# Locale name alias data base
+# Copyright (C) 1996 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# The format of this file is the same as for the corresponding file of
+# the X Window System, which normally can be found in
+#	/usr/lib/X11/locale/locale.alias
+# A single line contains two fields: an alias and a substitution value.
+# All entries are case independent.
+
+# Note: This file is far from being complete.  If you have a value for
+# your own site which you think might be useful for others too, share it
+# with the rest of us.  Send it to bug-gnu-utils@prep.ai.mit.edu.
+
+czech		cz_CZ.ISO-8859-2
+danish          da_DK.ISO-8859-1
+dansk		da_DK.ISO-8859-1
+deutsch		de_DE.ISO-8859-1
+dutch		nl_NL.ISO-8859-1
+finnish         fi_FI.ISO-8859-1
+français	fr_FR.ISO-8859-1
+french		fr_FR.ISO-8859-1
+german		de_DE.ISO-8859-1
+greek           el_GR.ISO-8859-7
+hebrew          iw_IL.ISO-8859-8
+hungarian       hu_HU.ISO-8859-2
+icelandic       is_IS.ISO-8859-1
+italian         it_CH.ISO-8859-1
+japanese	ja_JP.EUC
+norwegian       no_NO.ISO-8859-1
+polish          pl_PL.ISO-8859-2
+portuguese      pt_PT.ISO-8859-1
+rumanian        ro_RO.ISO-8859-2
+russian         ru_SU.ISO-8859-5
+slovak          sk_SK.ISO-8859-2
+slovene         sl_CS.ISO-8859-2
+spanish         es_ES.ISO-8859-1
+swedish         sv_SE.ISO-8859-1
+turkish         tr_TR.ISO-8859-9