summaryrefslogtreecommitdiff
path: root/intl
diff options
context:
space:
mode:
authorLutz Mueller <lutz@users.sourceforge.net>2000-11-29 07:59:25 +0000
committerLutz Mueller <lutz@users.sourceforge.net>2000-11-29 07:59:25 +0000
commitd943bc78146011bbe7352c7b60baa5056fde0671 (patch)
tree31e84629e67542f38f85f532d9d775b4f0f05c85 /intl
parentc552ae2180b69679529764ba44b44496ecef2daa (diff)
downloadlibgphoto2-d943bc78146011bbe7352c7b60baa5056fde0671.tar.gz
NLS support.
git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@1356 67ed7778-7388-44ab-90cf-0a291f65f57c
Diffstat (limited to 'intl')
-rw-r--r--intl/bindtextdom.c203
-rw-r--r--intl/cat-compat.c262
-rw-r--r--intl/dcgettext.c624
-rw-r--r--intl/dgettext.c59
-rw-r--r--intl/explodename.c188
-rw-r--r--intl/finddomain.c216
-rw-r--r--intl/gettext.c70
-rw-r--r--intl/gettext.h105
-rw-r--r--intl/gettextP.h89
-rw-r--r--intl/hash-string.h59
-rw-r--r--intl/intl-compat.c76
-rw-r--r--intl/l10nflist.c411
-rw-r--r--intl/libgettext.h182
-rw-r--r--intl/loadinfo.h76
-rw-r--r--intl/loadmsgcat.c222
-rw-r--r--intl/localealias.c424
-rw-r--r--intl/textdomain.c108
17 files changed, 3374 insertions, 0 deletions
diff --git a/intl/bindtextdom.c b/intl/bindtextdom.c
new file mode 100644
index 000000000..d9c3f349e
--- /dev/null
+++ b/intl/bindtextdom.c
@@ -0,0 +1,203 @@
+/* Implementation of the bindtextdomain(3) function
+ Copyright (C) 1995, 1996, 1997, 1998 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+# ifdef HAVE_MALLOC_H
+# include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+# define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+#include "gettext.h"
+#include "gettextP.h"
+
+/* @@ end of prolog @@ */
+
+/* Contains the default location of the message catalogs. */
+extern const char _nl_default_dirname[];
+
+/* List with bindings of specific domains. */
+extern struct binding *_nl_domain_bindings;
+
+
+/* Names for the libintl functions are a problem. They must not clash
+ with existing names and they should follow ANSI C. But this source
+ code is also used in GNU C Library where the names have a __
+ prefix. So we have to make a difference here. */
+#ifdef _LIBC
+# define BINDTEXTDOMAIN __bindtextdomain
+# ifndef strdup
+# define strdup(str) __strdup (str)
+# endif
+#else
+# define BINDTEXTDOMAIN bindtextdomain__
+#endif
+
+/* Specify that the DOMAINNAME message catalog will be found
+ in DIRNAME rather than in the system locale data base. */
+char *
+BINDTEXTDOMAIN (domainname, dirname)
+ const char *domainname;
+ const char *dirname;
+{
+ struct binding *binding;
+
+ /* Some sanity checks. */
+ if (domainname == NULL || domainname[0] == '\0')
+ return NULL;
+
+ for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
+ {
+ int compare = strcmp (domainname, binding->domainname);
+ if (compare == 0)
+ /* We found it! */
+ break;
+ if (compare < 0)
+ {
+ /* It is not in the list. */
+ binding = NULL;
+ break;
+ }
+ }
+
+ if (dirname == NULL)
+ /* The current binding has be to returned. */
+ return binding == NULL ? (char *) _nl_default_dirname : binding->dirname;
+
+ if (binding != NULL)
+ {
+ /* The domain is already bound. If the new value and the old
+ one are equal we simply do nothing. Otherwise replace the
+ old binding. */
+ if (strcmp (dirname, binding->dirname) != 0)
+ {
+ char *new_dirname;
+
+ if (strcmp (dirname, _nl_default_dirname) == 0)
+ new_dirname = (char *) _nl_default_dirname;
+ else
+ {
+#if defined _LIBC || defined HAVE_STRDUP
+ new_dirname = strdup (dirname);
+ if (new_dirname == NULL)
+ return NULL;
+#else
+ size_t len = strlen (dirname) + 1;
+ new_dirname = (char *) malloc (len);
+ if (new_dirname == NULL)
+ return NULL;
+
+ memcpy (new_dirname, dirname, len);
+#endif
+ }
+
+ if (binding->dirname != _nl_default_dirname)
+ free (binding->dirname);
+
+ binding->dirname = new_dirname;
+ }
+ }
+ else
+ {
+ /* We have to create a new binding. */
+#if !defined _LIBC && !defined HAVE_STRDUP
+ size_t len;
+#endif
+ struct binding *new_binding =
+ (struct binding *) malloc (sizeof (*new_binding));
+
+ if (new_binding == NULL)
+ return NULL;
+
+#if defined _LIBC || defined HAVE_STRDUP
+ new_binding->domainname = strdup (domainname);
+ if (new_binding->domainname == NULL)
+ return NULL;
+#else
+ len = strlen (domainname) + 1;
+ new_binding->domainname = (char *) malloc (len);
+ if (new_binding->domainname == NULL)
+ return NULL;
+ memcpy (new_binding->domainname, domainname, len);
+#endif
+
+ if (strcmp (dirname, _nl_default_dirname) == 0)
+ new_binding->dirname = (char *) _nl_default_dirname;
+ else
+ {
+#if defined _LIBC || defined HAVE_STRDUP
+ new_binding->dirname = strdup (dirname);
+ if (new_binding->dirname == NULL)
+ return NULL;
+#else
+ len = strlen (dirname) + 1;
+ new_binding->dirname = (char *) malloc (len);
+ if (new_binding->dirname == NULL)
+ return NULL;
+ memcpy (new_binding->dirname, dirname, len);
+#endif
+ }
+
+ /* Now enqueue it. */
+ if (_nl_domain_bindings == NULL
+ || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
+ {
+ new_binding->next = _nl_domain_bindings;
+ _nl_domain_bindings = new_binding;
+ }
+ else
+ {
+ binding = _nl_domain_bindings;
+ while (binding->next != NULL
+ && strcmp (domainname, binding->next->domainname) > 0)
+ binding = binding->next;
+
+ new_binding->next = binding->next;
+ binding->next = new_binding;
+ }
+
+ binding = new_binding;
+ }
+
+ return binding->dirname;
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library. */
+weak_alias (__bindtextdomain, bindtextdomain);
+#endif
diff --git a/intl/cat-compat.c b/intl/cat-compat.c
new file mode 100644
index 000000000..867d901b8
--- /dev/null
+++ b/intl/cat-compat.c
@@ -0,0 +1,262 @@
+/* Compatibility code for gettext-using-catgets interface.
+ Copyright (C) 1995, 1997 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#else
+char *getenv ();
+# ifdef HAVE_MALLOC_H
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef HAVE_NL_TYPES_H
+# include <nl_types.h>
+#endif
+
+#include "libgettext.h"
+
+/* @@ end of prolog @@ */
+
+/* XPG3 defines the result of `setlocale (category, NULL)' as:
+ ``Directs `setlocale()' to query `category' and return the current
+ setting of `local'.''
+ However it does not specify the exact format. And even worse: POSIX
+ defines this not at all. So we can use this feature only on selected
+ system (e.g. those using GNU C Library). */
+#ifdef _LIBC
+# define HAVE_LOCALE_NULL
+#endif
+
+/* The catalog descriptor. */
+static nl_catd catalog = (nl_catd) -1;
+
+/* Name of the default catalog. */
+static const char default_catalog_name[] = "messages";
+
+/* Name of currently used catalog. */
+static const char *catalog_name = default_catalog_name;
+
+/* Get ID for given string. If not found return -1. */
+static int msg_to_cat_id PARAMS ((const char *msg));
+
+/* Substitution for systems lacking this function in their C library. */
+#if !_LIBC && !HAVE_STPCPY
+static char *stpcpy PARAMS ((char *dest, const char *src));
+#endif
+
+
+/* Set currently used domain/catalog. */
+char *
+textdomain (domainname)
+ const char *domainname;
+{
+ nl_catd new_catalog;
+ char *new_name;
+ size_t new_name_len;
+ char *lang;
+
+#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES \
+ && defined HAVE_LOCALE_NULL
+ lang = setlocale (LC_MESSAGES, NULL);
+#else
+ lang = getenv ("LC_ALL");
+ if (lang == NULL || lang[0] == '\0')
+ {
+ lang = getenv ("LC_MESSAGES");
+ if (lang == NULL || lang[0] == '\0')
+ lang = getenv ("LANG");
+ }
+#endif
+ if (lang == NULL || lang[0] == '\0')
+ lang = "C";
+
+ /* See whether name of currently used domain is asked. */
+ if (domainname == NULL)
+ return (char *) catalog_name;
+
+ if (domainname[0] == '\0')
+ domainname = default_catalog_name;
+
+ /* Compute length of added path element. */
+ new_name_len = sizeof (LOCALEDIR) - 1 + 1 + strlen (lang)
+ + sizeof ("/LC_MESSAGES/") - 1 + sizeof (PACKAGE) - 1
+ + sizeof (".cat");
+
+ new_name = (char *) malloc (new_name_len);
+ if (new_name == NULL)
+ return NULL;
+
+ strcpy (new_name, PACKAGE);
+ new_catalog = catopen (new_name, 0);
+
+ if (new_catalog == (nl_catd) -1)
+ {
+ /* NLSPATH search didn't work, try absolute path */
+ sprintf (new_name, "%s/%s/LC_MESSAGES/%s.cat", LOCALEDIR, lang,
+ PACKAGE);
+ new_catalog = catopen (new_name, 0);
+
+ if (new_catalog == (nl_catd) -1)
+ {
+ free (new_name);
+ return (char *) catalog_name;
+ }
+ }
+
+ /* Close old catalog. */
+ if (catalog != (nl_catd) -1)
+ catclose (catalog);
+ if (catalog_name != default_catalog_name)
+ free ((char *) catalog_name);
+
+ catalog = new_catalog;
+ catalog_name = new_name;
+
+ return (char *) catalog_name;
+}
+
+char *
+bindtextdomain (domainname, dirname)
+ const char *domainname;
+ const char *dirname;
+{
+#if HAVE_SETENV || HAVE_PUTENV
+ char *old_val, *new_val, *cp;
+ size_t new_val_len;
+
+ /* This does not make much sense here but to be compatible do it. */
+ if (domainname == NULL)
+ return NULL;
+
+ /* Compute length of added path element. If we use setenv we don't need
+ the first byts for NLSPATH=, but why complicate the code for this
+ peanuts. */
+ new_val_len = sizeof ("NLSPATH=") - 1 + strlen (dirname)
+ + sizeof ("/%L/LC_MESSAGES/%N.cat");
+
+ old_val = getenv ("NLSPATH");
+ if (old_val == NULL || old_val[0] == '\0')
+ {
+ old_val = NULL;
+ new_val_len += 1 + sizeof (LOCALEDIR) - 1
+ + sizeof ("/%L/LC_MESSAGES/%N.cat");
+ }
+ else
+ new_val_len += strlen (old_val);
+
+ new_val = (char *) malloc (new_val_len);
+ if (new_val == NULL)
+ return NULL;
+
+# if HAVE_SETENV
+ cp = new_val;
+# else
+ cp = stpcpy (new_val, "NLSPATH=");
+# endif
+
+ cp = stpcpy (cp, dirname);
+ cp = stpcpy (cp, "/%L/LC_MESSAGES/%N.cat:");
+
+ if (old_val == NULL)
+ {
+# if __STDC__
+ stpcpy (cp, LOCALEDIR "/%L/LC_MESSAGES/%N.cat");
+# else
+
+ cp = stpcpy (cp, LOCALEDIR);
+ stpcpy (cp, "/%L/LC_MESSAGES/%N.cat");
+# endif
+ }
+ else
+ stpcpy (cp, old_val);
+
+# if HAVE_SETENV
+ setenv ("NLSPATH", new_val, 1);
+ free (new_val);
+# else
+ putenv (new_val);
+ /* Do *not* free the environment entry we just entered. It is used
+ from now on. */
+# endif
+
+#endif
+
+ return (char *) domainname;
+}
+
+#undef gettext
+char *
+gettext (msg)
+ const char *msg;
+{
+ int msgid;
+
+ if (msg == NULL || catalog == (nl_catd) -1)
+ return (char *) msg;
+
+ /* Get the message from the catalog. We always use set number 1.
+ The message ID is computed by the function `msg_to_cat_id'
+ which works on the table generated by `po-to-tbl'. */
+ msgid = msg_to_cat_id (msg);
+ if (msgid == -1)
+ return (char *) msg;
+
+ return catgets (catalog, 1, msgid, (char *) msg);
+}
+
+/* Look through the table `_msg_tbl' which has `_msg_tbl_length' entries
+ for the one equal to msg. If it is found return the ID. In case when
+ the string is not found return -1. */
+static int
+msg_to_cat_id (msg)
+ const char *msg;
+{
+ int cnt;
+
+ for (cnt = 0; cnt < _msg_tbl_length; ++cnt)
+ if (strcmp (msg, _msg_tbl[cnt]._msg) == 0)
+ return _msg_tbl[cnt]._msg_number;
+
+ return -1;
+}
+
+
+/* @@ begin of epilog @@ */
+
+/* We don't want libintl.a to depend on any other library. So we
+ avoid the non-standard function stpcpy. In GNU C Library this
+ function is available, though. Also allow the symbol HAVE_STPCPY
+ to be defined. */
+#if !_LIBC && !HAVE_STPCPY
+static char *
+stpcpy (dest, src)
+ char *dest;
+ const char *src;
+{
+ while ((*dest++ = *src++) != '\0')
+ /* Do nothing. */ ;
+ return dest - 1;
+}
+#endif
diff --git a/intl/dcgettext.c b/intl/dcgettext.c
new file mode 100644
index 000000000..c4c7a2c7d
--- /dev/null
+++ b/intl/dcgettext.c
@@ -0,0 +1,624 @@
+/* Implementation of the dcgettext(3) function.
+ Copyright (C) 1995, 1996, 1997, 1998 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+#else
+# if defined HAVE_ALLOCA_H || defined _LIBC
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca
+char *alloca ();
+# endif
+# endif
+# endif
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+char *getenv ();
+# ifdef HAVE_MALLOC_H
+# include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+# endif
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+# define strchr index
+# endif
+#endif
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+#include "hash-string.h"
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ANSI C functions. This is required by the standard
+ because some ANSI C functions will require linking with this object
+ file and the name space must not be polluted. */
+# define getcwd __getcwd
+# ifndef stpcpy
+# define stpcpy __stpcpy
+# endif
+#else
+# if !defined HAVE_GETCWD
+char *getwd ();
+# define getcwd(buf, max) getwd (buf)
+# else
+char *getcwd ();
+# endif
+# ifndef HAVE_STPCPY
+static char *stpcpy PARAMS ((char *dest, const char *src));
+# endif
+#endif
+
+/* Amount to increase buffer size by in each try. */
+#define PATH_INCR 32
+
+/* The following is from pathmax.h. */
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
+ PATH_MAX but might cause redefinition warnings when sys/param.h is
+ later included (as on MORE/BSD 4.3). */
+#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
+# include <limits.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+# define _POSIX_PATH_MAX 255
+#endif
+
+#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
+# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
+#endif
+
+/* Don't include sys/param.h if it already has been. */
+#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
+# include <sys/param.h>
+#endif
+
+#if !defined(PATH_MAX) && defined(MAXPATHLEN)
+# define PATH_MAX MAXPATHLEN
+#endif
+
+#ifndef PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+/* XPG3 defines the result of `setlocale (category, NULL)' as:
+ ``Directs `setlocale()' to query `category' and return the current
+ setting of `local'.''
+ However it does not specify the exact format. And even worse: POSIX
+ defines this not at all. So we can use this feature only on selected
+ system (e.g. those using GNU C Library). */
+#ifdef _LIBC
+# define HAVE_LOCALE_NULL
+#endif
+
+/* Name of the default domain used for gettext(3) prior any call to
+ textdomain(3). The default value for this is "messages". */
+const char _nl_default_default_domain[] = "messages";
+
+/* Value used as the default domain for gettext(3). */
+const char *_nl_current_default_domain = _nl_default_default_domain;
+
+/* Contains the default location of the message catalogs. */
+const char _nl_default_dirname[] = GNULOCALEDIR;
+
+/* List with bindings of specific domains created by bindtextdomain()
+ calls. */
+struct binding *_nl_domain_bindings;
+
+/* Prototypes for local functions. */
+static char *find_msg PARAMS ((struct loaded_l10nfile *domain_file,
+ const char *msgid)) internal_function;
+static const char *category_to_name PARAMS ((int category)) internal_function;
+static const char *guess_category_value PARAMS ((int category,
+ const char *categoryname))
+ internal_function;
+
+
+/* For those loosing systems which don't have `alloca' we have to add
+ some additional code emulating it. */
+#ifdef HAVE_ALLOCA
+/* Nothing has to be done. */
+# define ADD_BLOCK(list, address) /* nothing */
+# define FREE_BLOCKS(list) /* nothing */
+#else
+struct block_list
+{
+ void *address;
+ struct block_list *next;
+};
+# define ADD_BLOCK(list, addr) \
+ do { \
+ struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
+ /* If we cannot get a free block we cannot add the new element to \
+ the list. */ \
+ if (newp != NULL) { \
+ newp->address = (addr); \
+ newp->next = (list); \
+ (list) = newp; \
+ } \
+ } while (0)
+# define FREE_BLOCKS(list) \
+ do { \
+ while (list != NULL) { \
+ struct block_list *old = list; \
+ list = list->next; \
+ free (old); \
+ } \
+ } while (0)
+# undef alloca
+# define alloca(size) (malloc (size))
+#endif /* have alloca */
+
+
+/* Names for the libintl functions are a problem. They must not clash
+ with existing names and they should follow ANSI C. But this source
+ code is also used in GNU C Library where the names have a __
+ prefix. So we have to make a difference here. */
+#ifdef _LIBC
+# define DCGETTEXT __dcgettext
+#else
+# define DCGETTEXT dcgettext__
+#endif
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
+ locale. */
+char *
+DCGETTEXT (domainname, msgid, category)
+ const char *domainname;
+ const char *msgid;
+ int category;
+{
+#ifndef HAVE_ALLOCA
+ struct block_list *block_list = NULL;
+#endif
+ struct loaded_l10nfile *domain;
+ struct binding *binding;
+ const char *categoryname;
+ const char *categoryvalue;
+ char *dirname, *xdomainname;
+ char *single_locale;
+ char *retval;
+ int saved_errno = errno;
+
+ /* If no real MSGID is given return NULL. */
+ if (msgid == NULL)
+ return NULL;
+
+ /* If DOMAINNAME is NULL, we are interested in the default domain. If
+ CATEGORY is not LC_MESSAGES this might not make much sense but the
+ defintion left this undefined. */
+ if (domainname == NULL)
+ domainname = _nl_current_default_domain;
+
+ /* First find matching binding. */
+ for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
+ {
+ int compare = strcmp (domainname, binding->domainname);
+ if (compare == 0)
+ /* We found it! */
+ break;
+ if (compare < 0)
+ {
+ /* It is not in the list. */
+ binding = NULL;
+ break;
+ }
+ }
+
+ if (binding == NULL)
+ dirname = (char *) _nl_default_dirname;
+ else if (binding->dirname[0] == '/')
+ dirname = binding->dirname;
+ else
+ {
+ /* We have a relative path. Make it absolute now. */
+ size_t dirname_len = strlen (binding->dirname) + 1;
+ size_t path_max;
+ char *ret;
+
+ path_max = (unsigned) PATH_MAX;
+ path_max += 2; /* The getcwd docs say to do this. */
+
+ dirname = (char *) alloca (path_max + dirname_len);
+ ADD_BLOCK (block_list, dirname);
+
+ __set_errno (0);
+ while ((ret = getcwd (dirname, path_max)) == NULL && errno == ERANGE)
+ {
+ path_max += PATH_INCR;
+ dirname = (char *) alloca (path_max + dirname_len);
+ ADD_BLOCK (block_list, dirname);
+ __set_errno (0);
+ }
+
+ if (ret == NULL)
+ {
+ /* We cannot get the current working directory. Don't signal an
+ error but simply return the default string. */
+ FREE_BLOCKS (block_list);
+ __set_errno (saved_errno);
+ return (char *) msgid;
+ }
+
+ stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
+ }
+
+ /* Now determine the symbolic name of CATEGORY and its value. */
+ categoryname = category_to_name (category);
+ categoryvalue = guess_category_value (category, categoryname);
+
+ xdomainname = (char *) alloca (strlen (categoryname)
+ + strlen (domainname) + 5);
+ ADD_BLOCK (block_list, xdomainname);
+
+ stpcpy (stpcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
+ domainname),
+ ".mo");
+
+ /* Creating working area. */
+ single_locale = (char *) alloca (strlen (categoryvalue) + 1);
+ ADD_BLOCK (block_list, single_locale);
+
+
+ /* Search for the given string. This is a loop because we perhaps
+ got an ordered list of languages to consider for th translation. */
+ while (1)
+ {
+ /* Make CATEGORYVALUE point to the next element of the list. */
+ while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
+ ++categoryvalue;
+ if (categoryvalue[0] == '\0')
+ {
+ /* The whole contents of CATEGORYVALUE has been searched but
+ no valid entry has been found. We solve this situation
+ by implicitly appending a "C" entry, i.e. no translation
+ will take place. */
+ single_locale[0] = 'C';
+ single_locale[1] = '\0';
+ }
+ else
+ {
+ char *cp = single_locale;
+ while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
+ *cp++ = *categoryvalue++;
+ *cp = '\0';
+ }
+
+ /* If the current locale value is C (or POSIX) we don't load a
+ domain. Return the MSGID. */
+ if (strcmp (single_locale, "C") == 0
+ || strcmp (single_locale, "POSIX") == 0)
+ {
+ FREE_BLOCKS (block_list);
+ __set_errno (saved_errno);
+ return (char *) msgid;
+ }
+
+
+ /* Find structure describing the message catalog matching the
+ DOMAINNAME and CATEGORY. */
+ domain = _nl_find_domain (dirname, single_locale, xdomainname);
+
+ if (domain != NULL)
+ {
+ retval = find_msg (domain, msgid);
+
+ if (retval == NULL)
+ {
+ int cnt;
+
+ for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
+ {
+ retval = find_msg (domain->successor[cnt], msgid);
+
+ if (retval != NULL)
+ break;
+ }
+ }
+
+ if (retval != NULL)
+ {
+ FREE_BLOCKS (block_list);
+ __set_errno (saved_errno);
+ return retval;
+ }
+ }
+ }
+ /* NOTREACHED */
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library. */
+weak_alias (__dcgettext, dcgettext);
+#endif
+
+
+static char *
+internal_function
+find_msg (domain_file, msgid)
+ struct loaded_l10nfile *domain_file;
+ const char *msgid;
+{
+ size_t top, act, bottom;
+ struct loaded_domain *domain;
+
+ if (domain_file->decided == 0)
+ _nl_load_domain (domain_file);
+
+ 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)
+ {
+ /* Use the hashing table. */
+ nls_uint32 len = strlen (msgid);
+ nls_uint32 hash_val = hash_string (msgid);
+ nls_uint32 idx = hash_val % domain->hash_size;
+ nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
+ nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
+
+ if (nstr == 0)
+ /* Hash table entry is empty. */
+ return NULL;
+
+ if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
+ && strcmp (msgid,
+ domain->data + W (domain->must_swap,
+ domain->orig_tab[nstr - 1].offset)) == 0)
+ return (char *) domain->data + W (domain->must_swap,
+ domain->trans_tab[nstr - 1].offset);
+
+ while (1)
+ {
+ if (idx >= domain->hash_size - incr)
+ idx -= domain->hash_size - incr;
+ else
+ idx += incr;
+
+ nstr = W (domain->must_swap, domain->hash_tab[idx]);
+ if (nstr == 0)
+ /* Hash table entry is empty. */
+ return NULL;
+
+ if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
+ && strcmp (msgid,
+ domain->data + W (domain->must_swap,
+ domain->orig_tab[nstr - 1].offset))
+ == 0)
+ return (char *) domain->data
+ + W (domain->must_swap, domain->trans_tab[nstr - 1].offset);
+ }
+ /* NOTREACHED */
+ }
+
+ /* Now we try the default method: binary search in the sorted
+ array of messages. */
+ bottom = 0;
+ top = domain->nstrings;
+ while (bottom < top)
+ {
+ int cmp_val;
+
+ act = (bottom + top) / 2;
+ cmp_val = strcmp (msgid, domain->data
+ + W (domain->must_swap,
+ domain->orig_tab[act].offset));
+ if (cmp_val < 0)
+ top = act;
+ else if (cmp_val > 0)
+ bottom = act + 1;
+ else
+ break;
+ }
+
+ /* If an translation is found return this. */
+ return bottom >= top ? NULL : (char *) domain->data
+ + W (domain->must_swap,
+ domain->trans_tab[act].offset);
+}
+
+
+/* Return string representation of locale CATEGORY. */
+static const char *
+internal_function
+category_to_name (category)
+ int category;
+{
+ const char *retval;
+
+ switch (category)
+ {
+#ifdef LC_COLLATE
+ case LC_COLLATE:
+ retval = "LC_COLLATE";
+ break;
+#endif
+#ifdef LC_CTYPE
+ case LC_CTYPE:
+ retval = "LC_CTYPE";
+ break;
+#endif
+#ifdef LC_MONETARY
+ case LC_MONETARY:
+ retval = "LC_MONETARY";
+ break;
+#endif
+#ifdef LC_NUMERIC
+ case LC_NUMERIC:
+ retval = "LC_NUMERIC";
+ break;
+#endif
+#ifdef LC_TIME
+ case LC_TIME:
+ retval = "LC_TIME";
+ break;
+#endif
+#ifdef LC_MESSAGES
+ case LC_MESSAGES:
+ retval = "LC_MESSAGES";
+ break;
+#endif
+#ifdef LC_RESPONSE
+ case LC_RESPONSE:
+ retval = "LC_RESPONSE";
+ break;
+#endif
+#ifdef LC_ALL
+ case LC_ALL:
+ /* This might not make sense but is perhaps better than any other
+ value. */
+ retval = "LC_ALL";
+ break;
+#endif
+ default:
+ /* If you have a better idea for a default value let me know. */
+ retval = "LC_XXX";
+ }
+
+ return retval;
+}
+
+/* Guess value of current locale from value of the environment variables. */
+static const char *
+internal_function
+guess_category_value (category, categoryname)
+ int category;
+ const char *categoryname;
+{
+ const char *retval;
+
+ /* The highest priority value is the `LANGUAGE' environment
+ variable. This is a GNU extension. */
+ retval = getenv ("LANGUAGE");
+ if (retval != NULL && retval[0] != '\0')
+ return retval;
+
+ /* `LANGUAGE' is not set. So we have to proceed with the POSIX
+ methods of looking to `LC_ALL', `LC_xxx', and `LANG'. On some
+ systems this can be done by the `setlocale' function itself. */
+#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
+ return setlocale (category, NULL);
+#else
+ /* Setting of LC_ALL overwrites all other. */
+ retval = getenv ("LC_ALL");
+ if (retval != NULL && retval[0] != '\0')
+ return retval;
+
+ /* Next comes the name of the desired category. */
+ retval = getenv (categoryname);
+ if (retval != NULL && retval[0] != '\0')
+ return retval;
+
+ /* Last possibility is the LANG environment variable. */
+ retval = getenv ("LANG");
+ if (retval != NULL && retval[0] != '\0')
+ return retval;
+
+ /* We use C as the default domain. POSIX says this is implementation
+ defined. */
+ return "C";
+#endif
+}
+
+/* @@ begin of epilog @@ */
+
+/* We don't want libintl.a to depend on any other library. So we
+ avoid the non-standard function stpcpy. In GNU C Library this
+ function is available, though. Also allow the symbol HAVE_STPCPY
+ to be defined. */
+#if !_LIBC && !HAVE_STPCPY
+static char *
+stpcpy (dest, src)
+ char *dest;
+ const char *src;
+{
+ while ((*dest++ = *src++) != '\0')
+ /* Do nothing. */ ;
+ return dest - 1;
+}
+#endif
+
+
+#ifdef _LIBC
+/* If we want to free all resources we have to do some work at
+ program's end. */
+static void __attribute__ ((unused))
+free_mem (void)
+{
+ struct binding *runp;
+
+ for (runp = _nl_domain_bindings; runp != NULL; runp = runp->next)
+ {
+ free (runp->domainname);
+ if (runp->dirname != _nl_default_dirname)
+ /* Yes, this is a pointer comparison. */
+ free (runp->dirname);
+ }
+
+ if (_nl_current_default_domain != _nl_default_default_domain)
+ /* Yes, again a pointer comparison. */
+ free ((char *) _nl_current_default_domain);
+}
+
+text_set_element (__libc_subfreeres, free_mem);
+#endif
diff --git a/intl/dgettext.c b/intl/dgettext.c
new file mode 100644
index 000000000..0510c2b07
--- /dev/null
+++ b/intl/dgettext.c
@@ -0,0 +1,59 @@
+/* Implementation of the dgettext(3) function
+ Copyright (C) 1995, 1996, 1997 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined HAVE_LOCALE_H || defined _LIBC
+# include <locale.h>
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+
+/* Names for the libintl functions are a problem. They must not clash
+ with existing names and they should follow ANSI C. But this source
+ code is also used in GNU C Library where the names have a __
+ prefix. So we have to make a difference here. */
+#ifdef _LIBC
+# define DGETTEXT __dgettext
+# define DCGETTEXT __dcgettext
+#else
+# define DGETTEXT dgettext__
+# define DCGETTEXT dcgettext__
+#endif
+
+/* Look up MSGID in the DOMAINNAME message catalog of the current
+ LC_MESSAGES locale. */
+char *
+DGETTEXT (domainname, msgid)
+ const char *domainname;
+ const char *msgid;
+{
+ return DCGETTEXT (domainname, msgid, LC_MESSAGES);
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library. */
+weak_alias (__dgettext, dgettext);
+#endif
diff --git a/intl/explodename.c b/intl/explodename.c
new file mode 100644
index 000000000..8066dc299
--- /dev/null
+++ b/intl/explodename.c
@@ -0,0 +1,188 @@
+/* Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#include <sys/types.h>
+
+#include "loadinfo.h"
+
+/* On some strange systems still no definition of NULL is found. Sigh! */
+#ifndef NULL
+# if defined __STDC__ && __STDC__
+# define NULL ((void *) 0)
+# else
+# define NULL 0
+# endif
+#endif
+
+/* @@ end of prolog @@ */
+
+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 syntax 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
new file mode 100644
index 000000000..81ea29bf4
--- /dev/null
+++ b/intl/finddomain.c
@@ -0,0 +1,216 @@
+/* Handle list of needed message catalogs
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+# ifdef HAVE_MALLOC_H
+# include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+# define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+# define strchr index
+# endif
+#endif
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+/* List of already loaded domains. */
+static struct loaded_l10nfile *_nl_loaded_domains;
+
+
+/* Return a data structure describing the message catalog described by
+ the DOMAINNAME and CATEGORY parameters with respect to the currently
+ established bindings. */
+struct loaded_l10nfile *
+internal_function
+_nl_find_domain (dirname, locale, domainname)
+ const char *dirname;
+ char *locale;
+ const char *domainname;
+{
+ struct loaded_l10nfile *retval;
+ 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;
+ const char *alias_value;
+ int mask;
+
+ /* LOCALE can consist of up to four recognized parts for the XPG syntax:
+
+ language[_territory[.codeset]][@modifier]
+
+ and six parts for the CEN syntax:
+
+ language[_territory][+audience][+special][,[sponsor][_revision]]
+
+ Beside the first part all of them are allowed to be missing. If
+ the full specified locale is not found, the less specific one are
+ looked for. The various parts will be stripped off according to
+ the following order:
+ (1) revision
+ (2) sponsor
+ (3) special
+ (4) codeset
+ (5) normalized codeset
+ (6) territory
+ (7) audience/modifier
+ */
+
+ /* If we have already tested for this locale entry there has to
+ be one data set in the list of loaded domains. */
+ 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);
+
+ if (retval->data != NULL)
+ return retval;
+
+ for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
+ {
+ if (retval->successor[cnt]->decided == 0)
+ _nl_load_domain (retval->successor[cnt]);
+
+ if (retval->successor[cnt]->data != NULL)
+ break;
+ }
+ return cnt >= 0 ? retval : NULL;
+ /* NOTREACHED */
+ }
+
+ /* See whether the locale value is an alias. If yes its value
+ *overwrites* the alias name. No test for the original value is
+ done. */
+ alias_value = _nl_expand_alias (locale);
+ if (alias_value != NULL)
+ {
+#if defined _LIBC || defined HAVE_STRDUP
+ locale = strdup (alias_value);
+ if (locale == NULL)
+ return NULL;
+#else
+ size_t len = strlen (alias_value) + 1;
+ locale = (char *) malloc (len);
+ if (locale == NULL)
+ return NULL;
+
+ memcpy (locale, alias_value, len);
+#endif
+ }
+
+ /* 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 = _nl_explode_name (locale, &language, &modifier, &territory,
+ &codeset, &normalized_codeset, &special,
+ &sponsor, &revision);
+
+ /* Create all possible locale entries which might be interested in
+ generalization. */
+ 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;
+
+ if (retval->decided == 0)
+ _nl_load_domain (retval);
+ if (retval->data == NULL)
+ {
+ int cnt;
+ for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
+ {
+ if (retval->successor[cnt]->decided == 0)
+ _nl_load_domain (retval->successor[cnt]);
+ if (retval->successor[cnt]->data != NULL)
+ break;
+ }
+ }
+
+ /* The room for an alias was dynamically allocated. Free it now. */
+ if (alias_value != NULL)
+ free (locale);
+
+ return retval;
+}
+
+
+#ifdef _LIBC
+static void __attribute__ ((unused))
+free_mem (void)
+{
+ struct loaded_l10nfile *runp = _nl_loaded_domains;
+
+ while (runp != NULL)
+ {
+ struct loaded_l10nfile *here = runp;
+ if (runp->data != NULL)
+ _nl_unload_domain ((struct loaded_domain *) runp->data);
+ runp = runp->next;
+ free (here);
+ }
+}
+
+text_set_element (__libc_subfreeres, free_mem);
+#endif
diff --git a/intl/gettext.c b/intl/gettext.c
new file mode 100644
index 000000000..d929f98d6
--- /dev/null
+++ b/intl/gettext.c
@@ -0,0 +1,70 @@
+/* Implementation of gettext(3) function.
+ Copyright (C) 1995, 1997 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define __need_NULL
+# include <stddef.h>
+#else
+# ifdef STDC_HEADERS
+# include <stdlib.h> /* Just for NULL. */
+# else
+# ifdef HAVE_STRING_H
+# include <string.h>
+# else
+# define NULL ((void *) 0)
+# endif
+# endif
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+
+/* Names for the libintl functions are a problem. They must not clash
+ with existing names and they should follow ANSI C. But this source
+ code is also used in GNU C Library where the names have a __
+ prefix. So we have to make a difference here. */
+#ifdef _LIBC
+# define GETTEXT __gettext
+# define DGETTEXT __dgettext
+#else
+# define GETTEXT gettext__
+# define DGETTEXT dgettext__
+#endif
+
+/* Look up MSGID in the current default message catalog for the current
+ LC_MESSAGES locale. If not found, returns MSGID itself (the default
+ text). */
+char *
+GETTEXT (msgid)
+ const char *msgid;
+{
+ return DGETTEXT (NULL, msgid);
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library. */
+weak_alias (__gettext, gettext);
+#endif
diff --git a/intl/gettext.h b/intl/gettext.h
new file mode 100644
index 000000000..3cd23d7d6
--- /dev/null
+++ b/intl/gettext.h
@@ -0,0 +1,105 @@
+/* Internal header for GNU gettext internationalization functions.
+ Copyright (C) 1995, 1997 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 Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _GETTEXT_H
+#define _GETTEXT_H 1
+
+#include <stdio.h>
+
+#if HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+/* @@ end of prolog @@ */
+
+/* The magic number of the GNU message catalog format. */
+#define _MAGIC 0x950412de
+#define _MAGIC_SWAPPED 0xde120495
+
+/* Revision number of the currently used .mo (binary) file format. */
+#define MO_REVISION_NUMBER 0
+
+/* The following contortions are an attempt to use the C preprocessor
+ to determine an unsigned integral type that is 32 bits wide. An
+ alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+ doing that would require that the configure script compile and *run*
+ the resulting executable. Locally running cross-compiled executables
+ is usually not possible. */
+
+#if __STDC__
+# define UINT_MAX_32_BITS 4294967295U
+#else
+# define UINT_MAX_32_BITS 0xFFFFFFFF
+#endif
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+ This should be valid for all systems GNU cares about because
+ that doesn't include 16-bit systems, and only modern systems
+ (that certainly have <limits.h>) have 64+-bit integral types. */
+
+#ifndef UINT_MAX
+# define UINT_MAX UINT_MAX_32_BITS
+#endif
+
+#if UINT_MAX == UINT_MAX_32_BITS
+typedef unsigned nls_uint32;
+#else
+# if USHRT_MAX == UINT_MAX_32_BITS
+typedef unsigned short nls_uint32;
+# else
+# if ULONG_MAX == UINT_MAX_32_BITS
+typedef unsigned long nls_uint32;
+# else
+ /* The following line is intended to throw an error. Using #error is
+ not portable enough. */
+ "Cannot determine unsigned 32-bit data type."
+# endif
+# endif
+#endif
+
+
+/* Header for binary .mo file format. */
+struct mo_file_header
+{
+ /* The magic number. */
+ nls_uint32 magic;
+ /* The revision number of the file format. */
+ nls_uint32 revision;
+ /* The number of strings pairs. */
+ nls_uint32 nstrings;
+ /* Offset of table with start offsets of original strings. */
+ nls_uint32 orig_tab_offset;
+ /* Offset of table with start offsets of translation strings. */
+ nls_uint32 trans_tab_offset;
+ /* Size of hashing table. */
+ nls_uint32 hash_tab_size;
+ /* Offset of first hashing entry. */
+ nls_uint32 hash_tab_offset;
+};
+
+struct string_desc
+{
+ /* Length of addressed string. */
+ nls_uint32 length;
+ /* Offset of string in file. */
+ nls_uint32 offset;
+};
+
+/* @@ begin of epilog @@ */
+
+#endif /* gettext.h */
diff --git a/intl/gettextP.h b/intl/gettextP.h
new file mode 100644
index 000000000..00c520319
--- /dev/null
+++ b/intl/gettextP.h
@@ -0,0 +1,89 @@
+/* Header describing internals of gettext library
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+ 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. */
+
+#ifndef _GETTEXTP_H
+#define _GETTEXTP_H
+
+#include "loadinfo.h"
+
+/* @@ end of prolog @@ */
+
+#ifndef PARAMS
+# if __STDC__
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif
+#endif
+
+#ifndef internal_function
+# define internal_function
+#endif
+
+#ifndef W
+# define W(flag, data) ((flag) ? SWAP (data) : (data))
+#endif
+
+
+#ifdef _LIBC
+# include <byteswap.h>
+# define SWAP(i) bswap_32 (i)
+#else
+static nls_uint32 SWAP PARAMS ((nls_uint32 i));
+
+static inline nls_uint32
+SWAP (i)
+ nls_uint32 i;
+{
+ return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
+}
+#endif
+
+
+struct loaded_domain
+{
+ const char *data;
+ int use_mmap;
+ size_t mmap_size;
+ int must_swap;
+ nls_uint32 nstrings;
+ struct string_desc *orig_tab;
+ struct string_desc *trans_tab;
+ nls_uint32 hash_size;
+ nls_uint32 *hash_tab;
+};
+
+struct binding
+{
+ struct binding *next;
+ char *domainname;
+ char *dirname;
+};
+
+struct loaded_l10nfile *_nl_find_domain PARAMS ((const char *__dirname,
+ char *__locale,
+ const char *__domainname))
+ internal_function;
+void _nl_load_domain PARAMS ((struct loaded_l10nfile *__domain))
+ internal_function;
+void _nl_unload_domain PARAMS ((struct loaded_domain *__domain))
+ internal_function;
+
+/* @@ begin of epilog @@ */
+
+#endif /* gettextP.h */
diff --git a/intl/hash-string.h b/intl/hash-string.h
new file mode 100644
index 000000000..cacb38e47
--- /dev/null
+++ b/intl/hash-string.h
@@ -0,0 +1,59 @@
+/* Implements a string hashing function.
+ Copyright (C) 1995, 1997 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 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. */
+
+/* @@ end of prolog @@ */
+
+#ifndef PARAMS
+# if __STDC__
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+/* We assume to have `unsigned long int' value with at least 32 bits. */
+#define HASHWORDBITS 32
+
+
+/* Defines the so called `hashpjw' function by P.J. Weinberger
+ [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
+ 1986, 1987 Bell Telephone Laboratories, Inc.] */
+static unsigned long hash_string PARAMS ((const char *__str_param));
+
+static inline unsigned long
+hash_string (str_param)
+ const char *str_param;
+{
+ unsigned long int hval, g;
+ const char *str = str_param;
+
+ /* Compute the hash value for the given string. */
+ hval = 0;
+ while (*str != '\0')
+ {
+ hval <<= 4;
+ hval += (unsigned long) *str++;
+ g = hval & ((unsigned long) 0xf << (HASHWORDBITS - 4));
+ if (g != 0)
+ {
+ hval ^= g >> (HASHWORDBITS - 8);
+ hval ^= g;
+ }
+ }
+ return hval;
+}
diff --git a/intl/intl-compat.c b/intl/intl-compat.c
new file mode 100644
index 000000000..503efa0fa
--- /dev/null
+++ b/intl/intl-compat.c
@@ -0,0 +1,76 @@
+/* intl-compat.c - Stub functions to call gettext functions from GNU gettext
+ Library.
+ Copyright (C) 1995 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libgettext.h"
+
+/* @@ end of prolog @@ */
+
+
+#undef gettext
+#undef dgettext
+#undef dcgettext
+#undef textdomain
+#undef bindtextdomain
+
+
+char *
+bindtextdomain (domainname, dirname)
+ const char *domainname;
+ const char *dirname;
+{
+ return bindtextdomain__ (domainname, dirname);
+}
+
+
+char *
+dcgettext (domainname, msgid, category)
+ const char *domainname;
+ const char *msgid;
+ int category;
+{
+ return dcgettext__ (domainname, msgid, category);
+}
+
+
+char *
+dgettext (domainname, msgid)
+ const char *domainname;
+ const char *msgid;
+{
+ return dgettext__ (domainname, msgid);
+}
+
+
+char *
+gettext (msgid)
+ const char *msgid;
+{
+ return gettext__ (msgid);
+}
+
+
+char *
+textdomain (domainname)
+ const char *domainname;
+{
+ return textdomain__ (domainname);
+}
diff --git a/intl/l10nflist.c b/intl/l10nflist.c
new file mode 100644
index 000000000..9c7dc1836
--- /dev/null
+++ b/intl/l10nflist.c
@@ -0,0 +1,411 @@
+/* Handle list of needed message catalogs
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+
+#if defined HAVE_STRING_H || defined _LIBC
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+# endif
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+# define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+# define strchr index
+# endif
+#endif
+
+#if defined _LIBC || defined HAVE_ARGZ_H
+# include <argz.h>
+#endif
+#include <ctype.h>
+#include <sys/types.h>
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#include "loadinfo.h"
+
+/* On some strange systems still no definition of NULL is found. Sigh! */
+#ifndef NULL
+# if defined __STDC__ && __STDC__
+# define NULL ((void *) 0)
+# else
+# define NULL 0
+# endif
+#endif
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ANSI C functions. This is required by the standard
+ because some ANSI C functions will require linking with this object
+ file and the name space must not be polluted. */
+# ifndef stpcpy
+# define stpcpy(dest, src) __stpcpy(dest, src)
+# endif
+#else
+# ifndef HAVE_STPCPY
+static char *stpcpy PARAMS ((char *dest, const char *src));
+# endif
+#endif
+
+/* Define function which are usually not available. */
+
+#if !defined _LIBC && !defined HAVE___ARGZ_COUNT
+/* Returns the number of strings in ARGZ. */
+static size_t argz_count__ PARAMS ((const char *argz, size_t len));
+
+static size_t
+argz_count__ (argz, len)
+ const char *argz;
+ size_t len;
+{
+ size_t count = 0;
+ while (len > 0)
+ {
+ size_t part_len = strlen (argz);
+ argz += part_len + 1;
+ len -= part_len + 1;
+ count++;
+ }
+ return count;
+}
+# undef __argz_count
+# define __argz_count(argz, len) argz_count__ (argz, len)
+#endif /* !_LIBC && !HAVE___ARGZ_COUNT */
+
+#if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
+/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
+ except the last into the character SEP. */
+static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
+
+static void
+argz_stringify__ (argz, len, sep)
+ char *argz;
+ size_t len;
+ int sep;
+{
+ while (len > 0)
+ {
+ size_t part_len = strlen (argz);
+ argz += part_len;
+ len -= part_len + 1;
+ if (len > 0)
+ *argz++ = sep;
+ }
+}
+# undef __argz_stringify
+# define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
+#endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
+
+#if !defined _LIBC && !defined HAVE___ARGZ_NEXT
+static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
+ const char *entry));
+
+static char *
+argz_next__ (argz, argz_len, entry)
+ char *argz;
+ size_t argz_len;
+ const char *entry;
+{
+ if (entry)
+ {
+ if (entry < argz + argz_len)
+ entry = strchr (entry, '\0') + 1;
+
+ return entry >= argz + argz_len ? NULL : (char *) entry;
+ }
+ else
+ if (argz_len > 0)
+ return argz;
+ else
+ return 0;
+}
+# undef __argz_next
+# define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
+#endif /* !_LIBC && !HAVE___ARGZ_NEXT */
+
+
+/* Return number of bits set in X. */
+static int pop PARAMS ((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
+ || (mask & CEN_REVISION) != 0)
+ ? (1 + ((mask & CEN_SPONSOR) != 0
+ ? strlen (sponsor) + 1 : 0)
+ + ((mask & CEN_REVISION) != 0
+ ? strlen (revision) + 1 : 0)) : 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 | CEN_REVISION)) != 0)
+ {
+ *cp++ = ',';
+ if ((mask & CEN_SPONSOR) != 0)
+ 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 corresponds not to
+ a real file. So we have to use the DIRLIST separation mechanism
+ 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 unsigned 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;
+}
+
+
+/* @@ begin of epilog @@ */
+
+/* We don't want libintl.a to depend on any other library. So we
+ avoid the non-standard function stpcpy. In GNU C Library this
+ function is available, though. Also allow the symbol HAVE_STPCPY
+ to be defined. */
+#if !_LIBC && !HAVE_STPCPY
+static char *
+stpcpy (dest, src)
+ char *dest;
+ const char *src;
+{
+ while ((*dest++ = *src++) != '\0')
+ /* Do nothing. */ ;
+ return dest - 1;
+}
+#endif
diff --git a/intl/libgettext.h b/intl/libgettext.h
new file mode 100644
index 000000000..3a92960ae
--- /dev/null
+++ b/intl/libgettext.h
@@ -0,0 +1,182 @@
+/* Message catalogs for internationalization.
+ Copyright (C) 1995, 1996, 1997, 1998 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. */
+
+/* Because on some systems (e.g. Solaris) we sometimes have to include
+ the systems libintl.h as well as this file we have more complex
+ include protection above. But the systems header might perhaps also
+ define _LIBINTL_H and therefore we have to protect the definition here. */
+
+#if !defined _LIBINTL_H || !defined _LIBGETTEXT_H
+#ifndef _LIBINTL_H
+# define _LIBINTL_H 1
+#endif
+#define _LIBGETTEXT_H 1
+
+/* We define an additional symbol to signal that we use the GNU
+ implementation of gettext. */
+#define __USE_GNU_GETTEXT 1
+
+#include <sys/types.h>
+
+#if HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* @@ end of prolog @@ */
+
+#ifndef PARAMS
+# if __STDC__ || defined __cplusplus
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif
+#endif
+
+#ifndef NULL
+# if !defined __cplusplus || defined __GNUC__
+# define NULL ((void *) 0)
+# else
+# define NULL (0)
+# endif
+#endif
+
+#if !HAVE_LC_MESSAGES
+/* This value determines the behaviour of the gettext() and dgettext()
+ function. But some system does not have this defined. Define it
+ to a default value. */
+# define LC_MESSAGES (-1)
+#endif
+
+
+/* Declarations for gettext-using-catgets interface. Derived from
+ Jim Meyering's libintl.h. */
+struct _msg_ent
+{
+ const char *_msg;
+ int _msg_number;
+};
+
+
+#if HAVE_CATGETS
+/* These two variables are defined in the automatically by po-to-tbl.sed
+ generated file `cat-id-tbl.c'. */
+extern const struct _msg_ent _msg_tbl[];
+extern int _msg_tbl_length;
+#endif
+
+
+/* For automatical extraction of messages sometimes no real
+ translation is needed. Instead the string itself is the result. */
+#define gettext_noop(Str) (Str)
+
+/* Look up MSGID in the current default message catalog for the current
+ LC_MESSAGES locale. If not found, returns MSGID itself (the default
+ text). */
+extern char *gettext PARAMS ((const char *__msgid));
+extern char *gettext__ PARAMS ((const char *__msgid));
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current
+ LC_MESSAGES locale. */
+extern char *dgettext PARAMS ((const char *__domainname, const char *__msgid));
+extern char *dgettext__ PARAMS ((const char *__domainname,
+ const char *__msgid));
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
+ locale. */
+extern char *dcgettext PARAMS ((const char *__domainname, const char *__msgid,
+ int __category));
+extern char *dcgettext__ PARAMS ((const char *__domainname,
+ const char *__msgid, int __category));
+
+
+/* Set the current default message catalog to DOMAINNAME.
+ If DOMAINNAME is null, return the current default.
+ If DOMAINNAME is "", reset to the default of "messages". */
+extern char *textdomain PARAMS ((const char *__domainname));
+extern char *textdomain__ PARAMS ((const char *__domainname));
+
+/* Specify that the DOMAINNAME message catalog will be found
+ in DIRNAME rather than in the system locale data base. */
+extern char *bindtextdomain PARAMS ((const char *__domainname,
+ const char *__dirname));
+extern char *bindtextdomain__ PARAMS ((const char *__domainname,
+ const char *__dirname));
+
+#if ENABLE_NLS
+
+/* Solaris 2.3 has the gettext function but dcgettext is missing.
+ So we omit this optimization for Solaris 2.3. BTW, Solaris 2.4
+ has dcgettext. */
+# if !HAVE_CATGETS && (!HAVE_GETTEXT || HAVE_DCGETTEXT)
+
+# define gettext(Msgid) \
+ dgettext (NULL, Msgid)
+
+# define dgettext(Domainname, Msgid) \
+ dcgettext (Domainname, Msgid, LC_MESSAGES)
+
+# if defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ >= 7
+/* This global variable is defined in loadmsgcat.c. We need a sign,
+ whether a new catalog was loaded, which can be associated with all
+ translations. */
+extern int _nl_msg_cat_cntr;
+
+# define dcgettext(Domainname, Msgid, Category) \
+ (__extension__ \
+ ({ \
+ char *__result; \
+ if (__builtin_constant_p (Msgid)) \
+ { \
+ static char *__translation__; \
+ static int __catalog_counter__; \
+ if (! __translation__ || __catalog_counter__ != _nl_msg_cat_cntr) \
+ { \
+ __translation__ = \
+ dcgettext__ (Domainname, Msgid, Category); \
+ __catalog_counter__ = _nl_msg_cat_cntr; \
+ } \
+ __result = __translation__; \
+ } \
+ else \
+ __result = dcgettext__ (Domainname, Msgid, Category); \
+ __result; \
+ }))
+# endif
+# endif
+
+#else
+
+# define gettext(Msgid) (Msgid)
+# define dgettext(Domainname, Msgid) (Msgid)
+# define dcgettext(Domainname, Msgid, Category) (Msgid)
+# define textdomain(Domainname) ((char *) Domainname)
+# define bindtextdomain(Domainname, Dirname) ((char *) Dirname)
+
+#endif
+
+/* @@ begin of epilog @@ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/intl/loadinfo.h b/intl/loadinfo.h
new file mode 100644
index 000000000..f4ebf6d81
--- /dev/null
+++ b/intl/loadinfo.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+ 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. */
+
+#ifndef PARAMS
+# if __STDC__
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif
+#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)
+
+
+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 PARAMS ((const unsigned char *codeset,
+ size_t name_len));
+
+extern struct loaded_l10nfile *
+_nl_make_l10nflist PARAMS ((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 PARAMS ((const char *name));
+
+extern int _nl_explode_name PARAMS ((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
new file mode 100644
index 000000000..515892dfb
--- /dev/null
+++ b/intl/loadmsgcat.c
@@ -0,0 +1,222 @@
+/* Load needed message catalogs.
+ Copyright (C) 1995, 1996, 1997, 1998 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP) || defined _LIBC
+# include <sys/mman.h>
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ISO C functions. This is required by the standard
+ because some ISO C functions will require linking with this object
+ file and the name space must not be polluted. */
+# define open __open
+# define close __close
+# define read __read
+# define mmap __mmap
+# define munmap __munmap
+#endif
+
+/* We need a sign, whether a new catalog was loaded, which can be associated
+ with all translations. This is important if the translations are
+ cached by one of GCC's features. */
+int _nl_msg_cat_cntr = 0;
+
+
+/* Load the message catalogs specified by FILENAME. If it is no valid
+ message catalog do nothing. */
+void
+internal_function
+_nl_load_domain (domain_file)
+ struct loaded_l10nfile *domain_file;
+{
+ int fd;
+ size_t size;
+ struct stat st;
+ struct mo_file_header *data = (struct mo_file_header *) -1;
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+ || defined _LIBC
+ int use_mmap = 0;
+#endif
+ struct loaded_domain *domain;
+
+ 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_file->filename == NULL)
+ return;
+
+ /* Try to open the addressed file. */
+ fd = open (domain_file->filename, O_RDONLY);
+ if (fd == -1)
+ return;
+
+ /* We must know about the size of the file. */
+ if (fstat (fd, &st) != 0
+ || (size = (size_t) st.st_size) != st.st_size
+ || size < sizeof (struct mo_file_header))
+ {
+ /* Something went wrong. */
+ close (fd);
+ return;
+ }
+
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+ || defined _LIBC
+ /* Now we are ready to load the file. If mmap() is available we try
+ this first. If not available or it failed we try to load it. */
+ data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
+ MAP_PRIVATE, fd, 0);
+
+ if (data != (struct mo_file_header *) -1)
+ {
+ /* mmap() call was successful. */
+ close (fd);
+ use_mmap = 1;
+ }
+#endif
+
+ /* If the data is not yet available (i.e. mmap'ed) we try to load
+ it manually. */
+ if (data == (struct mo_file_header *) -1)
+ {
+ size_t to_read;
+ char *read_ptr;
+
+ data = (struct mo_file_header *) malloc (size);
+ if (data == NULL)
+ return;
+
+ to_read = size;
+ read_ptr = (char *) data;
+ do
+ {
+ long int nb = (long int) read (fd, read_ptr, to_read);
+ if (nb == -1)
+ {
+ close (fd);
+ return;
+ }
+
+ read_ptr += nb;
+ to_read -= nb;
+ }
+ while (to_read > 0);
+
+ close (fd);
+ }
+
+ /* Using the magic number we can test whether it really is a message
+ catalog file. */
+ if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
+ {
+ /* The magic number is wrong: not a message catalog file. */
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+ || defined _LIBC
+ if (use_mmap)
+ munmap ((caddr_t) data, size);
+ else
+#endif
+ free (data);
+ return;
+ }
+
+ domain_file->data
+ = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
+ if (domain_file->data == NULL)
+ return;
+
+ domain = (struct loaded_domain *) domain_file->data;
+ domain->data = (char *) data;
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+ || defined _LIBC
+ domain->use_mmap = use_mmap;
+#endif
+ domain->mmap_size = size;
+ domain->must_swap = data->magic != _MAGIC;
+
+ /* Fill in the information about the available tables. */
+ switch (W (domain->must_swap, data->revision))
+ {
+ case 0:
+ domain->nstrings = W (domain->must_swap, data->nstrings);
+ domain->orig_tab = (struct string_desc *)
+ ((char *) data + W (domain->must_swap, data->orig_tab_offset));
+ domain->trans_tab = (struct string_desc *)
+ ((char *) data + W (domain->must_swap, data->trans_tab_offset));
+ domain->hash_size = W (domain->must_swap, data->hash_tab_size);
+ domain->hash_tab = (nls_uint32 *)
+ ((char *) data + W (domain->must_swap, data->hash_tab_offset));
+ break;
+ default:
+ /* This is an illegal revision. */
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+ || defined _LIBC
+ if (use_mmap)
+ munmap ((caddr_t) data, size);
+ else
+#endif
+ free (data);
+ free (domain);
+ domain_file->data = NULL;
+ return;
+ }
+
+ /* Show that one domain is changed. This might make some cached
+ translations invalid. */
+ ++_nl_msg_cat_cntr;
+}
+
+
+#ifdef _LIBC
+void
+internal_function
+_nl_unload_domain (domain)
+ struct loaded_domain *domain;
+{
+ if (domain->use_mmap)
+ munmap ((caddr_t) domain->data, domain->mmap_size);
+ else
+ free ((void *) domain->data);
+
+ free (domain);
+}
+#endif
diff --git a/intl/localealias.c b/intl/localealias.c
new file mode 100644
index 000000000..bca555a61
--- /dev/null
+++ b/intl/localealias.c
@@ -0,0 +1,424 @@
+/* Handle aliases for locale names.
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+#else
+# if defined HAVE_ALLOCA_H || defined _LIBC
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca
+char *alloca ();
+# endif
+# endif
+# endif
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+char *getenv ();
+# ifdef HAVE_MALLOC_H
+# include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+# endif
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+# define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+# define strchr index
+# endif
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ANSI C functions. This is required by the standard
+ because some ANSI C functions will require linking with this object
+ file and the name space must not be polluted. */
+# define strcasecmp __strcasecmp
+
+# define mempcpy __mempcpy
+# define HAVE_MEMPCPY 1
+
+/* We need locking here since we can be called from different places. */
+# include <bits/libc-lock.h>
+
+__libc_lock_define_initialized (static, lock);
+#endif
+
+
+/* For those loosing systems which don't have `alloca' we have to add
+ some additional code emulating it. */
+#ifdef HAVE_ALLOCA
+/* Nothing has to be done. */
+# define ADD_BLOCK(list, address) /* nothing */
+# define FREE_BLOCKS(list) /* nothing */
+#else
+struct block_list
+{
+ void *address;
+ struct block_list *next;
+};
+# define ADD_BLOCK(list, addr) \
+ do { \
+ struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
+ /* If we cannot get a free block we cannot add the new element to \
+ the list. */ \
+ if (newp != NULL) { \
+ newp->address = (addr); \
+ newp->next = (list); \
+ (list) = newp; \
+ } \
+ } while (0)
+# define FREE_BLOCKS(list) \
+ do { \
+ while (list != NULL) { \
+ struct block_list *old = list; \
+ list = list->next; \
+ free (old); \
+ } \
+ } while (0)
+# undef alloca
+# define alloca(size) (malloc (size))
+#endif /* have alloca */
+
+
+struct alias_map
+{
+ const char *alias;
+ const char *value;
+};
+
+
+static char *string_space = NULL;
+static size_t string_space_act = 0;
+static size_t string_space_max = 0;
+static struct alias_map *map;
+static size_t nmap = 0;
+static size_t maxmap = 0;
+
+
+/* Prototypes for local functions. */
+static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
+ internal_function;
+static void extend_alias_table PARAMS ((void));
+static int alias_compare PARAMS ((const struct alias_map *map1,
+ const struct alias_map *map2));
+
+
+const char *
+_nl_expand_alias (name)
+ const char *name;
+{
+ static const char *locale_alias_path = LOCALE_ALIAS_PATH;
+ struct alias_map *retval;
+ const char *result = NULL;
+ size_t added;
+
+#ifdef _LIBC
+ __libc_lock_lock (lock);
+#endif
+
+ do
+ {
+ struct alias_map item;
+
+ item.alias = name;
+
+ if (nmap > 0)
+ retval = (struct alias_map *) bsearch (&item, map, nmap,
+ sizeof (struct alias_map),
+ (int (*) PARAMS ((const void *,
+ const void *))
+ ) alias_compare);
+ else
+ retval = NULL;
+
+ /* We really found an alias. Return the value. */
+ if (retval != NULL)
+ {
+ result = retval->value;
+ break;
+ }
+
+ /* Perhaps we can find another alias file. */
+ added = 0;
+ while (added == 0 && locale_alias_path[0] != '\0')
+ {
+ const char *start;
+
+ while (locale_alias_path[0] == ':')
+ ++locale_alias_path;
+ start = locale_alias_path;
+
+ while (locale_alias_path[0] != '\0' && locale_alias_path[0] != ':')
+ ++locale_alias_path;
+
+ if (start < locale_alias_path)
+ added = read_alias_file (start, locale_alias_path - start);
+ }
+ }
+ while (added != 0);
+
+#ifdef _LIBC
+ __libc_lock_unlock (lock);
+#endif
+
+ return result;
+}
+
+
+static size_t
+internal_function
+read_alias_file (fname, fname_len)
+ const char *fname;
+ int fname_len;
+{
+#ifndef HAVE_ALLOCA
+ struct block_list *block_list = NULL;
+#endif
+ FILE *fp;
+ char *full_fname;
+ size_t added;
+ static const char aliasfile[] = "/locale.alias";
+
+ full_fname = (char *) alloca (fname_len + sizeof aliasfile);
+ ADD_BLOCK (block_list, full_fname);
+#ifdef HAVE_MEMPCPY
+ mempcpy (mempcpy (full_fname, fname, fname_len),
+ aliasfile, sizeof aliasfile);
+#else
+ memcpy (full_fname, fname, fname_len);
+ memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
+#endif
+
+ fp = fopen (full_fname, "r");
+ if (fp == NULL)
+ {
+ FREE_BLOCKS (block_list);
+ return 0;
+ }
+
+ added = 0;
+ while (!feof (fp))
+ {
+ /* It is a reasonable approach to use a fix buffer here because
+ a) we are only interested in the first two fields
+ b) these fields must be usable as file names and so must not
+ be that long
+ */
+ unsigned char buf[BUFSIZ];
+ unsigned char *alias;
+ unsigned char *value;
+ unsigned char *cp;
+
+ if (fgets (buf, sizeof buf, fp) == NULL)
+ /* EOF reached. */
+ break;
+
+ /* Possibly not the whole line fits into the buffer. Ignore
+ the rest of the line. */
+ if (strchr (buf, '\n') == NULL)
+ {
+ char altbuf[BUFSIZ];
+ do
+ if (fgets (altbuf, sizeof altbuf, fp) == NULL)
+ /* Make sure the inner loop will be left. The outer loop
+ will exit at the `feof' test. */
+ break;
+ while (strchr (altbuf, '\n') == NULL);
+ }
+
+ cp = buf;
+ /* Ignore leading white space. */
+ while (isspace (cp[0]))
+ ++cp;
+
+ /* A leading '#' signals a comment line. */
+ if (cp[0] != '\0' && cp[0] != '#')
+ {
+ alias = cp++;
+ while (cp[0] != '\0' && !isspace (cp[0]))
+ ++cp;
+ /* Terminate alias name. */
+ if (cp[0] != '\0')
+ *cp++ = '\0';
+
+ /* Now look for the beginning of the value. */
+ while (isspace (cp[0]))
+ ++cp;
+
+ if (cp[0] != '\0')
+ {
+ size_t alias_len;
+ size_t value_len;
+
+ value = cp++;
+ while (cp[0] != '\0' && !isspace (cp[0]))
+ ++cp;
+ /* Terminate value. */
+ if (cp[0] == '\n')
+ {
+ /* This has to be done to make the following test
+ for the end of line possible. We are looking for
+ the terminating '\n' which do not overwrite here. */
+ *cp++ = '\0';
+ *cp = '\n';
+ }
+ else if (cp[0] != '\0')
+ *cp++ = '\0';
+
+ if (nmap >= maxmap)
+ extend_alias_table ();
+
+ alias_len = strlen (alias) + 1;
+ value_len = strlen (value) + 1;
+
+ if (string_space_act + alias_len + value_len > string_space_max)
+ {
+ /* Increase size of memory pool. */
+ size_t new_size = (string_space_max
+ + (alias_len + value_len > 1024
+ ? alias_len + value_len : 1024));
+ char *new_pool = (char *) realloc (string_space, new_size);
+ if (new_pool == NULL)
+ {
+ FREE_BLOCKS (block_list);
+ return added;
+ }
+ string_space = new_pool;
+ string_space_max = new_size;
+ }
+
+ map[nmap].alias = memcpy (&string_space[string_space_act],
+ alias, alias_len);
+ string_space_act += alias_len;
+
+ map[nmap].value = memcpy (&string_space[string_space_act],
+ value, value_len);
+ string_space_act += value_len;
+
+ ++nmap;
+ ++added;
+ }
+ }
+ }
+
+ /* Should we test for ferror()? I think we have to silently ignore
+ errors. --drepper */
+ fclose (fp);
+
+ if (added > 0)
+ qsort (map, nmap, sizeof (struct alias_map),
+ (int (*) PARAMS ((const void *, const void *))) alias_compare);
+
+ FREE_BLOCKS (block_list);
+ return added;
+}
+
+
+static void
+extend_alias_table ()
+{
+ size_t new_size;
+ struct alias_map *new_map;
+
+ new_size = maxmap == 0 ? 100 : 2 * maxmap;
+ new_map = (struct alias_map *) realloc (map, (new_size
+ * sizeof (struct alias_map)));
+ if (new_map == NULL)
+ /* Simply don't extend: we don't have any more core. */
+ return;
+
+ map = new_map;
+ maxmap = new_size;
+}
+
+
+#ifdef _LIBC
+static void __attribute__ ((unused))
+free_mem (void)
+{
+ if (string_space != NULL)
+ free (string_space);
+ if (map != NULL)
+ free (map);
+}
+text_set_element (__libc_subfreeres, free_mem);
+#endif
+
+
+static int
+alias_compare (map1, map2)
+ const struct alias_map *map1;
+ const struct alias_map *map2;
+{
+#if defined _LIBC || defined HAVE_STRCASECMP
+ return strcasecmp (map1->alias, map2->alias);
+#else
+ const unsigned char *p1 = (const unsigned char *) map1->alias;
+ const unsigned char *p2 = (const unsigned char *) map2->alias;
+ unsigned char c1, c2;
+
+ if (p1 == p2)
+ return 0;
+
+ do
+ {
+ /* I know this seems to be odd but the tolower() function in
+ some systems libc cannot handle nonalpha characters. */
+ c1 = isupper (*p1) ? tolower (*p1) : *p1;
+ c2 = isupper (*p2) ? tolower (*p2) : *p2;
+ if (c1 == '\0')
+ break;
+ ++p1;
+ ++p2;
+ }
+ while (c1 == c2);
+
+ return c1 - c2;
+#endif
+}
diff --git a/intl/textdomain.c b/intl/textdomain.c
new file mode 100644
index 000000000..88557460f
--- /dev/null
+++ b/intl/textdomain.c
@@ -0,0 +1,108 @@
+/* Implementation of the textdomain(3) function.
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#if defined STDC_HEADERS || defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+# define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+
+/* Name of the default text domain. */
+extern const char _nl_default_default_domain[];
+
+/* Default text domain in which entries for gettext(3) are to be found. */
+extern const char *_nl_current_default_domain;
+
+
+/* Names for the libintl functions are a problem. They must not clash
+ with existing names and they should follow ANSI C. But this source
+ code is also used in GNU C Library where the names have a __
+ prefix. So we have to make a difference here. */
+#ifdef _LIBC
+# define TEXTDOMAIN __textdomain
+# ifndef strdup
+# define strdup(str) __strdup (str)
+# endif
+#else
+# define TEXTDOMAIN textdomain__
+#endif
+
+/* Set the current default message catalog to DOMAINNAME.
+ If DOMAINNAME is null, return the current default.
+ If DOMAINNAME is "", reset to the default of "messages". */
+char *
+TEXTDOMAIN (domainname)
+ const char *domainname;
+{
+ char *old;
+
+ /* A NULL pointer requests the current setting. */
+ if (domainname == NULL)
+ return (char *) _nl_current_default_domain;
+
+ old = (char *) _nl_current_default_domain;
+
+ /* If domain name is the null string set to default domain "messages". */
+ if (domainname[0] == '\0'
+ || strcmp (domainname, _nl_default_default_domain) == 0)
+ _nl_current_default_domain = _nl_default_default_domain;
+ else
+ {
+ /* If the following malloc fails `_nl_current_default_domain'
+ will be NULL. This value will be returned and so signals we
+ are out of core. */
+#if defined _LIBC || defined HAVE_STRDUP
+ _nl_current_default_domain = strdup (domainname);
+#else
+ size_t len = strlen (domainname) + 1;
+ char *cp = (char *) malloc (len);
+ if (cp != NULL)
+ memcpy (cp, domainname, len);
+ _nl_current_default_domain = cp;
+#endif
+ }
+
+ if (old != _nl_default_default_domain)
+ free (old);
+
+ return (char *) _nl_current_default_domain;
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library. */
+weak_alias (__textdomain, textdomain);
+#endif