summaryrefslogtreecommitdiff
path: root/intl
diff options
context:
space:
mode:
authorkazer_ <kazer_@ffa7fe5e-494d-0410-b361-a75ebd5db220>2007-07-10 12:22:11 +0000
committerkazer_ <kazer_@ffa7fe5e-494d-0410-b361-a75ebd5db220>2007-07-10 12:22:11 +0000
commitff58e178b3d3b69ae53654bca5e350f23aab2937 (patch)
tree2350a565d0ea7a18c0e4200f9d06b01601a0b65b /intl
parent20594dcd34b537bd5d6cb63a881e293576b5dcbb (diff)
downloadnavit-ff58e178b3d3b69ae53654bca5e350f23aab2937.tar.gz
Working on i18n
git-svn-id: http://svn.code.sf.net/p/navit/code/trunk/navit@290 ffa7fe5e-494d-0410-b361-a75ebd5db220
Diffstat (limited to 'intl')
-rw-r--r--intl/bindtextdom.c357
-rw-r--r--intl/dcgettext.c56
-rw-r--r--intl/dcigettext.c1654
-rw-r--r--intl/dcngettext.c57
-rw-r--r--intl/dgettext.c58
-rw-r--r--intl/dngettext.c59
-rw-r--r--intl/eval-plural.h108
-rw-r--r--intl/explodename.c133
-rw-r--r--intl/export.h6
-rw-r--r--intl/finddomain.c208
-rw-r--r--intl/gettext.c63
-rw-r--r--intl/gettextP.h247
-rw-r--r--intl/gmo.h149
-rw-r--r--intl/hash-string.c51
-rw-r--r--intl/hash-string.h36
-rw-r--r--intl/intl-compat.c133
-rw-r--r--intl/intl-exports.c36
-rw-r--r--intl/l10nflist.c400
-rw-r--r--intl/langprefs.c130
-rw-r--r--intl/loadinfo.h132
-rw-r--r--intl/loadmsgcat.c1333
-rw-r--r--intl/localcharset.c461
-rw-r--r--intl/localcharset.h42
-rw-r--r--intl/localealias.c437
-rw-r--r--intl/localename.c1499
-rw-r--r--intl/lock.c922
-rw-r--r--intl/lock.h833
-rw-r--r--intl/log.c116
-rw-r--r--intl/ngettext.c65
-rw-r--r--intl/os2compat.c98
-rw-r--r--intl/os2compat.h46
-rw-r--r--intl/osdep.c26
-rw-r--r--intl/plural-exp.c154
-rw-r--r--intl/plural-exp.h118
-rw-r--r--intl/plural.c1492
-rw-r--r--intl/printf-args.c142
-rw-r--r--intl/printf-args.h137
-rw-r--r--intl/printf-parse.c544
-rw-r--r--intl/printf-parse.h75
-rw-r--r--intl/printf.c422
-rw-r--r--intl/relocatable.c468
-rw-r--r--intl/relocatable.h79
-rw-r--r--intl/textdomain.c141
-rw-r--r--intl/vasnprintf.c890
-rw-r--r--intl/vasnprintf.h78
-rw-r--r--intl/vasnwprintf.h46
-rw-r--r--intl/version.c26
-rw-r--r--intl/wprintf-parse.h75
-rw-r--r--intl/xsize.h109
49 files changed, 14947 insertions, 0 deletions
diff --git a/intl/bindtextdom.c b/intl/bindtextdom.c
new file mode 100644
index 000000000..d1b1f9028
--- /dev/null
+++ b/intl/bindtextdom.c
@@ -0,0 +1,357 @@
+/* Implementation of the bindtextdomain(3) function
+ Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgnuintl.h"
+#endif
+
+/* Handle multi-threaded applications. */
+#ifdef _LIBC
+# include <bits/libc-lock.h>
+# define gl_rwlock_define __libc_rwlock_define
+# define gl_rwlock_wrlock __libc_rwlock_wrlock
+# define gl_rwlock_unlock __libc_rwlock_unlock
+#else
+# include "lock.h"
+#endif
+
+/* The internal variables in the standalone libintl.a must have different
+ names than the internal variables in GNU libc, otherwise programs
+ using libintl.a cannot be linked statically. */
+#if !defined _LIBC
+# define _nl_default_dirname libintl_nl_default_dirname
+# define _nl_domain_bindings libintl_nl_domain_bindings
+#endif
+
+/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
+#ifndef offsetof
+# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
+#endif
+
+/* @@ end of prolog @@ */
+
+/* Contains the default location of the message catalogs. */
+extern const char _nl_default_dirname[];
+#ifdef _LIBC
+libc_hidden_proto (_nl_default_dirname)
+#endif
+
+/* List with bindings of specific domains. */
+extern struct binding *_nl_domain_bindings;
+
+/* Lock variable to protect the global data in the gettext implementation. */
+gl_rwlock_define (extern, _nl_state_lock attribute_hidden)
+
+
+/* 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
+# define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
+# ifndef strdup
+# define strdup(str) __strdup (str)
+# endif
+#else
+# define BINDTEXTDOMAIN libintl_bindtextdomain
+# define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
+#endif
+
+/* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
+ to be used for the DOMAINNAME message catalog.
+ If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
+ modified, only the current value is returned.
+ If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
+ modified nor returned. */
+static void
+set_binding_values (const char *domainname,
+ const char **dirnamep, const char **codesetp)
+{
+ struct binding *binding;
+ int modified;
+
+ /* Some sanity checks. */
+ if (domainname == NULL || domainname[0] == '\0')
+ {
+ if (dirnamep)
+ *dirnamep = NULL;
+ if (codesetp)
+ *codesetp = NULL;
+ return;
+ }
+
+ gl_rwlock_wrlock (_nl_state_lock);
+
+ modified = 0;
+
+ 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)
+ {
+ if (dirnamep)
+ {
+ const char *dirname = *dirnamep;
+
+ if (dirname == NULL)
+ /* The current binding has be to returned. */
+ *dirnamep = binding->dirname;
+ else
+ {
+ /* The domain is already bound. If the new value and the old
+ one are equal we simply do nothing. Otherwise replace the
+ old binding. */
+ char *result = binding->dirname;
+ if (strcmp (dirname, result) != 0)
+ {
+ if (strcmp (dirname, _nl_default_dirname) == 0)
+ result = (char *) _nl_default_dirname;
+ else
+ {
+#if defined _LIBC || defined HAVE_STRDUP
+ result = strdup (dirname);
+#else
+ size_t len = strlen (dirname) + 1;
+ result = (char *) malloc (len);
+ if (__builtin_expect (result != NULL, 1))
+ memcpy (result, dirname, len);
+#endif
+ }
+
+ if (__builtin_expect (result != NULL, 1))
+ {
+ if (binding->dirname != _nl_default_dirname)
+ free (binding->dirname);
+
+ binding->dirname = result;
+ modified = 1;
+ }
+ }
+ *dirnamep = result;
+ }
+ }
+
+ if (codesetp)
+ {
+ const char *codeset = *codesetp;
+
+ if (codeset == NULL)
+ /* The current binding has be to returned. */
+ *codesetp = binding->codeset;
+ else
+ {
+ /* The domain is already bound. If the new value and the old
+ one are equal we simply do nothing. Otherwise replace the
+ old binding. */
+ char *result = binding->codeset;
+ if (result == NULL || strcmp (codeset, result) != 0)
+ {
+#if defined _LIBC || defined HAVE_STRDUP
+ result = strdup (codeset);
+#else
+ size_t len = strlen (codeset) + 1;
+ result = (char *) malloc (len);
+ if (__builtin_expect (result != NULL, 1))
+ memcpy (result, codeset, len);
+#endif
+
+ if (__builtin_expect (result != NULL, 1))
+ {
+ if (binding->codeset != NULL)
+ free (binding->codeset);
+
+ binding->codeset = result;
+ modified = 1;
+ }
+ }
+ *codesetp = result;
+ }
+ }
+ }
+ else if ((dirnamep == NULL || *dirnamep == NULL)
+ && (codesetp == NULL || *codesetp == NULL))
+ {
+ /* Simply return the default values. */
+ if (dirnamep)
+ *dirnamep = _nl_default_dirname;
+ if (codesetp)
+ *codesetp = NULL;
+ }
+ else
+ {
+ /* We have to create a new binding. */
+ size_t len = strlen (domainname) + 1;
+ struct binding *new_binding =
+ (struct binding *) malloc (offsetof (struct binding, domainname) + len);
+
+ if (__builtin_expect (new_binding == NULL, 0))
+ goto failed;
+
+ memcpy (new_binding->domainname, domainname, len);
+
+ if (dirnamep)
+ {
+ const char *dirname = *dirnamep;
+
+ if (dirname == NULL)
+ /* The default value. */
+ dirname = _nl_default_dirname;
+ else
+ {
+ if (strcmp (dirname, _nl_default_dirname) == 0)
+ dirname = _nl_default_dirname;
+ else
+ {
+ char *result;
+#if defined _LIBC || defined HAVE_STRDUP
+ result = strdup (dirname);
+ if (__builtin_expect (result == NULL, 0))
+ goto failed_dirname;
+#else
+ size_t len = strlen (dirname) + 1;
+ result = (char *) malloc (len);
+ if (__builtin_expect (result == NULL, 0))
+ goto failed_dirname;
+ memcpy (result, dirname, len);
+#endif
+ dirname = result;
+ }
+ }
+ *dirnamep = dirname;
+ new_binding->dirname = (char *) dirname;
+ }
+ else
+ /* The default value. */
+ new_binding->dirname = (char *) _nl_default_dirname;
+
+ if (codesetp)
+ {
+ const char *codeset = *codesetp;
+
+ if (codeset != NULL)
+ {
+ char *result;
+
+#if defined _LIBC || defined HAVE_STRDUP
+ result = strdup (codeset);
+ if (__builtin_expect (result == NULL, 0))
+ goto failed_codeset;
+#else
+ size_t len = strlen (codeset) + 1;
+ result = (char *) malloc (len);
+ if (__builtin_expect (result == NULL, 0))
+ goto failed_codeset;
+ memcpy (result, codeset, len);
+#endif
+ codeset = result;
+ }
+ *codesetp = codeset;
+ new_binding->codeset = (char *) codeset;
+ }
+ else
+ new_binding->codeset = NULL;
+
+ /* 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;
+ }
+
+ modified = 1;
+
+ /* Here we deal with memory allocation failures. */
+ if (0)
+ {
+ failed_codeset:
+ if (new_binding->dirname != _nl_default_dirname)
+ free (new_binding->dirname);
+ failed_dirname:
+ free (new_binding);
+ failed:
+ if (dirnamep)
+ *dirnamep = NULL;
+ if (codesetp)
+ *codesetp = NULL;
+ }
+ }
+
+ /* If we modified any binding, we flush the caches. */
+ if (modified)
+ ++_nl_msg_cat_cntr;
+
+ gl_rwlock_unlock (_nl_state_lock);
+}
+
+/* Specify that the DOMAINNAME message catalog will be found
+ in DIRNAME rather than in the system locale data base. */
+char *
+BINDTEXTDOMAIN (const char *domainname, const char *dirname)
+{
+ set_binding_values (domainname, &dirname, NULL);
+ return (char *) dirname;
+}
+
+/* Specify the character encoding in which the messages from the
+ DOMAINNAME message catalog will be returned. */
+char *
+BIND_TEXTDOMAIN_CODESET (const char *domainname, const char *codeset)
+{
+ set_binding_values (domainname, NULL, &codeset);
+ return (char *) codeset;
+}
+
+#ifdef _LIBC
+/* Aliases for function names in GNU C Library. */
+weak_alias (__bindtextdomain, bindtextdomain);
+weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
+#endif
diff --git a/intl/dcgettext.c b/intl/dcgettext.c
new file mode 100644
index 000000000..c2a63f08e
--- /dev/null
+++ b/intl/dcgettext.c
@@ -0,0 +1,56 @@
+/* Implementation of the dcgettext(3) function.
+ Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgnuintl.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 DCGETTEXT __dcgettext
+# define DCIGETTEXT __dcigettext
+#else
+# define DCGETTEXT libintl_dcgettext
+# define DCIGETTEXT libintl_dcigettext
+#endif
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
+ locale. */
+char *
+DCGETTEXT (const char *domainname, const char *msgid, int category)
+{
+ return DCIGETTEXT (domainname, msgid, NULL, 0, 0, category);
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library. */
+INTDEF(__dcgettext)
+weak_alias (__dcgettext, dcgettext);
+#endif
diff --git a/intl/dcigettext.c b/intl/dcigettext.c
new file mode 100644
index 000000000..583976821
--- /dev/null
+++ b/intl/dcigettext.c
@@ -0,0 +1,1654 @@
+/* Implementation of the internal dcigettext function.
+ Copyright (C) 1995-1999, 2000-2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Tell glibc's <string.h> to provide a prototype for mempcpy().
+ This must come before <config.h> because <config.h> may include
+ <features.h>, and once <features.h> has been included, it's too late. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* NL_LOCALE_NAME does not work in glibc-2.4. Ignore it. */
+#undef HAVE_NL_LOCALE_NAME
+
+#include <sys/types.h>
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+#else
+# ifdef _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# 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
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#include <locale.h>
+
+#ifdef _LIBC
+ /* Guess whether integer division by zero raises signal SIGFPE.
+ Set to 1 only if you know for sure. In case of doubt, set to 0. */
+# if defined __alpha__ || defined __arm__ || defined __i386__ \
+ || defined __m68k__ || defined __s390__
+# define INTDIV0_RAISES_SIGFPE 1
+# else
+# define INTDIV0_RAISES_SIGFPE 0
+# endif
+#endif
+#if !INTDIV0_RAISES_SIGFPE
+# include <signal.h>
+#endif
+
+#if defined HAVE_SYS_PARAM_H || defined _LIBC
+# include <sys/param.h>
+#endif
+
+#if !defined _LIBC && HAVE_NL_LOCALE_NAME
+# include <langinfo.h>
+#endif
+
+#include "gettextP.h"
+#include "plural-exp.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# ifdef IN_LIBGLOCALE
+# include <libintl.h>
+# endif
+# include "libgnuintl.h"
+#endif
+#include "hash-string.h"
+
+/* Handle multi-threaded applications. */
+#ifdef _LIBC
+# include <bits/libc-lock.h>
+# define gl_rwlock_define_initialized __libc_rwlock_define_initialized
+# define gl_rwlock_rdlock __libc_rwlock_rdlock
+# define gl_rwlock_wrlock __libc_rwlock_wrlock
+# define gl_rwlock_unlock __libc_rwlock_unlock
+#else
+# include "lock.h"
+#endif
+
+/* Alignment of types. */
+#if defined __GNUC__ && __GNUC__ >= 2
+# define alignof(TYPE) __alignof__ (TYPE)
+#else
+# define alignof(TYPE) \
+ ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
+#endif
+
+/* The internal variables in the standalone libintl.a must have different
+ names than the internal variables in GNU libc, otherwise programs
+ using libintl.a cannot be linked statically. */
+#if !defined _LIBC
+# define _nl_default_default_domain libintl_nl_default_default_domain
+# define _nl_current_default_domain libintl_nl_current_default_domain
+# define _nl_default_dirname libintl_nl_default_dirname
+# define _nl_domain_bindings libintl_nl_domain_bindings
+#endif
+
+/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
+#ifndef offsetof
+# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
+#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. */
+# define getcwd __getcwd
+# ifndef stpcpy
+# define stpcpy __stpcpy
+# endif
+# define tfind __tfind
+#else
+# if !defined HAVE_GETCWD
+char *getwd ();
+# define getcwd(buf, max) getwd (buf)
+# else
+# if VMS
+# define getcwd(buf, max) (getcwd) (buf, max, 0)
+# else
+char *getcwd ();
+# endif
+# endif
+# ifndef HAVE_STPCPY
+static char *stpcpy (char *dest, const char *src);
+# endif
+# ifndef HAVE_MEMPCPY
+static void *mempcpy (void *dest, const void *src, size_t n);
+# 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
+
+/* Pathname support.
+ ISSLASH(C) tests whether C is a directory separator character.
+ IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
+ it may be concatenated to a directory pathname.
+ IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
+ */
+#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
+ /* Win32, Cygwin, OS/2, DOS */
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+# define HAS_DEVICE(P) \
+ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
+ && (P)[1] == ':')
+# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
+# define IS_PATH_WITH_DIR(P) \
+ (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
+#else
+ /* Unix */
+# define ISSLASH(C) ((C) == '/')
+# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
+# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
+#endif
+
+/* Whether to support different locales in different threads. */
+#if defined _LIBC || HAVE_NL_LOCALE_NAME || (HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS) || defined IN_LIBGLOCALE
+# define HAVE_PER_THREAD_LOCALE
+#endif
+
+/* This is the type used for the search tree where known translations
+ are stored. */
+struct known_translation_t
+{
+ /* Domain in which to search. */
+ const char *domainname;
+
+ /* The category. */
+ int category;
+
+#ifdef HAVE_PER_THREAD_LOCALE
+ /* Name of the relevant locale category, or "" for the global locale. */
+ const char *localename;
+#endif
+
+#ifdef IN_LIBGLOCALE
+ /* The character encoding. */
+ const char *encoding;
+#endif
+
+ /* State of the catalog counter at the point the string was found. */
+ int counter;
+
+ /* Catalog where the string was found. */
+ struct loaded_l10nfile *domain;
+
+ /* And finally the translation. */
+ const char *translation;
+ size_t translation_length;
+
+ /* Pointer to the string in question. */
+ char msgid[ZERO];
+};
+
+/* Root of the search tree with known translations. We can use this
+ only if the system provides the `tsearch' function family. */
+#if defined HAVE_TSEARCH || defined _LIBC
+# include <search.h>
+
+gl_rwlock_define_initialized (static, tree_lock)
+
+static void *root;
+
+# ifdef _LIBC
+# define tsearch __tsearch
+# endif
+
+/* Function to compare two entries in the table of known translations. */
+static int
+transcmp (const void *p1, const void *p2)
+{
+ const struct known_translation_t *s1;
+ const struct known_translation_t *s2;
+ int result;
+
+ s1 = (const struct known_translation_t *) p1;
+ s2 = (const struct known_translation_t *) p2;
+
+ result = strcmp (s1->msgid, s2->msgid);
+ if (result == 0)
+ {
+ result = strcmp (s1->domainname, s2->domainname);
+ if (result == 0)
+ {
+#ifdef HAVE_PER_THREAD_LOCALE
+ result = strcmp (s1->localename, s2->localename);
+ if (result == 0)
+#endif
+ {
+#ifdef IN_LIBGLOCALE
+ result = strcmp (s1->encoding, s2->encoding);
+ if (result == 0)
+#endif
+ /* We compare the category last (though this is the cheapest
+ operation) since it is hopefully always the same (namely
+ LC_MESSAGES). */
+ result = s1->category - s2->category;
+ }
+ }
+ }
+
+ return result;
+}
+#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[] attribute_hidden = "messages";
+
+#ifndef IN_LIBGLOCALE
+/* Value used as the default domain for gettext(3). */
+const char *_nl_current_default_domain attribute_hidden
+ = _nl_default_default_domain;
+#endif
+
+/* Contains the default location of the message catalogs. */
+#if defined __EMX__
+extern const char _nl_default_dirname[];
+#else
+# ifdef _LIBC
+extern const char _nl_default_dirname[];
+libc_hidden_proto (_nl_default_dirname)
+# endif
+const char _nl_default_dirname[] = LOCALEDIR;
+# ifdef _LIBC
+libc_hidden_data_def (_nl_default_dirname)
+# endif
+#endif
+
+#ifndef IN_LIBGLOCALE
+/* List with bindings of specific domains created by bindtextdomain()
+ calls. */
+struct binding *_nl_domain_bindings;
+#endif
+
+/* Prototypes for local functions. */
+static char *plural_lookup (struct loaded_l10nfile *domain,
+ unsigned long int n,
+ const char *translation, size_t translation_len)
+ internal_function;
+
+#ifdef IN_LIBGLOCALE
+static const char *guess_category_value (int category,
+ const char *categoryname,
+ const char *localename)
+ internal_function;
+#else
+static const char *guess_category_value (int category,
+ const char *categoryname)
+ internal_function;
+#endif
+
+#ifdef _LIBC
+# include "../locale/localeinfo.h"
+# define category_to_name(category) \
+ _nl_category_names.str + _nl_category_name_idxs[category]
+#else
+static const char *category_to_name (int category) internal_function;
+#endif
+#if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
+static const char *get_output_charset (struct binding *domainbinding)
+ internal_function;
+#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 freea(p) /* nothing */
+# 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->address); \
+ free (old); \
+ } \
+ } while (0)
+# undef alloca
+# define alloca(size) (malloc (size))
+# define freea(p) free (p)
+#endif /* have alloca */
+
+
+#ifdef _LIBC
+/* List of blocks allocated for translations. */
+typedef struct transmem_list
+{
+ struct transmem_list *next;
+ char data[ZERO];
+} transmem_block_t;
+static struct transmem_list *transmem_list;
+#else
+typedef unsigned char transmem_block_t;
+#endif
+
+
+/* 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 DCIGETTEXT __dcigettext
+#else
+# define DCIGETTEXT libintl_dcigettext
+#endif
+
+/* Lock variable to protect the global data in the gettext implementation. */
+gl_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
+
+/* Checking whether the binaries runs SUID must be done and glibc provides
+ easier methods therefore we make a difference here. */
+#ifdef _LIBC
+# define ENABLE_SECURE __libc_enable_secure
+# define DETERMINE_SECURE
+#else
+# ifndef HAVE_GETUID
+# define getuid() 0
+# endif
+# ifndef HAVE_GETGID
+# define getgid() 0
+# endif
+# ifndef HAVE_GETEUID
+# define geteuid() getuid()
+# endif
+# ifndef HAVE_GETEGID
+# define getegid() getgid()
+# endif
+static int enable_secure;
+# define ENABLE_SECURE (enable_secure == 1)
+# define DETERMINE_SECURE \
+ if (enable_secure == 0) \
+ { \
+ if (getuid () != geteuid () || getgid () != getegid ()) \
+ enable_secure = 1; \
+ else \
+ enable_secure = -1; \
+ }
+#endif
+
+/* Get the function to evaluate the plural expression. */
+#include "eval-plural.h"
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current
+ CATEGORY locale and, if PLURAL is nonzero, search over string
+ depending on the plural form determined by N. */
+#ifdef IN_LIBGLOCALE
+char *
+gl_dcigettext (const char *domainname,
+ const char *msgid1, const char *msgid2,
+ int plural, unsigned long int n,
+ int category,
+ const char *localename, const char *encoding)
+#else
+char *
+DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
+ int plural, unsigned long int n, int category)
+#endif
+{
+#ifndef HAVE_ALLOCA
+ struct block_list *block_list = NULL;
+#endif
+ struct loaded_l10nfile *domain;
+ struct binding *binding;
+ const char *categoryname;
+ const char *categoryvalue;
+ const char *dirname;
+ char *xdomainname;
+ char *single_locale;
+ char *retval;
+ size_t retlen;
+ int saved_errno;
+#if defined HAVE_TSEARCH || defined _LIBC
+ struct known_translation_t *search;
+ struct known_translation_t **foundp = NULL;
+ size_t msgid_len;
+# if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE
+ const char *localename;
+# endif
+#endif
+ size_t domainname_len;
+
+ /* If no real MSGID is given return NULL. */
+ if (msgid1 == NULL)
+ return NULL;
+
+#ifdef _LIBC
+ if (category < 0 || category >= __LC_LAST || category == LC_ALL)
+ /* Bogus. */
+ return (plural == 0
+ ? (char *) msgid1
+ /* Use the Germanic plural rule. */
+ : n == 1 ? (char *) msgid1 : (char *) msgid2);
+#endif
+
+ gl_rwlock_rdlock (_nl_state_lock);
+
+ /* 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
+ definition left this undefined. */
+ if (domainname == NULL)
+ domainname = _nl_current_default_domain;
+
+ /* OS/2 specific: backward compatibility with older libintl versions */
+#ifdef LC_MESSAGES_COMPAT
+ if (category == LC_MESSAGES_COMPAT)
+ category = LC_MESSAGES;
+#endif
+
+#if defined HAVE_TSEARCH || defined _LIBC
+ msgid_len = strlen (msgid1) + 1;
+
+ /* Try to find the translation among those which we found at
+ some time. */
+ search = (struct known_translation_t *)
+ alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
+ memcpy (search->msgid, msgid1, msgid_len);
+ search->domainname = domainname;
+ search->category = category;
+# ifdef HAVE_PER_THREAD_LOCALE
+# ifndef IN_LIBGLOCALE
+# ifdef _LIBC
+ localename = __current_locale_name (category);
+# else
+# if HAVE_NL_LOCALE_NAME
+ /* NL_LOCALE_NAME is public glibc API introduced in glibc-2.4. */
+ localename = nl_langinfo (NL_LOCALE_NAME (category));
+# else
+# if HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS
+ /* The __names field is not public glibc API and must therefore not be used
+ in code that is installed in public locations. */
+ {
+ locale_t thread_locale = uselocale (NULL);
+ if (thread_locale != LC_GLOBAL_LOCALE)
+ localename = thread_locale->__names[category];
+ else
+ localename = "";
+ }
+# endif
+# endif
+# endif
+# endif
+ search->localename = localename;
+# ifdef IN_LIBGLOCALE
+ search->encoding = encoding;
+# endif
+# endif
+
+ /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
+ tsearch calls can be fatal. */
+ gl_rwlock_rdlock (tree_lock);
+
+ foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
+
+ gl_rwlock_unlock (tree_lock);
+
+ freea (search);
+ if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
+ {
+ /* Now deal with plural. */
+ if (plural)
+ retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
+ (*foundp)->translation_length);
+ else
+ retval = (char *) (*foundp)->translation;
+
+ gl_rwlock_unlock (_nl_state_lock);
+ return retval;
+ }
+#endif
+
+ /* Preserve the `errno' value. */
+ saved_errno = errno;
+
+ /* See whether this is a SUID binary or not. */
+ DETERMINE_SECURE;
+
+ /* First find matching binding. */
+#ifdef IN_LIBGLOCALE
+ /* We can use a trivial binding, since _nl_find_msg will ignore it anyway,
+ and _nl_load_domain and _nl_find_domain just pass it through. */
+ binding = NULL;
+ dirname = bindtextdomain (domainname, NULL);
+#else
+ 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 = _nl_default_dirname;
+ else
+ {
+ dirname = binding->dirname;
+#endif
+ if (!IS_ABSOLUTE_PATH (dirname))
+ {
+ /* We have a relative path. Make it absolute now. */
+ size_t dirname_len = strlen (dirname) + 1;
+ size_t path_max;
+ char *resolved_dirname;
+ char *ret;
+
+ path_max = (unsigned int) PATH_MAX;
+ path_max += 2; /* The getcwd docs say to do this. */
+
+ for (;;)
+ {
+ resolved_dirname = (char *) alloca (path_max + dirname_len);
+ ADD_BLOCK (block_list, tmp_dirname);
+
+ __set_errno (0);
+ ret = getcwd (resolved_dirname, path_max);
+ if (ret != NULL || errno != ERANGE)
+ break;
+
+ path_max += path_max / 2;
+ path_max += PATH_INCR;
+ }
+
+ if (ret == NULL)
+ /* We cannot get the current working directory. Don't signal an
+ error but simply return the default string. */
+ goto return_untranslated;
+
+ stpcpy (stpcpy (strchr (resolved_dirname, '\0'), "/"), dirname);
+ dirname = resolved_dirname;
+ }
+#ifndef IN_LIBGLOCALE
+ }
+#endif
+
+ /* Now determine the symbolic name of CATEGORY and its value. */
+ categoryname = category_to_name (category);
+#ifdef IN_LIBGLOCALE
+ categoryvalue = guess_category_value (category, categoryname, localename);
+#else
+ categoryvalue = guess_category_value (category, categoryname);
+#endif
+
+ domainname_len = strlen (domainname);
+ xdomainname = (char *) alloca (strlen (categoryname)
+ + domainname_len + 5);
+ ADD_BLOCK (block_list, xdomainname);
+
+ stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
+ domainname, domainname_len),
+ ".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 the 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';
+
+ /* When this is a SUID binary we must not allow accessing files
+ outside the dedicated directories. */
+ if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
+ /* Ingore this entry. */
+ continue;
+ }
+
+ /* 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)
+ break;
+
+ /* Find structure describing the message catalog matching the
+ DOMAINNAME and CATEGORY. */
+ domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
+
+ if (domain != NULL)
+ {
+#if defined IN_LIBGLOCALE
+ retval = _nl_find_msg (domain, binding, encoding, msgid1, &retlen);
+#else
+ retval = _nl_find_msg (domain, binding, msgid1, 1, &retlen);
+#endif
+
+ if (retval == NULL)
+ {
+ int cnt;
+
+ for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
+ {
+#if defined IN_LIBGLOCALE
+ retval = _nl_find_msg (domain->successor[cnt], binding,
+ encoding, msgid1, &retlen);
+#else
+ retval = _nl_find_msg (domain->successor[cnt], binding,
+ msgid1, 1, &retlen);
+#endif
+
+ if (retval != NULL)
+ {
+ domain = domain->successor[cnt];
+ break;
+ }
+ }
+ }
+
+ /* Returning -1 means that some resource problem exists
+ (likely memory) and that the strings could not be
+ converted. Return the original strings. */
+ if (__builtin_expect (retval == (char *) -1, 0))
+ break;
+
+ if (retval != NULL)
+ {
+ /* Found the translation of MSGID1 in domain DOMAIN:
+ starting at RETVAL, RETLEN bytes. */
+ FREE_BLOCKS (block_list);
+#if defined HAVE_TSEARCH || defined _LIBC
+ if (foundp == NULL)
+ {
+ /* Create a new entry and add it to the search tree. */
+ size_t size;
+ struct known_translation_t *newp;
+
+ size = offsetof (struct known_translation_t, msgid)
+ + msgid_len + domainname_len + 1;
+# ifdef HAVE_PER_THREAD_LOCALE
+ size += strlen (localename) + 1;
+# endif
+ newp = (struct known_translation_t *) malloc (size);
+ if (newp != NULL)
+ {
+ char *new_domainname;
+# ifdef HAVE_PER_THREAD_LOCALE
+ char *new_localename;
+# endif
+
+ new_domainname = mempcpy (newp->msgid, msgid1, msgid_len);
+ memcpy (new_domainname, domainname, domainname_len + 1);
+# ifdef HAVE_PER_THREAD_LOCALE
+ new_localename = new_domainname + domainname_len + 1;
+ strcpy (new_localename, localename);
+# endif
+ newp->domainname = new_domainname;
+ newp->category = category;
+# ifdef HAVE_PER_THREAD_LOCALE
+ newp->localename = new_localename;
+# endif
+# ifdef IN_LIBGLOCALE
+ newp->encoding = encoding;
+# endif
+ newp->counter = _nl_msg_cat_cntr;
+ newp->domain = domain;
+ newp->translation = retval;
+ newp->translation_length = retlen;
+
+ gl_rwlock_wrlock (tree_lock);
+
+ /* Insert the entry in the search tree. */
+ foundp = (struct known_translation_t **)
+ tsearch (newp, &root, transcmp);
+
+ gl_rwlock_unlock (tree_lock);
+
+ if (foundp == NULL
+ || __builtin_expect (*foundp != newp, 0))
+ /* The insert failed. */
+ free (newp);
+ }
+ }
+ else
+ {
+ /* We can update the existing entry. */
+ (*foundp)->counter = _nl_msg_cat_cntr;
+ (*foundp)->domain = domain;
+ (*foundp)->translation = retval;
+ (*foundp)->translation_length = retlen;
+ }
+#endif
+ __set_errno (saved_errno);
+
+ /* Now deal with plural. */
+ if (plural)
+ retval = plural_lookup (domain, n, retval, retlen);
+
+ gl_rwlock_unlock (_nl_state_lock);
+ return retval;
+ }
+ }
+ }
+
+ return_untranslated:
+ /* Return the untranslated MSGID. */
+ FREE_BLOCKS (block_list);
+ gl_rwlock_unlock (_nl_state_lock);
+#ifndef _LIBC
+ if (!ENABLE_SECURE)
+ {
+ extern void _nl_log_untranslated (const char *logfilename,
+ const char *domainname,
+ const char *msgid1, const char *msgid2,
+ int plural);
+ const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
+
+ if (logfilename != NULL && logfilename[0] != '\0')
+ _nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
+ }
+#endif
+ __set_errno (saved_errno);
+ return (plural == 0
+ ? (char *) msgid1
+ /* Use the Germanic plural rule. */
+ : n == 1 ? (char *) msgid1 : (char *) msgid2);
+}
+
+
+/* Look up the translation of msgid within DOMAIN_FILE and DOMAINBINDING.
+ Return it if found. Return NULL if not found or in case of a conversion
+ failure (problem in the particular message catalog). Return (char *) -1
+ in case of a memory allocation failure during conversion (only if
+ ENCODING != NULL resp. CONVERT == true). */
+char *
+internal_function
+#ifdef IN_LIBGLOCALE
+_nl_find_msg (struct loaded_l10nfile *domain_file,
+ struct binding *domainbinding, const char *encoding,
+ const char *msgid,
+ size_t *lengthp)
+#else
+_nl_find_msg (struct loaded_l10nfile *domain_file,
+ struct binding *domainbinding,
+ const char *msgid, int convert,
+ size_t *lengthp)
+#endif
+{
+ struct loaded_domain *domain;
+ nls_uint32 nstrings;
+ size_t act;
+ char *result;
+ size_t resultlen;
+
+ if (domain_file->decided <= 0)
+ _nl_load_domain (domain_file, domainbinding);
+
+ if (domain_file->data == NULL)
+ return NULL;
+
+ domain = (struct loaded_domain *) domain_file->data;
+
+ nstrings = domain->nstrings;
+
+ /* Locate the MSGID and its translation. */
+ if (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));
+
+ while (1)
+ {
+ nls_uint32 nstr =
+ W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
+
+ if (nstr == 0)
+ /* Hash table entry is empty. */
+ return NULL;
+
+ nstr--;
+
+ /* Compare msgid with the original string at index nstr.
+ We compare the lengths with >=, not ==, because plural entries
+ are represented by strings with an embedded NUL. */
+ if (nstr < nstrings
+ ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
+ && (strcmp (msgid,
+ domain->data + W (domain->must_swap,
+ domain->orig_tab[nstr].offset))
+ == 0)
+ : domain->orig_sysdep_tab[nstr - nstrings].length > len
+ && (strcmp (msgid,
+ domain->orig_sysdep_tab[nstr - nstrings].pointer)
+ == 0))
+ {
+ act = nstr;
+ goto found;
+ }
+
+ if (idx >= domain->hash_size - incr)
+ idx -= domain->hash_size - incr;
+ else
+ idx += incr;
+ }
+ /* NOTREACHED */
+ }
+ else
+ {
+ /* Try the default method: binary search in the sorted array of
+ messages. */
+ size_t top, bottom;
+
+ bottom = 0;
+ top = 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
+ goto found;
+ }
+ /* No translation was found. */
+ return NULL;
+ }
+
+ found:
+ /* The translation was found at index ACT. If we have to convert the
+ string to use a different character set, this is the time. */
+ if (act < nstrings)
+ {
+ result = (char *)
+ (domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
+ resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
+ }
+ else
+ {
+ result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
+ resultlen = domain->trans_sysdep_tab[act - nstrings].length;
+ }
+
+#if defined _LIBC || HAVE_ICONV
+# ifdef IN_LIBGLOCALE
+ if (encoding != NULL)
+# else
+ if (convert)
+# endif
+ {
+ /* We are supposed to do a conversion. */
+# ifndef IN_LIBGLOCALE
+ const char *encoding = get_output_charset (domainbinding);
+# endif
+
+ /* Search whether a table with converted translations for this
+ encoding has already been allocated. */
+ size_t nconversions = domain->nconversions;
+ struct converted_domain *convd = NULL;
+ size_t i;
+
+ for (i = nconversions; i > 0; )
+ {
+ i--;
+ if (strcmp (domain->conversions[i].encoding, encoding) == 0)
+ {
+ convd = &domain->conversions[i];
+ break;
+ }
+ }
+
+ if (convd == NULL)
+ {
+ /* Allocate a table for the converted translations for this
+ encoding. */
+ struct converted_domain *new_conversions =
+ (struct converted_domain *)
+ (domain->conversions != NULL
+ ? realloc (domain->conversions,
+ (nconversions + 1) * sizeof (struct converted_domain))
+ : malloc ((nconversions + 1) * sizeof (struct converted_domain)));
+
+ if (__builtin_expect (new_conversions == NULL, 0))
+ /* Nothing we can do, no more memory. We cannot use the
+ translation because it might be encoded incorrectly. */
+ return (char *) -1;
+
+ domain->conversions = new_conversions;
+
+ /* Copy the 'encoding' string to permanent storage. */
+ encoding = strdup (encoding);
+ if (__builtin_expect (encoding == NULL, 0))
+ /* Nothing we can do, no more memory. We cannot use the
+ translation because it might be encoded incorrectly. */
+ return (char *) -1;
+
+ convd = &new_conversions[nconversions];
+ convd->encoding = encoding;
+
+ /* Find out about the character set the file is encoded with.
+ This can be found (in textual form) in the entry "". If this
+ entry does not exist or if this does not contain the 'charset='
+ information, we will assume the charset matches the one the
+ current locale and we don't have to perform any conversion. */
+# ifdef _LIBC
+ convd->conv = (__gconv_t) -1;
+# else
+# if HAVE_ICONV
+ convd->conv = (iconv_t) -1;
+# endif
+# endif
+ {
+ char *nullentry;
+ size_t nullentrylen;
+
+ /* Get the header entry. This is a recursion, but it doesn't
+ reallocate domain->conversions because we pass
+ encoding = NULL or convert = 0, respectively. */
+ nullentry =
+# ifdef IN_LIBGLOCALE
+ _nl_find_msg (domain_file, domainbinding, NULL, "",
+ &nullentrylen);
+# else
+ _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
+# endif
+
+ if (nullentry != NULL)
+ {
+ const char *charsetstr;
+
+ charsetstr = strstr (nullentry, "charset=");
+ if (charsetstr != NULL)
+ {
+ size_t len;
+ char *charset;
+ const char *outcharset;
+
+ charsetstr += strlen ("charset=");
+ len = strcspn (charsetstr, " \t\n");
+
+ charset = (char *) alloca (len + 1);
+# if defined _LIBC || HAVE_MEMPCPY
+ *((char *) mempcpy (charset, charsetstr, len)) = '\0';
+# else
+ memcpy (charset, charsetstr, len);
+ charset[len] = '\0';
+# endif
+
+ outcharset = encoding;
+
+# ifdef _LIBC
+ /* We always want to use transliteration. */
+ outcharset = norm_add_slashes (outcharset, "TRANSLIT");
+ charset = norm_add_slashes (charset, "");
+ int r = __gconv_open (outcharset, charset, &convd->conv,
+ GCONV_AVOID_NOCONV);
+ if (__builtin_expect (r != __GCONV_OK, 0))
+ {
+ /* If the output encoding is the same there is
+ nothing to do. Otherwise do not use the
+ translation at all. */
+ if (__builtin_expect (r != __GCONV_NOCONV, 1))
+ return NULL;
+
+ convd->conv = (__gconv_t) -1;
+ }
+# else
+# if HAVE_ICONV
+ /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
+ we want to use transliteration. */
+# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
+ || _LIBICONV_VERSION >= 0x0105
+ if (strchr (outcharset, '/') == NULL)
+ {
+ char *tmp;
+
+ len = strlen (outcharset);
+ tmp = (char *) alloca (len + 10 + 1);
+ memcpy (tmp, outcharset, len);
+ memcpy (tmp + len, "//TRANSLIT", 10 + 1);
+ outcharset = tmp;
+
+ convd->conv = iconv_open (outcharset, charset);
+
+ freea (outcharset);
+ }
+ else
+# endif
+ convd->conv = iconv_open (outcharset, charset);
+# endif
+# endif
+
+ freea (charset);
+ }
+ }
+ }
+ convd->conv_tab = NULL;
+ /* Here domain->conversions is still == new_conversions. */
+ domain->nconversions++;
+ }
+
+ if (
+# ifdef _LIBC
+ convd->conv != (__gconv_t) -1
+# else
+# if HAVE_ICONV
+ convd->conv != (iconv_t) -1
+# endif
+# endif
+ )
+ {
+ /* We are supposed to do a conversion. First allocate an
+ appropriate table with the same structure as the table
+ of translations in the file, where we can put the pointers
+ to the converted strings in.
+ There is a slight complication with plural entries. They
+ are represented by consecutive NUL terminated strings. We
+ handle this case by converting RESULTLEN bytes, including
+ NULs. */
+
+ if (convd->conv_tab == NULL
+ && ((convd->conv_tab =
+ (char **) calloc (nstrings + domain->n_sysdep_strings,
+ sizeof (char *)))
+ == NULL))
+ /* Mark that we didn't succeed allocating a table. */
+ convd->conv_tab = (char **) -1;
+
+ if (__builtin_expect (convd->conv_tab == (char **) -1, 0))
+ /* Nothing we can do, no more memory. We cannot use the
+ translation because it might be encoded incorrectly. */
+ return (char *) -1;
+
+ if (convd->conv_tab[act] == NULL)
+ {
+ /* We haven't used this string so far, so it is not
+ translated yet. Do this now. */
+ /* We use a bit more efficient memory handling.
+ We allocate always larger blocks which get used over
+ time. This is faster than many small allocations. */
+ __libc_lock_define_initialized (static, lock)
+# define INITIAL_BLOCK_SIZE 4080
+ static unsigned char *freemem;
+ static size_t freemem_size;
+
+ const unsigned char *inbuf;
+ unsigned char *outbuf;
+ int malloc_count;
+# ifndef _LIBC
+ transmem_block_t *transmem_list = NULL;
+# endif
+
+ __libc_lock_lock (lock);
+
+ inbuf = (const unsigned char *) result;
+ outbuf = freemem + sizeof (size_t);
+
+ malloc_count = 0;
+ while (1)
+ {
+ transmem_block_t *newmem;
+# ifdef _LIBC
+ size_t non_reversible;
+ int res;
+
+ if (freemem_size < sizeof (size_t))
+ goto resize_freemem;
+
+ res = __gconv (convd->conv,
+ &inbuf, inbuf + resultlen,
+ &outbuf,
+ outbuf + freemem_size - sizeof (size_t),
+ &non_reversible);
+
+ if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
+ break;
+
+ if (res != __GCONV_FULL_OUTPUT)
+ {
+ /* We should not use the translation at all, it
+ is incorrectly encoded. */
+ __libc_lock_unlock (lock);
+ return NULL;
+ }
+
+ inbuf = (const unsigned char *) result;
+# else
+# if HAVE_ICONV
+ const char *inptr = (const char *) inbuf;
+ size_t inleft = resultlen;
+ char *outptr = (char *) outbuf;
+ size_t outleft;
+
+ if (freemem_size < sizeof (size_t))
+ goto resize_freemem;
+
+ outleft = freemem_size - sizeof (size_t);
+ if (iconv (convd->conv,
+ (ICONV_CONST char **) &inptr, &inleft,
+ &outptr, &outleft)
+ != (size_t) (-1))
+ {
+ outbuf = (unsigned char *) outptr;
+ break;
+ }
+ if (errno != E2BIG)
+ {
+ __libc_lock_unlock (lock);
+ return NULL;
+ }
+# endif
+# endif
+
+ resize_freemem:
+ /* We must allocate a new buffer or resize the old one. */
+ if (malloc_count > 0)
+ {
+ ++malloc_count;
+ freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
+ newmem = (transmem_block_t *) realloc (transmem_list,
+ freemem_size);
+# ifdef _LIBC
+ if (newmem != NULL)
+ transmem_list = transmem_list->next;
+ else
+ {
+ struct transmem_list *old = transmem_list;
+
+ transmem_list = transmem_list->next;
+ free (old);
+ }
+# endif
+ }
+ else
+ {
+ malloc_count = 1;
+ freemem_size = INITIAL_BLOCK_SIZE;
+ newmem = (transmem_block_t *) malloc (freemem_size);
+ }
+ if (__builtin_expect (newmem == NULL, 0))
+ {
+ freemem = NULL;
+ freemem_size = 0;
+ __libc_lock_unlock (lock);
+ return (char *) -1;
+ }
+
+# ifdef _LIBC
+ /* Add the block to the list of blocks we have to free
+ at some point. */
+ newmem->next = transmem_list;
+ transmem_list = newmem;
+
+ freemem = (unsigned char *) newmem->data;
+ freemem_size -= offsetof (struct transmem_list, data);
+# else
+ transmem_list = newmem;
+ freemem = newmem;
+# endif
+
+ outbuf = freemem + sizeof (size_t);
+ }
+
+ /* We have now in our buffer a converted string. Put this
+ into the table of conversions. */
+ *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
+ convd->conv_tab[act] = (char *) freemem;
+ /* Shrink freemem, but keep it aligned. */
+ freemem_size -= outbuf - freemem;
+ freemem = outbuf;
+ freemem += freemem_size & (alignof (size_t) - 1);
+ freemem_size = freemem_size & ~ (alignof (size_t) - 1);
+
+ __libc_lock_unlock (lock);
+ }
+
+ /* Now convd->conv_tab[act] contains the translation of all
+ the plural variants. */
+ result = convd->conv_tab[act] + sizeof (size_t);
+ resultlen = *(size_t *) convd->conv_tab[act];
+ }
+ }
+
+ /* The result string is converted. */
+
+#endif /* _LIBC || HAVE_ICONV */
+
+ *lengthp = resultlen;
+ return result;
+}
+
+
+/* Look up a plural variant. */
+static char *
+internal_function
+plural_lookup (struct loaded_l10nfile *domain, unsigned long int n,
+ const char *translation, size_t translation_len)
+{
+ struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
+ unsigned long int index;
+ const char *p;
+
+ index = plural_eval (domaindata->plural, n);
+ if (index >= domaindata->nplurals)
+ /* This should never happen. It means the plural expression and the
+ given maximum value do not match. */
+ index = 0;
+
+ /* Skip INDEX strings at TRANSLATION. */
+ p = translation;
+ while (index-- > 0)
+ {
+#ifdef _LIBC
+ p = __rawmemchr (p, '\0');
+#else
+ p = strchr (p, '\0');
+#endif
+ /* And skip over the NUL byte. */
+ p++;
+
+ if (p >= translation + translation_len)
+ /* This should never happen. It means the plural expression
+ evaluated to a value larger than the number of variants
+ available for MSGID1. */
+ return (char *) translation;
+ }
+ return (char *) p;
+}
+
+#ifndef _LIBC
+/* Return string representation of locale CATEGORY. */
+static const char *
+internal_function
+category_to_name (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;
+}
+#endif
+
+/* Guess value of current locale from value of the environment variables
+ or system-dependent defaults. */
+static const char *
+internal_function
+#ifdef IN_LIBGLOCALE
+guess_category_value (int category, const char *categoryname,
+ const char *locale)
+
+#else
+guess_category_value (int category, const char *categoryname)
+#endif
+{
+ const char *language;
+#ifndef IN_LIBGLOCALE
+ const char *locale;
+# ifndef _LIBC
+ const char *language_default;
+ int locale_defaulted;
+# endif
+#endif
+
+ /* We use the settings in the following order:
+ 1. The value of the environment variable 'LANGUAGE'. This is a GNU
+ extension. Its value can be a colon-separated list of locale names.
+ 2. The value of the environment variable 'LC_ALL', 'LC_xxx', or 'LANG'.
+ More precisely, the first among these that is set to a non-empty value.
+ This is how POSIX specifies it. The value is a single locale name.
+ 3. A system-dependent preference list of languages. Its value can be a
+ colon-separated list of locale names.
+ 4. A system-dependent default locale name.
+ This way:
+ - System-dependent settings can be overridden by environment variables.
+ - If the system provides both a list of languages and a default locale,
+ the former is used. */
+
+#ifndef IN_LIBGLOCALE
+ /* Fetch the locale name, through the POSIX method of looking to `LC_ALL',
+ `LC_xxx', and `LANG'. On some systems this can be done by the
+ `setlocale' function itself. */
+# ifdef _LIBC
+ locale = __current_locale_name (category);
+# else
+# if HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS
+ /* The __names field is not public glibc API and must therefore not be used
+ in code that is installed in public locations. */
+ locale_t thread_locale = uselocale (NULL);
+ if (thread_locale != LC_GLOBAL_LOCALE)
+ {
+ locale = thread_locale->__names[category];
+ locale_defaulted = 0;
+ }
+ else
+# endif
+ {
+ locale = _nl_locale_name_posix (category, categoryname);
+ locale_defaulted = 0;
+ if (locale == NULL)
+ {
+ locale = _nl_locale_name_default ();
+ locale_defaulted = 1;
+ }
+ }
+# endif
+#endif
+
+ /* Ignore LANGUAGE and its system-dependent analogon if the locale is set
+ to "C" because
+ 1. "C" locale usually uses the ASCII encoding, and most international
+ messages use non-ASCII characters. These characters get displayed
+ as question marks (if using glibc's iconv()) or as invalid 8-bit
+ characters (because other iconv()s refuse to convert most non-ASCII
+ characters to ASCII). In any case, the output is ugly.
+ 2. The precise output of some programs in the "C" locale is specified
+ by POSIX and should not depend on environment variables like
+ "LANGUAGE" or system-dependent information. We allow such programs
+ to use gettext(). */
+ if (strcmp (locale, "C") == 0)
+ return locale;
+
+ /* The highest priority value is the value of the 'LANGUAGE' environment
+ variable. */
+ language = getenv ("LANGUAGE");
+ if (language != NULL && language[0] != '\0')
+ return language;
+#if !defined IN_LIBGLOCALE && !defined _LIBC
+ /* The next priority value is the locale name, if not defaulted. */
+ if (locale_defaulted)
+ {
+ /* The next priority value is the default language preferences list. */
+ language_default = _nl_language_preferences_default ();
+ if (language_default != NULL)
+ return language_default;
+ }
+ /* The least priority value is the locale name, if defaulted. */
+#endif
+ return locale;
+}
+
+#if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
+/* Returns the output charset. */
+static const char *
+internal_function
+get_output_charset (struct binding *domainbinding)
+{
+ /* The output charset should normally be determined by the locale. But
+ sometimes the locale is not used or not correctly set up, so we provide
+ a possibility for the user to override this: the OUTPUT_CHARSET
+ environment variable. Moreover, the value specified through
+ bind_textdomain_codeset overrides both. */
+ if (domainbinding != NULL && domainbinding->codeset != NULL)
+ return domainbinding->codeset;
+ else
+ {
+ /* For speed reasons, we look at the value of OUTPUT_CHARSET only
+ once. This is a user variable that is not supposed to change
+ during a program run. */
+ static char *output_charset_cache;
+ static int output_charset_cached;
+
+ if (!output_charset_cached)
+ {
+ const char *value = getenv ("OUTPUT_CHARSET");
+
+ if (value != NULL && value[0] != '\0')
+ {
+ size_t len = strlen (value) + 1;
+ char *value_copy = (char *) malloc (len);
+
+ if (value_copy != NULL)
+ memcpy (value_copy, value, len);
+ output_charset_cache = value_copy;
+ }
+ output_charset_cached = 1;
+ }
+
+ if (output_charset_cache != NULL)
+ return output_charset_cache;
+ else
+ {
+# ifdef _LIBC
+ return _NL_CURRENT (LC_CTYPE, CODESET);
+# else
+# if HAVE_ICONV
+ extern const char *locale_charset (void);
+ return locale_charset ();
+# endif
+# endif
+ }
+ }
+}
+#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 (char *dest, const char *src)
+{
+ while ((*dest++ = *src++) != '\0')
+ /* Do nothing. */ ;
+ return dest - 1;
+}
+#endif
+
+#if !_LIBC && !HAVE_MEMPCPY
+static void *
+mempcpy (void *dest, const void *src, size_t n)
+{
+ return (void *) ((char *) memcpy (dest, src, n) + n);
+}
+#endif
+
+
+#ifdef _LIBC
+/* If we want to free all resources we have to do some work at
+ program's end. */
+libc_freeres_fn (free_mem)
+{
+ void *old;
+
+ while (_nl_domain_bindings != NULL)
+ {
+ struct binding *oldp = _nl_domain_bindings;
+ _nl_domain_bindings = _nl_domain_bindings->next;
+ if (oldp->dirname != _nl_default_dirname)
+ /* Yes, this is a pointer comparison. */
+ free (oldp->dirname);
+ free (oldp->codeset);
+ free (oldp);
+ }
+
+ if (_nl_current_default_domain != _nl_default_default_domain)
+ /* Yes, again a pointer comparison. */
+ free ((char *) _nl_current_default_domain);
+
+ /* Remove the search tree with the known translations. */
+ __tdestroy (root, free);
+ root = NULL;
+
+ while (transmem_list != NULL)
+ {
+ old = transmem_list;
+ transmem_list = transmem_list->next;
+ free (old);
+ }
+}
+#endif
diff --git a/intl/dcngettext.c b/intl/dcngettext.c
new file mode 100644
index 000000000..eb368336c
--- /dev/null
+++ b/intl/dcngettext.c
@@ -0,0 +1,57 @@
+/* Implementation of the dcngettext(3) function.
+ Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgnuintl.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 DCNGETTEXT __dcngettext
+# define DCIGETTEXT __dcigettext
+#else
+# define DCNGETTEXT libintl_dcngettext
+# define DCIGETTEXT libintl_dcigettext
+#endif
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
+ locale. */
+char *
+DCNGETTEXT (const char *domainname,
+ const char *msgid1, const char *msgid2, unsigned long int n,
+ int category)
+{
+ return DCIGETTEXT (domainname, msgid1, msgid2, 1, n, category);
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library. */
+weak_alias (__dcngettext, dcngettext);
+#endif
diff --git a/intl/dgettext.c b/intl/dgettext.c
new file mode 100644
index 000000000..9b0d0de6c
--- /dev/null
+++ b/intl/dgettext.c
@@ -0,0 +1,58 @@
+/* Implementation of the dgettext(3) function.
+ Copyright (C) 1995-1997, 2000-2003 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "gettextP.h"
+
+#include <locale.h>
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgnuintl.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 INTUSE(__dcgettext)
+#else
+# define DGETTEXT libintl_dgettext
+# define DCGETTEXT libintl_dcgettext
+#endif
+
+/* Look up MSGID in the DOMAINNAME message catalog of the current
+ LC_MESSAGES locale. */
+char *
+DGETTEXT (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/dngettext.c b/intl/dngettext.c
new file mode 100644
index 000000000..3278438fe
--- /dev/null
+++ b/intl/dngettext.c
@@ -0,0 +1,59 @@
+/* Implementation of the dngettext(3) function.
+ Copyright (C) 1995-1997, 2000-2003 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "gettextP.h"
+
+#include <locale.h>
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgnuintl.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 DNGETTEXT __dngettext
+# define DCNGETTEXT __dcngettext
+#else
+# define DNGETTEXT libintl_dngettext
+# define DCNGETTEXT libintl_dcngettext
+#endif
+
+/* Look up MSGID in the DOMAINNAME message catalog of the current
+ LC_MESSAGES locale and skip message according to the plural form. */
+char *
+DNGETTEXT (const char *domainname,
+ const char *msgid1, const char *msgid2, unsigned long int n)
+{
+ return DCNGETTEXT (domainname, msgid1, msgid2, n, LC_MESSAGES);
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library. */
+weak_alias (__dngettext, dngettext);
+#endif
diff --git a/intl/eval-plural.h b/intl/eval-plural.h
new file mode 100644
index 000000000..dacd003db
--- /dev/null
+++ b/intl/eval-plural.h
@@ -0,0 +1,108 @@
+/* Plural expression evaluation.
+ Copyright (C) 2000-2003 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef STATIC
+#define STATIC static
+#endif
+
+/* Evaluate the plural expression and return an index value. */
+STATIC
+unsigned long int
+internal_function
+plural_eval (struct expression *pexp, unsigned long int n)
+{
+ switch (pexp->nargs)
+ {
+ case 0:
+ switch (pexp->operation)
+ {
+ case var:
+ return n;
+ case num:
+ return pexp->val.num;
+ default:
+ break;
+ }
+ /* NOTREACHED */
+ break;
+ case 1:
+ {
+ /* pexp->operation must be lnot. */
+ unsigned long int arg = plural_eval (pexp->val.args[0], n);
+ return ! arg;
+ }
+ case 2:
+ {
+ unsigned long int leftarg = plural_eval (pexp->val.args[0], n);
+ if (pexp->operation == lor)
+ return leftarg || plural_eval (pexp->val.args[1], n);
+ else if (pexp->operation == land)
+ return leftarg && plural_eval (pexp->val.args[1], n);
+ else
+ {
+ unsigned long int rightarg = plural_eval (pexp->val.args[1], n);
+
+ switch (pexp->operation)
+ {
+ case mult:
+ return leftarg * rightarg;
+ case divide:
+#if !INTDIV0_RAISES_SIGFPE
+ if (rightarg == 0)
+ raise (SIGFPE);
+#endif
+ return leftarg / rightarg;
+ case module:
+#if !INTDIV0_RAISES_SIGFPE
+ if (rightarg == 0)
+ raise (SIGFPE);
+#endif
+ return leftarg % rightarg;
+ case plus:
+ return leftarg + rightarg;
+ case minus:
+ return leftarg - rightarg;
+ case less_than:
+ return leftarg < rightarg;
+ case greater_than:
+ return leftarg > rightarg;
+ case less_or_equal:
+ return leftarg <= rightarg;
+ case greater_or_equal:
+ return leftarg >= rightarg;
+ case equal:
+ return leftarg == rightarg;
+ case not_equal:
+ return leftarg != rightarg;
+ default:
+ break;
+ }
+ }
+ /* NOTREACHED */
+ break;
+ }
+ case 3:
+ {
+ /* pexp->operation must be qmop. */
+ unsigned long int boolarg = plural_eval (pexp->val.args[0], n);
+ return plural_eval (pexp->val.args[boolarg ? 1 : 2], n);
+ }
+ }
+ /* NOTREACHED */
+ return 0;
+}
diff --git a/intl/explodename.c b/intl/explodename.c
new file mode 100644
index 000000000..8d3e1463d
--- /dev/null
+++ b/intl/explodename.c
@@ -0,0 +1,133 @@
+/* Copyright (C) 1995-1998, 2000-2001, 2003, 2005 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 Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#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 @@ */
+
+/* Split a locale name NAME into a leading language part and all the
+ rest. Return a pointer to the first character after the language,
+ i.e. to the first byte of the rest. */
+static char *_nl_find_language (const char *name);
+
+static char *
+_nl_find_language (const char *name)
+{
+ while (name[0] != '\0' && name[0] != '_' && name[0] != '@' && name[0] != '.')
+ ++name;
+
+ return (char *) name;
+}
+
+
+int
+_nl_explode_name (char *name,
+ const char **language, const char **modifier,
+ const char **territory, const char **codeset,
+ const char **normalized_codeset)
+{
+ char *cp;
+ int mask;
+
+ *modifier = NULL;
+ *territory = NULL;
+ *codeset = NULL;
+ *normalized_codeset = NULL;
+
+ /* Now we determine the single parts of the locale name. First
+ look for the language. Termination symbols are `_', '.', and `@'. */
+ mask = 0;
+ *language = cp = name;
+ cp = _nl_find_language (*language);
+
+ 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;
+
+ mask |= XPG_TERRITORY;
+ }
+
+ if (cp[0] == '.')
+ {
+ /* Next is the codeset. */
+ 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] == '@')
+ {
+ /* Next is the modifier. */
+ cp[0] = '\0';
+ *modifier = ++cp;
+
+ if (cp[0] != '\0')
+ mask |= XPG_MODIFIER;
+ }
+
+ if (*territory != NULL && (*territory)[0] == '\0')
+ mask &= ~XPG_TERRITORY;
+
+ if (*codeset != NULL && (*codeset)[0] == '\0')
+ mask &= ~XPG_CODESET;
+
+ return mask;
+}
diff --git a/intl/export.h b/intl/export.h
new file mode 100644
index 000000000..b5c47ad5b
--- /dev/null
+++ b/intl/export.h
@@ -0,0 +1,6 @@
+
+#if @HAVE_VISIBILITY@ && BUILDING_LIBINTL
+#define LIBINTL_DLL_EXPORTED __attribute__((__visibility__("default")))
+#else
+#define LIBINTL_DLL_EXPORTED
+#endif
diff --git a/intl/finddomain.c b/intl/finddomain.c
new file mode 100644
index 000000000..a25bebcb9
--- /dev/null
+++ b/intl/finddomain.c
@@ -0,0 +1,208 @@
+/* Handle list of needed message catalogs
+ Copyright (C) 1995-1999, 2000-2001, 2003-2006 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper@gnu.org>, 1995.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgnuintl.h"
+#endif
+
+/* Handle multi-threaded applications. */
+#ifdef _LIBC
+# include <bits/libc-lock.h>
+# define gl_rwlock_define_initialized __libc_rwlock_define_initialized
+# define gl_rwlock_rdlock __libc_rwlock_rdlock
+# define gl_rwlock_wrlock __libc_rwlock_wrlock
+# define gl_rwlock_unlock __libc_rwlock_unlock
+#else
+# include "lock.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 (const char *dirname, char *locale,
+ const char *domainname, struct binding *domainbinding)
+{
+ struct loaded_l10nfile *retval;
+ const char *language;
+ const char *modifier;
+ const char *territory;
+ const char *codeset;
+ const char *normalized_codeset;
+ const char *alias_value;
+ int mask;
+
+ /* LOCALE can consist of up to four recognized parts for the XPG syntax:
+
+ language[_territory][.codeset][@modifier]
+
+ 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) codeset
+ (2) normalized codeset
+ (3) territory
+ (4) modifier
+ */
+
+ /* We need to protect modifying the _NL_LOADED_DOMAINS data. */
+ gl_rwlock_define_initialized (static, lock);
+ gl_rwlock_rdlock (lock);
+
+ /* 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, domainname, 0);
+
+ gl_rwlock_unlock (lock);
+
+ if (retval != NULL)
+ {
+ /* We know something about this locale. */
+ int cnt;
+
+ if (retval->decided <= 0)
+ _nl_load_domain (retval, domainbinding);
+
+ 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], domainbinding);
+
+ if (retval->successor[cnt]->data != NULL)
+ break;
+ }
+
+ return retval;
+ /* 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 `@'. */
+ mask = _nl_explode_name (locale, &language, &modifier, &territory,
+ &codeset, &normalized_codeset);
+
+ /* We need to protect modifying the _NL_LOADED_DOMAINS data. */
+ gl_rwlock_wrlock (lock);
+
+ /* 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,
+ domainname, 1);
+
+ gl_rwlock_unlock (lock);
+
+ if (retval == NULL)
+ /* This means we are out of core. */
+ return NULL;
+
+ if (retval->decided <= 0)
+ _nl_load_domain (retval, domainbinding);
+ 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], domainbinding);
+ if (retval->successor[cnt]->data != NULL)
+ break;
+ }
+ }
+
+ /* The room for an alias was dynamically allocated. Free it now. */
+ if (alias_value != NULL)
+ free (locale);
+
+ /* The space for normalized_codeset is dynamically allocated. Free it. */
+ if (mask & XPG_NORM_CODESET)
+ free ((void *) normalized_codeset);
+
+ return retval;
+}
+
+
+#ifdef _LIBC
+/* This is called from iconv/gconv_db.c's free_mem, as locales must
+ be freed before freeing gconv steps arrays. */
+void __libc_freeres_fn_section
+_nl_finddomain_subfreeres ()
+{
+ 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 ((char *) here->filename);
+ free (here);
+ }
+}
+#endif
diff --git a/intl/gettext.c b/intl/gettext.c
new file mode 100644
index 000000000..d82d439c0
--- /dev/null
+++ b/intl/gettext.c
@@ -0,0 +1,63 @@
+/* Implementation of gettext(3) function.
+ Copyright (C) 1995, 1997, 2000-2003 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define __need_NULL
+# include <stddef.h>
+#else
+# include <stdlib.h> /* Just for NULL. */
+#endif
+
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgnuintl.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 DCGETTEXT INTUSE(__dcgettext)
+#else
+# define GETTEXT libintl_gettext
+# define DCGETTEXT libintl_dcgettext
+#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 (const char *msgid)
+{
+ return DCGETTEXT (NULL, msgid, LC_MESSAGES);
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library. */
+weak_alias (__gettext, gettext);
+#endif
diff --git a/intl/gettextP.h b/intl/gettextP.h
new file mode 100644
index 000000000..8be38d2d7
--- /dev/null
+++ b/intl/gettextP.h
@@ -0,0 +1,247 @@
+/* Header describing internals of libintl library.
+ Copyright (C) 1995-1999, 2000-2005 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper@cygnus.com>, 1995.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _GETTEXTP_H
+#define _GETTEXTP_H
+
+#include <stddef.h> /* Get size_t. */
+
+#ifdef _LIBC
+# include "../iconv/gconv_int.h"
+#else
+# if HAVE_ICONV
+# include <iconv.h>
+# endif
+#endif
+
+#ifdef _LIBC
+extern char *__gettext (const char *__msgid);
+extern char *__dgettext (const char *__domainname, const char *__msgid);
+extern char *__dcgettext (const char *__domainname, const char *__msgid,
+ int __category);
+extern char *__ngettext (const char *__msgid1, const char *__msgid2,
+ unsigned long int __n);
+extern char *__dngettext (const char *__domainname,
+ const char *__msgid1, const char *__msgid2,
+ unsigned long int n);
+extern char *__dcngettext (const char *__domainname,
+ const char *__msgid1, const char *__msgid2,
+ unsigned long int __n, int __category);
+extern char *__dcigettext (const char *__domainname,
+ const char *__msgid1, const char *__msgid2,
+ int __plural, unsigned long int __n,
+ int __category);
+extern char *__textdomain (const char *__domainname);
+extern char *__bindtextdomain (const char *__domainname,
+ const char *__dirname);
+extern char *__bind_textdomain_codeset (const char *__domainname,
+ const char *__codeset);
+extern void _nl_finddomain_subfreeres (void) attribute_hidden;
+extern void _nl_unload_domain (struct loaded_domain *__domain)
+ internal_function attribute_hidden;
+#else
+/* Declare the exported libintl_* functions, in a way that allows us to
+ call them under their real name. */
+# undef _INTL_REDIRECT_INLINE
+# undef _INTL_REDIRECT_MACROS
+# define _INTL_REDIRECT_MACROS
+# include "libgnuintl.h"
+# ifdef IN_LIBGLOCALE
+extern char *gl_dcigettext (const char *__domainname,
+ const char *__msgid1, const char *__msgid2,
+ int __plural, unsigned long int __n,
+ int __category,
+ const char *__localename, const char *__encoding);
+# else
+extern char *libintl_dcigettext (const char *__domainname,
+ const char *__msgid1, const char *__msgid2,
+ int __plural, unsigned long int __n,
+ int __category);
+# endif
+#endif
+
+#include "loadinfo.h"
+
+#include "gmo.h" /* Get nls_uint32. */
+
+/* @@ end of prolog @@ */
+
+#ifndef internal_function
+# define internal_function
+#endif
+
+#ifndef attribute_hidden
+# define attribute_hidden
+#endif
+
+/* Tell the compiler when a conditional or integer expression is
+ almost always true or almost always false. */
+#ifndef HAVE_BUILTIN_EXPECT
+# define __builtin_expect(expr, val) (expr)
+#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 inline nls_uint32
+SWAP (i)
+ nls_uint32 i;
+{
+ return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
+}
+#endif
+
+
+/* In-memory representation of system dependent string. */
+struct sysdep_string_desc
+{
+ /* Length of addressed string, including the trailing NUL. */
+ size_t length;
+ /* Pointer to addressed string. */
+ const char *pointer;
+};
+
+/* Cache of translated strings after charset conversion.
+ Note: The strings are converted to the target encoding only on an as-needed
+ basis. */
+struct converted_domain
+{
+ /* The target encoding name. */
+ const char *encoding;
+ /* The descriptor for conversion from the message catalog's encoding to
+ this target encoding. */
+#ifdef _LIBC
+ __gconv_t conv;
+#else
+# if HAVE_ICONV
+ iconv_t conv;
+# endif
+#endif
+ /* The table of translated strings after charset conversion. */
+ char **conv_tab;
+};
+
+/* The representation of an opened message catalog. */
+struct loaded_domain
+{
+ /* Pointer to memory containing the .mo file. */
+ const char *data;
+ /* 1 if the memory is mmap()ed, 0 if the memory is malloc()ed. */
+ int use_mmap;
+ /* Size of mmap()ed memory. */
+ size_t mmap_size;
+ /* 1 if the .mo file uses a different endianness than this machine. */
+ int must_swap;
+ /* Pointer to additional malloc()ed memory. */
+ void *malloced;
+
+ /* Number of static strings pairs. */
+ nls_uint32 nstrings;
+ /* Pointer to descriptors of original strings in the file. */
+ const struct string_desc *orig_tab;
+ /* Pointer to descriptors of translated strings in the file. */
+ const struct string_desc *trans_tab;
+
+ /* Number of system dependent strings pairs. */
+ nls_uint32 n_sysdep_strings;
+ /* Pointer to descriptors of original sysdep strings. */
+ const struct sysdep_string_desc *orig_sysdep_tab;
+ /* Pointer to descriptors of translated sysdep strings. */
+ const struct sysdep_string_desc *trans_sysdep_tab;
+
+ /* Size of hash table. */
+ nls_uint32 hash_size;
+ /* Pointer to hash table. */
+ const nls_uint32 *hash_tab;
+ /* 1 if the hash table uses a different endianness than this machine. */
+ int must_swap_hash_tab;
+
+ /* Cache of charset conversions of the translated strings. */
+ struct converted_domain *conversions;
+ size_t nconversions;
+
+ struct expression *plural;
+ unsigned long int nplurals;
+};
+
+/* We want to allocate a string at the end of the struct. But ISO C
+ doesn't allow zero sized arrays. */
+#ifdef __GNUC__
+# define ZERO 0
+#else
+# define ZERO 1
+#endif
+
+/* A set of settings bound to a message domain. Used to store settings
+ from bindtextdomain() and bind_textdomain_codeset(). */
+struct binding
+{
+ struct binding *next;
+ char *dirname;
+ char *codeset;
+ char domainname[ZERO];
+};
+
+/* A counter which is incremented each time some previous translations
+ become invalid.
+ This variable is part of the external ABI of the GNU libintl. */
+#ifdef IN_LIBGLOCALE
+# include <glocale/config.h>
+extern LIBGLOCALE_DLL_EXPORTED int _nl_msg_cat_cntr;
+#else
+extern LIBINTL_DLL_EXPORTED int _nl_msg_cat_cntr;
+#endif
+
+#ifndef _LIBC
+const char *_nl_language_preferences_default (void);
+const char *_nl_locale_name_posix (int category, const char *categoryname);
+const char *_nl_locale_name_default (void);
+const char *_nl_locale_name (int category, const char *categoryname);
+#endif
+
+struct loaded_l10nfile *_nl_find_domain (const char *__dirname, char *__locale,
+ const char *__domainname,
+ struct binding *__domainbinding)
+ internal_function;
+void _nl_load_domain (struct loaded_l10nfile *__domain,
+ struct binding *__domainbinding)
+ internal_function;
+
+#ifdef IN_LIBGLOCALE
+char *_nl_find_msg (struct loaded_l10nfile *domain_file,
+ struct binding *domainbinding, const char *encoding,
+ const char *msgid,
+ size_t *lengthp)
+ internal_function;
+#else
+char *_nl_find_msg (struct loaded_l10nfile *domain_file,
+ struct binding *domainbinding, const char *msgid,
+ int convert, size_t *lengthp)
+ internal_function;
+#endif
+
+/* @@ begin of epilog @@ */
+
+#endif /* gettextP.h */
diff --git a/intl/gmo.h b/intl/gmo.h
new file mode 100644
index 000000000..26515feb2
--- /dev/null
+++ b/intl/gmo.h
@@ -0,0 +1,149 @@
+/* Description of GNU message catalog format: general file layout.
+ Copyright (C) 1995, 1997, 2000-2002, 2004 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _GETTEXT_H
+#define _GETTEXT_H 1
+
+#include <limits.h>
+
+/* @@ 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
+#define MO_REVISION_NUMBER_WITH_SYSDEP_I 1
+
+/* 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
+ as of version autoconf-2.13, the AC_CHECK_SIZEOF macro doesn't work
+ when cross-compiling. */
+
+#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 following are only used in .mo files with major revision 0 or 1. */
+
+ /* 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 translated strings. */
+ nls_uint32 trans_tab_offset;
+ /* Size of hash table. */
+ nls_uint32 hash_tab_size;
+ /* Offset of first hash table entry. */
+ nls_uint32 hash_tab_offset;
+
+ /* The following are only used in .mo files with minor revision >= 1. */
+
+ /* The number of system dependent segments. */
+ nls_uint32 n_sysdep_segments;
+ /* Offset of table describing system dependent segments. */
+ nls_uint32 sysdep_segments_offset;
+ /* The number of system dependent strings pairs. */
+ nls_uint32 n_sysdep_strings;
+ /* Offset of table with start offsets of original sysdep strings. */
+ nls_uint32 orig_sysdep_tab_offset;
+ /* Offset of table with start offsets of translated sysdep strings. */
+ nls_uint32 trans_sysdep_tab_offset;
+};
+
+/* Descriptor for static string contained in the binary .mo file. */
+struct string_desc
+{
+ /* Length of addressed string, not including the trailing NUL. */
+ nls_uint32 length;
+ /* Offset of string in file. */
+ nls_uint32 offset;
+};
+
+/* The following are only used in .mo files with minor revision >= 1. */
+
+/* Descriptor for system dependent string segment. */
+struct sysdep_segment
+{
+ /* Length of addressed string, including the trailing NUL. */
+ nls_uint32 length;
+ /* Offset of string in file. */
+ nls_uint32 offset;
+};
+
+/* Descriptor for system dependent string. */
+struct sysdep_string
+{
+ /* Offset of static string segments in file. */
+ nls_uint32 offset;
+ /* Alternating sequence of static and system dependent segments.
+ The last segment is a static segment, including the trailing NUL. */
+ struct segment_pair
+ {
+ /* Size of static segment. */
+ nls_uint32 segsize;
+ /* Reference to system dependent string segment, or ~0 at the end. */
+ nls_uint32 sysdepref;
+ } segments[1];
+};
+
+/* Marker for the end of the segments[] array. This has the value 0xFFFFFFFF,
+ regardless whether 'int' is 16 bit, 32 bit, or 64 bit. */
+#define SEGMENTS_END ((nls_uint32) ~0)
+
+/* @@ begin of epilog @@ */
+
+#endif /* gettext.h */
diff --git a/intl/hash-string.c b/intl/hash-string.c
new file mode 100644
index 000000000..3c513f099
--- /dev/null
+++ b/intl/hash-string.c
@@ -0,0 +1,51 @@
+/* Implements a string hashing function.
+ Copyright (C) 1995, 1997, 1998, 2000, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "hash-string.h"
+
+
+/* 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.] */
+unsigned long int
+__hash_string (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 char) *str++;
+ g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
+ if (g != 0)
+ {
+ hval ^= g >> (HASHWORDBITS - 8);
+ hval ^= g;
+ }
+ }
+ return hval;
+}
diff --git a/intl/hash-string.h b/intl/hash-string.h
new file mode 100644
index 000000000..98c07e4a7
--- /dev/null
+++ b/intl/hash-string.h
@@ -0,0 +1,36 @@
+/* Description of GNU message catalog format: string hashing function.
+ Copyright (C) 1995, 1997-1998, 2000-2003, 2005 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* @@ end of prolog @@ */
+
+/* We assume to have `unsigned long int' value with at least 32 bits. */
+#define HASHWORDBITS 32
+
+
+#ifndef _LIBC
+# ifdef IN_LIBINTL
+# define __hash_string libintl_hash_string
+# else
+# define __hash_string hash_string
+# endif
+#endif
+
+/* 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.] */
+extern unsigned long int __hash_string (const char *str_param);
diff --git a/intl/intl-compat.c b/intl/intl-compat.c
new file mode 100644
index 000000000..9b9ecbb64
--- /dev/null
+++ b/intl/intl-compat.c
@@ -0,0 +1,133 @@
+/* intl-compat.c - Stub functions to call gettext functions from GNU gettext
+ Library.
+ Copyright (C) 1995, 2000-2003, 2005 Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "gettextP.h"
+
+/* @@ end of prolog @@ */
+
+/* This file redirects the gettext functions (without prefix) to those
+ defined in the included GNU libintl library (with "libintl_" prefix).
+ It is compiled into libintl in order to make the AM_GNU_GETTEXT test
+ of gettext <= 0.11.2 work with the libintl library >= 0.11.3 which
+ has the redirections primarily in the <libintl.h> include file.
+ It is also compiled into libgnuintl so that libgnuintl.so can be used
+ as LD_PRELOADable library on glibc systems, to provide the extra
+ features that the functions in the libc don't have (namely, logging). */
+
+
+#undef gettext
+#undef dgettext
+#undef dcgettext
+#undef ngettext
+#undef dngettext
+#undef dcngettext
+#undef textdomain
+#undef bindtextdomain
+#undef bind_textdomain_codeset
+
+
+/* When building a DLL, we must export some functions. Note that because
+ the functions are only defined for binary backward compatibility, we
+ don't need to use __declspec(dllimport) in any case. */
+#if HAVE_VISIBILITY && BUILDING_DLL
+# define DLL_EXPORTED __attribute__((__visibility__("default")))
+#elif defined _MSC_VER && BUILDING_DLL
+# define DLL_EXPORTED __declspec(dllexport)
+#else
+# define DLL_EXPORTED
+#endif
+
+
+DLL_EXPORTED
+char *
+gettext (const char *msgid)
+{
+ return libintl_gettext (msgid);
+}
+
+
+DLL_EXPORTED
+char *
+dgettext (const char *domainname, const char *msgid)
+{
+ return libintl_dgettext (domainname, msgid);
+}
+
+
+DLL_EXPORTED
+char *
+dcgettext (const char *domainname, const char *msgid, int category)
+{
+ return libintl_dcgettext (domainname, msgid, category);
+}
+
+
+DLL_EXPORTED
+char *
+ngettext (const char *msgid1, const char *msgid2, unsigned long int n)
+{
+ return libintl_ngettext (msgid1, msgid2, n);
+}
+
+
+DLL_EXPORTED
+char *
+dngettext (const char *domainname,
+ const char *msgid1, const char *msgid2, unsigned long int n)
+{
+ return libintl_dngettext (domainname, msgid1, msgid2, n);
+}
+
+
+DLL_EXPORTED
+char *
+dcngettext (const char *domainname,
+ const char *msgid1, const char *msgid2, unsigned long int n,
+ int category)
+{
+ return libintl_dcngettext (domainname, msgid1, msgid2, n, category);
+}
+
+
+DLL_EXPORTED
+char *
+textdomain (const char *domainname)
+{
+ return libintl_textdomain (domainname);
+}
+
+
+DLL_EXPORTED
+char *
+bindtextdomain (const char *domainname, const char *dirname)
+{
+ return libintl_bindtextdomain (domainname, dirname);
+}
+
+
+DLL_EXPORTED
+char *
+bind_textdomain_codeset (const char *domainname, const char *codeset)
+{
+ return libintl_bind_textdomain_codeset (domainname, codeset);
+}
diff --git a/intl/intl-exports.c b/intl/intl-exports.c
new file mode 100644
index 000000000..717658994
--- /dev/null
+++ b/intl/intl-exports.c
@@ -0,0 +1,36 @@
+/* List of exported symbols of libintl on Cygwin.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2006.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+ /* IMP(x) is a symbol that contains the address of x. */
+#define IMP(x) _imp__##x
+
+ /* Ensure that the variable x is exported from the library, and that a
+ pseudo-variable IMP(x) is available. */
+#define VARIABLE(x) \
+ /* Export x without redefining x. This code was found by compiling a \
+ snippet: \
+ extern __declspec(dllexport) int x; int x = 42; */ \
+ asm (".section .drectve\n"); \
+ asm (".ascii \" -export:" #x ",data\"\n"); \
+ asm (".data\n"); \
+ /* Allocate a pseudo-variable IMP(x). */ \
+ extern int x; \
+ void * IMP(x) = &x;
+
+VARIABLE(libintl_version)
diff --git a/intl/l10nflist.c b/intl/l10nflist.c
new file mode 100644
index 000000000..365aeb708
--- /dev/null
+++ b/intl/l10nflist.c
@@ -0,0 +1,400 @@
+/* Copyright (C) 1995-1999, 2000-2006 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 Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Tell glibc's <string.h> to provide a prototype for stpcpy().
+ This must come before <config.h> because <config.h> may include
+ <features.h>, and once <features.h> has been included, it's too late. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#if defined _LIBC || defined HAVE_ARGZ_H
+# include <argz.h>
+#endif
+#include <ctype.h>
+#include <sys/types.h>
+#include <stdlib.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 @@ */
+
+#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 (char *dest, const char *src);
+# endif
+#endif
+
+/* Pathname support.
+ ISSLASH(C) tests whether C is a directory separator character.
+ IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
+ it may be concatenated to a directory pathname.
+ */
+#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
+ /* Win32, Cygwin, OS/2, DOS */
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+# define HAS_DEVICE(P) \
+ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
+ && (P)[1] == ':')
+# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
+#else
+ /* Unix */
+# define ISSLASH(C) ((C) == '/')
+# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
+#endif
+
+/* Define function which are usually not available. */
+
+#ifdef _LIBC
+# define __argz_count(argz, len) INTUSE(__argz_count) (argz, len)
+#elif defined HAVE_ARGZ_COUNT
+# undef __argz_count
+# define __argz_count argz_count
+#else
+/* Returns the number of strings in ARGZ. */
+static size_t
+argz_count__ (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 */
+
+#ifdef _LIBC
+# define __argz_stringify(argz, len, sep) \
+ INTUSE(__argz_stringify) (argz, len, sep)
+#elif defined HAVE_ARGZ_STRINGIFY
+# undef __argz_stringify
+# define __argz_stringify argz_stringify
+#else
+/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
+ except the last into the character SEP. */
+static void
+argz_stringify__ (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 */
+
+#ifdef _LIBC
+#elif defined HAVE_ARGZ_NEXT
+# undef __argz_next
+# define __argz_next argz_next
+#else
+static char *
+argz_next__ (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 inline int
+pop (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 (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 *filename, int do_allocate)
+{
+ char *abs_filename;
+ struct loaded_l10nfile **lastp;
+ struct loaded_l10nfile *retval;
+ char *cp;
+ size_t dirlist_count;
+ size_t entries;
+ int cnt;
+
+ /* If LANGUAGE contains an absolute directory specification, we ignore
+ DIRLIST. */
+ if (IS_ABSOLUTE_PATH (language))
+ dirlist_len = 0;
+
+ /* Allocate room for the full file name. */
+ abs_filename = (char *) malloc (dirlist_len
+ + strlen (language)
+ + ((mask & XPG_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)
+ + 1 + strlen (filename) + 1);
+
+ if (abs_filename == NULL)
+ return NULL;
+
+ /* Construct file name. */
+ cp = abs_filename;
+ if (dirlist_len > 0)
+ {
+ memcpy (cp, dirlist, dirlist_len);
+ __argz_stringify (cp, dirlist_len, PATH_SEPARATOR);
+ cp += dirlist_len;
+ cp[-1] = '/';
+ }
+
+ cp = stpcpy (cp, language);
+
+ if ((mask & XPG_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) != 0)
+ {
+ *cp++ = '@';
+ cp = stpcpy (cp, modifier);
+ }
+
+ *cp++ = '/';
+ stpcpy (cp, filename);
+
+ /* Look in list of already loaded domains whether it is already
+ available. */
+ lastp = l10nfile_list;
+ 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;
+ }
+
+ lastp = &retval->next;
+ }
+
+ if (retval != NULL || do_allocate == 0)
+ {
+ free (abs_filename);
+ return retval;
+ }
+
+ dirlist_count = (dirlist_len > 0 ? __argz_count (dirlist, dirlist_len) : 1);
+
+ /* Allocate a new loaded_l10nfile. */
+ retval =
+ (struct loaded_l10nfile *)
+ malloc (sizeof (*retval)
+ + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0))
+ * sizeof (struct loaded_l10nfile *)));
+ if (retval == NULL)
+ {
+ free (abs_filename);
+ return NULL;
+ }
+
+ retval->filename = abs_filename;
+
+ /* We set retval->data to NULL here; it is filled in later.
+ Setting retval->decided to 1 here means that retval does not
+ correspond to a real file (dirlist_count > 1) or is not worth
+ looking up (if an unnormalized codeset was specified). */
+ retval->decided = (dirlist_count > 1
+ || ((mask & XPG_CODESET) != 0
+ && (mask & XPG_NORM_CODESET) != 0));
+ retval->data = NULL;
+
+ retval->next = *lastp;
+ *lastp = retval;
+
+ entries = 0;
+ /* Recurse to fill the inheritance list of RETVAL.
+ If the DIRLIST is a real list (i.e. DIRLIST_COUNT > 1), the RETVAL
+ entry does not correspond to a real file; retval->filename contains
+ colons. In this case we loop across all elements of DIRLIST and
+ across all bit patterns dominated by MASK.
+ If the DIRLIST is a single directory or entirely redundant (i.e.
+ DIRLIST_COUNT == 1), we loop across all bit patterns dominated by
+ MASK, excluding MASK itself.
+ In either case, we loop down from MASK to 0. This has the effect
+ that the extra bits in the locale name are dropped in this order:
+ first the modifier, then the territory, then the codeset, then the
+ normalized_codeset. */
+ for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt)
+ if ((cnt & ~mask) == 0
+ && !((cnt & XPG_CODESET) != 0 && (cnt & XPG_NORM_CODESET) != 0))
+ {
+ if (dirlist_count > 1)
+ {
+ /* 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, filename,
+ 1);
+ }
+ else
+ retval->successor[entries++]
+ = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len,
+ cnt, language, territory, codeset,
+ normalized_codeset, modifier, 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. The return value is dynamically allocated and has to be
+ freed by the caller. */
+const char *
+_nl_normalize_codeset (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 ((unsigned char) codeset[cnt]))
+ {
+ ++len;
+
+ if (isalpha ((unsigned char) 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 ((unsigned char) codeset[cnt]))
+ *wp++ = tolower ((unsigned char) codeset[cnt]);
+ else if (isdigit ((unsigned char) 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 (char *dest, const char *src)
+{
+ while ((*dest++ = *src++) != '\0')
+ /* Do nothing. */ ;
+ return dest - 1;
+}
+#endif
diff --git a/intl/langprefs.c b/intl/langprefs.c
new file mode 100644
index 000000000..59c8def21
--- /dev/null
+++ b/intl/langprefs.c
@@ -0,0 +1,130 @@
+/* Determine the user's language preferences.
+ Copyright (C) 2004-2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Written by Bruno Haible <bruno@clisp.org>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#if HAVE_CFPREFERENCESCOPYAPPVALUE
+# include <string.h>
+# include <CoreFoundation/CFPreferences.h>
+# include <CoreFoundation/CFPropertyList.h>
+# include <CoreFoundation/CFArray.h>
+# include <CoreFoundation/CFString.h>
+extern void _nl_locale_name_canonicalize (char *name);
+#endif
+
+/* Determine the user's language preferences, as a colon separated list of
+ locale names in XPG syntax
+ language[_territory][.codeset][@modifier]
+ The result must not be freed; it is statically allocated.
+ The LANGUAGE environment variable does not need to be considered; it is
+ already taken into account by the caller. */
+
+const char *
+_nl_language_preferences_default (void)
+{
+#if HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.2 or newer */
+ {
+ /* Cache the preferences list, since CoreFoundation calls are expensive. */
+ static const char *cached_languages;
+ static int cache_initialized;
+
+ if (!cache_initialized)
+ {
+ CFTypeRef preferences =
+ CFPreferencesCopyAppValue (CFSTR ("AppleLanguages"),
+ kCFPreferencesCurrentApplication);
+ if (preferences != NULL
+ && CFGetTypeID (preferences) == CFArrayGetTypeID ())
+ {
+ CFArrayRef prefArray = (CFArrayRef)preferences;
+ int n = CFArrayGetCount (prefArray);
+ char buf[256];
+ size_t size = 0;
+ int i;
+
+ for (i = 0; i < n; i++)
+ {
+ CFTypeRef element = CFArrayGetValueAtIndex (prefArray, i);
+ if (element != NULL
+ && CFGetTypeID (element) == CFStringGetTypeID ()
+ && CFStringGetCString ((CFStringRef)element,
+ buf, sizeof (buf),
+ kCFStringEncodingASCII))
+ {
+ _nl_locale_name_canonicalize (buf);
+ size += strlen (buf) + 1;
+ /* Most GNU programs use msgids in English and don't ship
+ an en.mo message catalog. Therefore when we see "en"
+ in the preferences list, arrange for gettext() to
+ return the msgid, and ignore all further elements of
+ the preferences list. */
+ if (strcmp (buf, "en") == 0)
+ break;
+ }
+ else
+ break;
+ }
+ if (size > 0)
+ {
+ char *languages = (char *) malloc (size);
+
+ if (languages != NULL)
+ {
+ char *p = languages;
+
+ for (i = 0; i < n; i++)
+ {
+ CFTypeRef element =
+ CFArrayGetValueAtIndex (prefArray, i);
+ if (element != NULL
+ && CFGetTypeID (element) == CFStringGetTypeID ()
+ && CFStringGetCString ((CFStringRef)element,
+ buf, sizeof (buf),
+ kCFStringEncodingASCII))
+ {
+ _nl_locale_name_canonicalize (buf);
+ strcpy (p, buf);
+ p += strlen (buf);
+ *p++ = ':';
+ if (strcmp (buf, "en") == 0)
+ break;
+ }
+ else
+ break;
+ }
+ *--p = '\0';
+
+ cached_languages = languages;
+ }
+ }
+ }
+ cache_initialized = 1;
+ }
+ if (cached_languages != NULL)
+ return cached_languages;
+ }
+#endif
+
+ return NULL;
+}
diff --git a/intl/loadinfo.h b/intl/loadinfo.h
new file mode 100644
index 000000000..a7a197031
--- /dev/null
+++ b/intl/loadinfo.h
@@ -0,0 +1,132 @@
+/* Copyright (C) 1996-1999, 2000-2003, 2005-2006 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 Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _LOADINFO_H
+#define _LOADINFO_H 1
+
+/* Declarations of locale dependent catalog lookup functions.
+ Implemented in
+
+ localealias.c Possibly replace a locale name by another.
+ explodename.c Split a locale name into its various fields.
+ l10nflist.c Generate a list of filenames of possible message catalogs.
+ finddomain.c Find and open the relevant message catalogs.
+
+ The main function _nl_find_domain() in finddomain.c is declared
+ in gettextP.h.
+ */
+
+#ifndef internal_function
+# define internal_function
+#endif
+
+#ifndef LIBINTL_DLL_EXPORTED
+# define LIBINTL_DLL_EXPORTED
+#endif
+
+/* Tell the compiler when a conditional or integer expression is
+ almost always true or almost always false. */
+#ifndef HAVE_BUILTIN_EXPECT
+# define __builtin_expect(expr, val) (expr)
+#endif
+
+/* Separator in PATH like lists of pathnames. */
+#if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
+ /* Win32, OS/2, DOS */
+# define PATH_SEPARATOR ';'
+#else
+ /* Unix */
+# define PATH_SEPARATOR ':'
+#endif
+
+/* Encoding of locale name parts. */
+#define XPG_NORM_CODESET 1
+#define XPG_CODESET 2
+#define XPG_TERRITORY 4
+#define XPG_MODIFIER 8
+
+
+struct loaded_l10nfile
+{
+ const char *filename;
+ int decided;
+
+ const void *data;
+
+ struct loaded_l10nfile *next;
+ struct loaded_l10nfile *successor[1];
+};
+
+
+/* Normalize codeset name. There is no standard for the codeset
+ names. Normalization allows the user to use any of the common
+ names. The return value is dynamically allocated and has to be
+ freed by the caller. */
+extern const char *_nl_normalize_codeset (const char *codeset,
+ size_t name_len);
+
+/* Lookup a locale dependent file.
+ *L10NFILE_LIST denotes a pool of lookup results of locale dependent
+ files of the same kind, sorted in decreasing order of ->filename.
+ DIRLIST and DIRLIST_LEN are an argz list of directories in which to
+ look, containing at least one directory (i.e. DIRLIST_LEN > 0).
+ MASK, LANGUAGE, TERRITORY, CODESET, NORMALIZED_CODESET, MODIFIER
+ are the pieces of the locale name, as produced by _nl_explode_name().
+ FILENAME is the filename suffix.
+ The return value is the lookup result, either found in *L10NFILE_LIST,
+ or - if DO_ALLOCATE is nonzero - freshly allocated, or possibly NULL.
+ If the return value is non-NULL, it is added to *L10NFILE_LIST, and
+ its ->next field denotes the chaining inside *L10NFILE_LIST, and
+ furthermore its ->successor[] field contains a list of other lookup
+ results from which this lookup result inherits. */
+extern struct loaded_l10nfile *
+_nl_make_l10nflist (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 *filename, int do_allocate);
+
+/* Lookup the real locale name for a locale alias NAME, or NULL if
+ NAME is not a locale alias (but possibly a real locale name).
+ The return value is statically allocated and must not be freed. */
+/* Part of the libintl ABI only for the sake of the gettext.m4 macro. */
+extern LIBINTL_DLL_EXPORTED const char *_nl_expand_alias (const char *name);
+
+/* Split a locale name NAME into its pieces: language, modifier,
+ territory, codeset.
+ NAME gets destructively modified: NUL bytes are inserted here and
+ there. *LANGUAGE gets assigned NAME. Each of *MODIFIER, *TERRITORY,
+ *CODESET gets assigned either a pointer into the old NAME string, or
+ NULL. *NORMALIZED_CODESET gets assigned the expanded *CODESET, if it
+ is different from *CODESET; this one is dynamically allocated and has
+ to be freed by the caller.
+ The return value is a bitmask, where each bit corresponds to one
+ filled-in value:
+ XPG_MODIFIER for *MODIFIER,
+ XPG_TERRITORY for *TERRITORY,
+ XPG_CODESET for *CODESET,
+ XPG_NORM_CODESET for *NORMALIZED_CODESET.
+ */
+extern int _nl_explode_name (char *name, const char **language,
+ const char **modifier, const char **territory,
+ const char **codeset,
+ const char **normalized_codeset);
+
+#endif /* loadinfo.h */
diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c
new file mode 100644
index 000000000..2520c8c21
--- /dev/null
+++ b/intl/loadmsgcat.c
@@ -0,0 +1,1333 @@
+/* Load needed message catalogs.
+ Copyright (C) 1995-1999, 2000-2005 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Tell glibc's <string.h> to provide a prototype for mempcpy().
+ This must come before <config.h> because <config.h> may include
+ <features.h>, and once <features.h> has been included, it's too late. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef __GNUC__
+# undef alloca
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+#else
+# ifdef _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# 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
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#ifdef _LIBC
+# include <langinfo.h>
+# include <locale.h>
+#endif
+
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+ || (defined _LIBC && defined _POSIX_MAPPED_FILES)
+# include <sys/mman.h>
+# undef HAVE_MMAP
+# define HAVE_MMAP 1
+#else
+# undef HAVE_MMAP
+#endif
+
+#if defined HAVE_STDINT_H_WITH_UINTMAX || defined _LIBC
+# include <stdint.h>
+#endif
+#if defined HAVE_INTTYPES_H || defined _LIBC
+# include <inttypes.h>
+#endif
+
+#include "gmo.h"
+#include "gettextP.h"
+#include "hash-string.h"
+#include "plural-exp.h"
+
+#ifdef _LIBC
+# include "../locale/localeinfo.h"
+# include <not-cancel.h>
+#endif
+
+/* Handle multi-threaded applications. */
+#ifdef _LIBC
+# include <bits/libc-lock.h>
+#else
+# include "lock.h"
+#endif
+
+/* Provide fallback values for macros that ought to be defined in <inttypes.h>.
+ Note that our fallback values need not be literal strings, because we don't
+ use them with preprocessor string concatenation. */
+#if !defined PRId8 || PRI_MACROS_BROKEN
+# undef PRId8
+# define PRId8 "d"
+#endif
+#if !defined PRIi8 || PRI_MACROS_BROKEN
+# undef PRIi8
+# define PRIi8 "i"
+#endif
+#if !defined PRIo8 || PRI_MACROS_BROKEN
+# undef PRIo8
+# define PRIo8 "o"
+#endif
+#if !defined PRIu8 || PRI_MACROS_BROKEN
+# undef PRIu8
+# define PRIu8 "u"
+#endif
+#if !defined PRIx8 || PRI_MACROS_BROKEN
+# undef PRIx8
+# define PRIx8 "x"
+#endif
+#if !defined PRIX8 || PRI_MACROS_BROKEN
+# undef PRIX8
+# define PRIX8 "X"
+#endif
+#if !defined PRId16 || PRI_MACROS_BROKEN
+# undef PRId16
+# define PRId16 "d"
+#endif
+#if !defined PRIi16 || PRI_MACROS_BROKEN
+# undef PRIi16
+# define PRIi16 "i"
+#endif
+#if !defined PRIo16 || PRI_MACROS_BROKEN
+# undef PRIo16
+# define PRIo16 "o"
+#endif
+#if !defined PRIu16 || PRI_MACROS_BROKEN
+# undef PRIu16
+# define PRIu16 "u"
+#endif
+#if !defined PRIx16 || PRI_MACROS_BROKEN
+# undef PRIx16
+# define PRIx16 "x"
+#endif
+#if !defined PRIX16 || PRI_MACROS_BROKEN
+# undef PRIX16
+# define PRIX16 "X"
+#endif
+#if !defined PRId32 || PRI_MACROS_BROKEN
+# undef PRId32
+# define PRId32 "d"
+#endif
+#if !defined PRIi32 || PRI_MACROS_BROKEN
+# undef PRIi32
+# define PRIi32 "i"
+#endif
+#if !defined PRIo32 || PRI_MACROS_BROKEN
+# undef PRIo32
+# define PRIo32 "o"
+#endif
+#if !defined PRIu32 || PRI_MACROS_BROKEN
+# undef PRIu32
+# define PRIu32 "u"
+#endif
+#if !defined PRIx32 || PRI_MACROS_BROKEN
+# undef PRIx32
+# define PRIx32 "x"
+#endif
+#if !defined PRIX32 || PRI_MACROS_BROKEN
+# undef PRIX32
+# define PRIX32 "X"
+#endif
+#if !defined PRId64 || PRI_MACROS_BROKEN
+# undef PRId64
+# define PRId64 (sizeof (long) == 8 ? "ld" : "lld")
+#endif
+#if !defined PRIi64 || PRI_MACROS_BROKEN
+# undef PRIi64
+# define PRIi64 (sizeof (long) == 8 ? "li" : "lli")
+#endif
+#if !defined PRIo64 || PRI_MACROS_BROKEN
+# undef PRIo64
+# define PRIo64 (sizeof (long) == 8 ? "lo" : "llo")
+#endif
+#if !defined PRIu64 || PRI_MACROS_BROKEN
+# undef PRIu64
+# define PRIu64 (sizeof (long) == 8 ? "lu" : "llu")
+#endif
+#if !defined PRIx64 || PRI_MACROS_BROKEN
+# undef PRIx64
+# define PRIx64 (sizeof (long) == 8 ? "lx" : "llx")
+#endif
+#if !defined PRIX64 || PRI_MACROS_BROKEN
+# undef PRIX64
+# define PRIX64 (sizeof (long) == 8 ? "lX" : "llX")
+#endif
+#if !defined PRIdLEAST8 || PRI_MACROS_BROKEN
+# undef PRIdLEAST8
+# define PRIdLEAST8 "d"
+#endif
+#if !defined PRIiLEAST8 || PRI_MACROS_BROKEN
+# undef PRIiLEAST8
+# define PRIiLEAST8 "i"
+#endif
+#if !defined PRIoLEAST8 || PRI_MACROS_BROKEN
+# undef PRIoLEAST8
+# define PRIoLEAST8 "o"
+#endif
+#if !defined PRIuLEAST8 || PRI_MACROS_BROKEN
+# undef PRIuLEAST8
+# define PRIuLEAST8 "u"
+#endif
+#if !defined PRIxLEAST8 || PRI_MACROS_BROKEN
+# undef PRIxLEAST8
+# define PRIxLEAST8 "x"
+#endif
+#if !defined PRIXLEAST8 || PRI_MACROS_BROKEN
+# undef PRIXLEAST8
+# define PRIXLEAST8 "X"
+#endif
+#if !defined PRIdLEAST16 || PRI_MACROS_BROKEN
+# undef PRIdLEAST16
+# define PRIdLEAST16 "d"
+#endif
+#if !defined PRIiLEAST16 || PRI_MACROS_BROKEN
+# undef PRIiLEAST16
+# define PRIiLEAST16 "i"
+#endif
+#if !defined PRIoLEAST16 || PRI_MACROS_BROKEN
+# undef PRIoLEAST16
+# define PRIoLEAST16 "o"
+#endif
+#if !defined PRIuLEAST16 || PRI_MACROS_BROKEN
+# undef PRIuLEAST16
+# define PRIuLEAST16 "u"
+#endif
+#if !defined PRIxLEAST16 || PRI_MACROS_BROKEN
+# undef PRIxLEAST16
+# define PRIxLEAST16 "x"
+#endif
+#if !defined PRIXLEAST16 || PRI_MACROS_BROKEN
+# undef PRIXLEAST16
+# define PRIXLEAST16 "X"
+#endif
+#if !defined PRIdLEAST32 || PRI_MACROS_BROKEN
+# undef PRIdLEAST32
+# define PRIdLEAST32 "d"
+#endif
+#if !defined PRIiLEAST32 || PRI_MACROS_BROKEN
+# undef PRIiLEAST32
+# define PRIiLEAST32 "i"
+#endif
+#if !defined PRIoLEAST32 || PRI_MACROS_BROKEN
+# undef PRIoLEAST32
+# define PRIoLEAST32 "o"
+#endif
+#if !defined PRIuLEAST32 || PRI_MACROS_BROKEN
+# undef PRIuLEAST32
+# define PRIuLEAST32 "u"
+#endif
+#if !defined PRIxLEAST32 || PRI_MACROS_BROKEN
+# undef PRIxLEAST32
+# define PRIxLEAST32 "x"
+#endif
+#if !defined PRIXLEAST32 || PRI_MACROS_BROKEN
+# undef PRIXLEAST32
+# define PRIXLEAST32 "X"
+#endif
+#if !defined PRIdLEAST64 || PRI_MACROS_BROKEN
+# undef PRIdLEAST64
+# define PRIdLEAST64 PRId64
+#endif
+#if !defined PRIiLEAST64 || PRI_MACROS_BROKEN
+# undef PRIiLEAST64
+# define PRIiLEAST64 PRIi64
+#endif
+#if !defined PRIoLEAST64 || PRI_MACROS_BROKEN
+# undef PRIoLEAST64
+# define PRIoLEAST64 PRIo64
+#endif
+#if !defined PRIuLEAST64 || PRI_MACROS_BROKEN
+# undef PRIuLEAST64
+# define PRIuLEAST64 PRIu64
+#endif
+#if !defined PRIxLEAST64 || PRI_MACROS_BROKEN
+# undef PRIxLEAST64
+# define PRIxLEAST64 PRIx64
+#endif
+#if !defined PRIXLEAST64 || PRI_MACROS_BROKEN
+# undef PRIXLEAST64
+# define PRIXLEAST64 PRIX64
+#endif
+#if !defined PRIdFAST8 || PRI_MACROS_BROKEN
+# undef PRIdFAST8
+# define PRIdFAST8 "d"
+#endif
+#if !defined PRIiFAST8 || PRI_MACROS_BROKEN
+# undef PRIiFAST8
+# define PRIiFAST8 "i"
+#endif
+#if !defined PRIoFAST8 || PRI_MACROS_BROKEN
+# undef PRIoFAST8
+# define PRIoFAST8 "o"
+#endif
+#if !defined PRIuFAST8 || PRI_MACROS_BROKEN
+# undef PRIuFAST8
+# define PRIuFAST8 "u"
+#endif
+#if !defined PRIxFAST8 || PRI_MACROS_BROKEN
+# undef PRIxFAST8
+# define PRIxFAST8 "x"
+#endif
+#if !defined PRIXFAST8 || PRI_MACROS_BROKEN
+# undef PRIXFAST8
+# define PRIXFAST8 "X"
+#endif
+#if !defined PRIdFAST16 || PRI_MACROS_BROKEN
+# undef PRIdFAST16
+# define PRIdFAST16 "d"
+#endif
+#if !defined PRIiFAST16 || PRI_MACROS_BROKEN
+# undef PRIiFAST16
+# define PRIiFAST16 "i"
+#endif
+#if !defined PRIoFAST16 || PRI_MACROS_BROKEN
+# undef PRIoFAST16
+# define PRIoFAST16 "o"
+#endif
+#if !defined PRIuFAST16 || PRI_MACROS_BROKEN
+# undef PRIuFAST16
+# define PRIuFAST16 "u"
+#endif
+#if !defined PRIxFAST16 || PRI_MACROS_BROKEN
+# undef PRIxFAST16
+# define PRIxFAST16 "x"
+#endif
+#if !defined PRIXFAST16 || PRI_MACROS_BROKEN
+# undef PRIXFAST16
+# define PRIXFAST16 "X"
+#endif
+#if !defined PRIdFAST32 || PRI_MACROS_BROKEN
+# undef PRIdFAST32
+# define PRIdFAST32 "d"
+#endif
+#if !defined PRIiFAST32 || PRI_MACROS_BROKEN
+# undef PRIiFAST32
+# define PRIiFAST32 "i"
+#endif
+#if !defined PRIoFAST32 || PRI_MACROS_BROKEN
+# undef PRIoFAST32
+# define PRIoFAST32 "o"
+#endif
+#if !defined PRIuFAST32 || PRI_MACROS_BROKEN
+# undef PRIuFAST32
+# define PRIuFAST32 "u"
+#endif
+#if !defined PRIxFAST32 || PRI_MACROS_BROKEN
+# undef PRIxFAST32
+# define PRIxFAST32 "x"
+#endif
+#if !defined PRIXFAST32 || PRI_MACROS_BROKEN
+# undef PRIXFAST32
+# define PRIXFAST32 "X"
+#endif
+#if !defined PRIdFAST64 || PRI_MACROS_BROKEN
+# undef PRIdFAST64
+# define PRIdFAST64 PRId64
+#endif
+#if !defined PRIiFAST64 || PRI_MACROS_BROKEN
+# undef PRIiFAST64
+# define PRIiFAST64 PRIi64
+#endif
+#if !defined PRIoFAST64 || PRI_MACROS_BROKEN
+# undef PRIoFAST64
+# define PRIoFAST64 PRIo64
+#endif
+#if !defined PRIuFAST64 || PRI_MACROS_BROKEN
+# undef PRIuFAST64
+# define PRIuFAST64 PRIu64
+#endif
+#if !defined PRIxFAST64 || PRI_MACROS_BROKEN
+# undef PRIxFAST64
+# define PRIxFAST64 PRIx64
+#endif
+#if !defined PRIXFAST64 || PRI_MACROS_BROKEN
+# undef PRIXFAST64
+# define PRIXFAST64 PRIX64
+#endif
+#if !defined PRIdMAX || PRI_MACROS_BROKEN
+# undef PRIdMAX
+# define PRIdMAX (sizeof (uintmax_t) == sizeof (long) ? "ld" : "lld")
+#endif
+#if !defined PRIiMAX || PRI_MACROS_BROKEN
+# undef PRIiMAX
+# define PRIiMAX (sizeof (uintmax_t) == sizeof (long) ? "li" : "lli")
+#endif
+#if !defined PRIoMAX || PRI_MACROS_BROKEN
+# undef PRIoMAX
+# define PRIoMAX (sizeof (uintmax_t) == sizeof (long) ? "lo" : "llo")
+#endif
+#if !defined PRIuMAX || PRI_MACROS_BROKEN
+# undef PRIuMAX
+# define PRIuMAX (sizeof (uintmax_t) == sizeof (long) ? "lu" : "llu")
+#endif
+#if !defined PRIxMAX || PRI_MACROS_BROKEN
+# undef PRIxMAX
+# define PRIxMAX (sizeof (uintmax_t) == sizeof (long) ? "lx" : "llx")
+#endif
+#if !defined PRIXMAX || PRI_MACROS_BROKEN
+# undef PRIXMAX
+# define PRIXMAX (sizeof (uintmax_t) == sizeof (long) ? "lX" : "llX")
+#endif
+#if !defined PRIdPTR || PRI_MACROS_BROKEN
+# undef PRIdPTR
+# define PRIdPTR \
+ (sizeof (void *) == sizeof (long) ? "ld" : \
+ sizeof (void *) == sizeof (int) ? "d" : \
+ "lld")
+#endif
+#if !defined PRIiPTR || PRI_MACROS_BROKEN
+# undef PRIiPTR
+# define PRIiPTR \
+ (sizeof (void *) == sizeof (long) ? "li" : \
+ sizeof (void *) == sizeof (int) ? "i" : \
+ "lli")
+#endif
+#if !defined PRIoPTR || PRI_MACROS_BROKEN
+# undef PRIoPTR
+# define PRIoPTR \
+ (sizeof (void *) == sizeof (long) ? "lo" : \
+ sizeof (void *) == sizeof (int) ? "o" : \
+ "llo")
+#endif
+#if !defined PRIuPTR || PRI_MACROS_BROKEN
+# undef PRIuPTR
+# define PRIuPTR \
+ (sizeof (void *) == sizeof (long) ? "lu" : \
+ sizeof (void *) == sizeof (int) ? "u" : \
+ "llu")
+#endif
+#if !defined PRIxPTR || PRI_MACROS_BROKEN
+# undef PRIxPTR
+# define PRIxPTR \
+ (sizeof (void *) == sizeof (long) ? "lx" : \
+ sizeof (void *) == sizeof (int) ? "x" : \
+ "llx")
+#endif
+#if !defined PRIXPTR || PRI_MACROS_BROKEN
+# undef PRIXPTR
+# define PRIXPTR \
+ (sizeof (void *) == sizeof (long) ? "lX" : \
+ sizeof (void *) == sizeof (int) ? "X" : \
+ "llX")
+#endif
+
+/* @@ 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(name, flags) open_not_cancel_2 (name, flags)
+# define close(fd) close_not_cancel_no_status (fd)
+# define read(fd, buf, n) read_not_cancel (fd, buf, n)
+# define mmap(addr, len, prot, flags, fd, offset) \
+ __mmap (addr, len, prot, flags, fd, offset)
+# define munmap(addr, len) __munmap (addr, len)
+#endif
+
+/* For those losing systems which don't have `alloca' we have to add
+ some additional code emulating it. */
+#ifdef HAVE_ALLOCA
+# define freea(p) /* nothing */
+#else
+# define alloca(n) malloc (n)
+# define freea(p) free (p)
+#endif
+
+/* For systems that distinguish between text and binary I/O.
+ O_BINARY is usually declared in <fcntl.h>. */
+#if !defined O_BINARY && defined _O_BINARY
+ /* For MSC-compatible compilers. */
+# define O_BINARY _O_BINARY
+# define O_TEXT _O_TEXT
+#endif
+#ifdef __BEOS__
+ /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */
+# undef O_BINARY
+# undef O_TEXT
+#endif
+/* On reasonable systems, binary I/O is the default. */
+#ifndef O_BINARY
+# define O_BINARY 0
+#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;
+
+
+/* Expand a system dependent string segment. Return NULL if unsupported. */
+static const char *
+get_sysdep_segment_value (const char *name)
+{
+ /* Test for an ISO C 99 section 7.8.1 format string directive.
+ Syntax:
+ P R I { d | i | o | u | x | X }
+ { { | LEAST | FAST } { 8 | 16 | 32 | 64 } | MAX | PTR } */
+ /* We don't use a table of 14 times 6 'const char *' strings here, because
+ data relocations cost startup time. */
+ if (name[0] == 'P' && name[1] == 'R' && name[2] == 'I')
+ {
+ if (name[3] == 'd' || name[3] == 'i' || name[3] == 'o' || name[3] == 'u'
+ || name[3] == 'x' || name[3] == 'X')
+ {
+ if (name[4] == '8' && name[5] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRId8;
+ if (name[3] == 'i')
+ return PRIi8;
+ if (name[3] == 'o')
+ return PRIo8;
+ if (name[3] == 'u')
+ return PRIu8;
+ if (name[3] == 'x')
+ return PRIx8;
+ if (name[3] == 'X')
+ return PRIX8;
+ abort ();
+ }
+ if (name[4] == '1' && name[5] == '6' && name[6] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRId16;
+ if (name[3] == 'i')
+ return PRIi16;
+ if (name[3] == 'o')
+ return PRIo16;
+ if (name[3] == 'u')
+ return PRIu16;
+ if (name[3] == 'x')
+ return PRIx16;
+ if (name[3] == 'X')
+ return PRIX16;
+ abort ();
+ }
+ if (name[4] == '3' && name[5] == '2' && name[6] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRId32;
+ if (name[3] == 'i')
+ return PRIi32;
+ if (name[3] == 'o')
+ return PRIo32;
+ if (name[3] == 'u')
+ return PRIu32;
+ if (name[3] == 'x')
+ return PRIx32;
+ if (name[3] == 'X')
+ return PRIX32;
+ abort ();
+ }
+ if (name[4] == '6' && name[5] == '4' && name[6] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRId64;
+ if (name[3] == 'i')
+ return PRIi64;
+ if (name[3] == 'o')
+ return PRIo64;
+ if (name[3] == 'u')
+ return PRIu64;
+ if (name[3] == 'x')
+ return PRIx64;
+ if (name[3] == 'X')
+ return PRIX64;
+ abort ();
+ }
+ if (name[4] == 'L' && name[5] == 'E' && name[6] == 'A'
+ && name[7] == 'S' && name[8] == 'T')
+ {
+ if (name[9] == '8' && name[10] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRIdLEAST8;
+ if (name[3] == 'i')
+ return PRIiLEAST8;
+ if (name[3] == 'o')
+ return PRIoLEAST8;
+ if (name[3] == 'u')
+ return PRIuLEAST8;
+ if (name[3] == 'x')
+ return PRIxLEAST8;
+ if (name[3] == 'X')
+ return PRIXLEAST8;
+ abort ();
+ }
+ if (name[9] == '1' && name[10] == '6' && name[11] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRIdLEAST16;
+ if (name[3] == 'i')
+ return PRIiLEAST16;
+ if (name[3] == 'o')
+ return PRIoLEAST16;
+ if (name[3] == 'u')
+ return PRIuLEAST16;
+ if (name[3] == 'x')
+ return PRIxLEAST16;
+ if (name[3] == 'X')
+ return PRIXLEAST16;
+ abort ();
+ }
+ if (name[9] == '3' && name[10] == '2' && name[11] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRIdLEAST32;
+ if (name[3] == 'i')
+ return PRIiLEAST32;
+ if (name[3] == 'o')
+ return PRIoLEAST32;
+ if (name[3] == 'u')
+ return PRIuLEAST32;
+ if (name[3] == 'x')
+ return PRIxLEAST32;
+ if (name[3] == 'X')
+ return PRIXLEAST32;
+ abort ();
+ }
+ if (name[9] == '6' && name[10] == '4' && name[11] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRIdLEAST64;
+ if (name[3] == 'i')
+ return PRIiLEAST64;
+ if (name[3] == 'o')
+ return PRIoLEAST64;
+ if (name[3] == 'u')
+ return PRIuLEAST64;
+ if (name[3] == 'x')
+ return PRIxLEAST64;
+ if (name[3] == 'X')
+ return PRIXLEAST64;
+ abort ();
+ }
+ }
+ if (name[4] == 'F' && name[5] == 'A' && name[6] == 'S'
+ && name[7] == 'T')
+ {
+ if (name[8] == '8' && name[9] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRIdFAST8;
+ if (name[3] == 'i')
+ return PRIiFAST8;
+ if (name[3] == 'o')
+ return PRIoFAST8;
+ if (name[3] == 'u')
+ return PRIuFAST8;
+ if (name[3] == 'x')
+ return PRIxFAST8;
+ if (name[3] == 'X')
+ return PRIXFAST8;
+ abort ();
+ }
+ if (name[8] == '1' && name[9] == '6' && name[10] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRIdFAST16;
+ if (name[3] == 'i')
+ return PRIiFAST16;
+ if (name[3] == 'o')
+ return PRIoFAST16;
+ if (name[3] == 'u')
+ return PRIuFAST16;
+ if (name[3] == 'x')
+ return PRIxFAST16;
+ if (name[3] == 'X')
+ return PRIXFAST16;
+ abort ();
+ }
+ if (name[8] == '3' && name[9] == '2' && name[10] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRIdFAST32;
+ if (name[3] == 'i')
+ return PRIiFAST32;
+ if (name[3] == 'o')
+ return PRIoFAST32;
+ if (name[3] == 'u')
+ return PRIuFAST32;
+ if (name[3] == 'x')
+ return PRIxFAST32;
+ if (name[3] == 'X')
+ return PRIXFAST32;
+ abort ();
+ }
+ if (name[8] == '6' && name[9] == '4' && name[10] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRIdFAST64;
+ if (name[3] == 'i')
+ return PRIiFAST64;
+ if (name[3] == 'o')
+ return PRIoFAST64;
+ if (name[3] == 'u')
+ return PRIuFAST64;
+ if (name[3] == 'x')
+ return PRIxFAST64;
+ if (name[3] == 'X')
+ return PRIXFAST64;
+ abort ();
+ }
+ }
+ if (name[4] == 'M' && name[5] == 'A' && name[6] == 'X'
+ && name[7] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRIdMAX;
+ if (name[3] == 'i')
+ return PRIiMAX;
+ if (name[3] == 'o')
+ return PRIoMAX;
+ if (name[3] == 'u')
+ return PRIuMAX;
+ if (name[3] == 'x')
+ return PRIxMAX;
+ if (name[3] == 'X')
+ return PRIXMAX;
+ abort ();
+ }
+ if (name[4] == 'P' && name[5] == 'T' && name[6] == 'R'
+ && name[7] == '\0')
+ {
+ if (name[3] == 'd')
+ return PRIdPTR;
+ if (name[3] == 'i')
+ return PRIiPTR;
+ if (name[3] == 'o')
+ return PRIoPTR;
+ if (name[3] == 'u')
+ return PRIuPTR;
+ if (name[3] == 'x')
+ return PRIxPTR;
+ if (name[3] == 'X')
+ return PRIXPTR;
+ abort ();
+ }
+ }
+ }
+ /* Test for a glibc specific printf() format directive flag. */
+ if (name[0] == 'I' && name[1] == '\0')
+ {
+#if defined _LIBC || __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)
+ /* The 'I' flag, in numeric format directives, replaces ASCII digits
+ with the 'outdigits' defined in the LC_CTYPE locale facet. This is
+ used for Farsi (Persian) and maybe Arabic. */
+ return "I";
+#else
+ return "";
+#endif
+ }
+ /* Other system dependent strings are not valid. */
+ return NULL;
+}
+
+/* Load the message catalogs specified by FILENAME. If it is no valid
+ message catalog do nothing. */
+void
+internal_function
+_nl_load_domain (struct loaded_l10nfile *domain_file,
+ struct binding *domainbinding)
+{
+ __libc_lock_define_initialized_recursive (static, lock)
+ int fd = -1;
+ size_t size;
+#ifdef _LIBC
+ struct stat64 st;
+#else
+ struct stat st;
+#endif
+ struct mo_file_header *data = (struct mo_file_header *) -1;
+ int use_mmap = 0;
+ struct loaded_domain *domain;
+ int revision;
+ const char *nullentry;
+ size_t nullentrylen;
+
+ __libc_lock_lock_recursive (lock);
+ if (domain_file->decided != 0)
+ {
+ /* There are two possibilities:
+
+ + this is the same thread calling again during this initialization
+ via _nl_find_msg. We have initialized everything this call needs.
+
+ + this is another thread which tried to initialize this object.
+ Not necessary anymore since if the lock is available this
+ is finished.
+ */
+ goto done;
+ }
+
+ domain_file->decided = -1;
+ domain_file->data = NULL;
+
+ /* Note that it would be useless to store domainbinding in domain_file
+ because domainbinding might be == NULL now but != NULL later (after
+ a call to bind_textdomain_codeset). */
+
+ /* 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)
+ goto out;
+
+ /* Try to open the addressed file. */
+ fd = open (domain_file->filename, O_RDONLY | O_BINARY);
+ if (fd == -1)
+ goto out;
+
+ /* We must know about the size of the file. */
+ if (
+#ifdef _LIBC
+ __builtin_expect (fstat64 (fd, &st) != 0, 0)
+#else
+ __builtin_expect (fstat (fd, &st) != 0, 0)
+#endif
+ || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
+ || __builtin_expect (size < sizeof (struct mo_file_header), 0))
+ /* Something went wrong. */
+ goto out;
+
+#ifdef HAVE_MMAP
+ /* 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 (__builtin_expect (data != (struct mo_file_header *) -1, 1))
+ {
+ /* mmap() call was successful. */
+ close (fd);
+ fd = -1;
+ 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)
+ goto out;
+
+ to_read = size;
+ read_ptr = (char *) data;
+ do
+ {
+ long int nb = (long int) read (fd, read_ptr, to_read);
+ if (nb <= 0)
+ {
+#ifdef EINTR
+ if (nb == -1 && errno == EINTR)
+ continue;
+#endif
+ goto out;
+ }
+ read_ptr += nb;
+ to_read -= nb;
+ }
+ while (to_read > 0);
+
+ close (fd);
+ fd = -1;
+ }
+
+ /* Using the magic number we can test whether it really is a message
+ catalog file. */
+ if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
+ 0))
+ {
+ /* The magic number is wrong: not a message catalog file. */
+#ifdef HAVE_MMAP
+ if (use_mmap)
+ munmap ((caddr_t) data, size);
+ else
+#endif
+ free (data);
+ goto out;
+ }
+
+ domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
+ if (domain == NULL)
+ goto out;
+ domain_file->data = domain;
+
+ domain->data = (char *) data;
+ domain->use_mmap = use_mmap;
+ domain->mmap_size = size;
+ domain->must_swap = data->magic != _MAGIC;
+ domain->malloced = NULL;
+
+ /* Fill in the information about the available tables. */
+ revision = W (domain->must_swap, data->revision);
+ /* We support only the major revisions 0 and 1. */
+ switch (revision >> 16)
+ {
+ case 0:
+ case 1:
+ domain->nstrings = W (domain->must_swap, data->nstrings);
+ domain->orig_tab = (const struct string_desc *)
+ ((char *) data + W (domain->must_swap, data->orig_tab_offset));
+ domain->trans_tab = (const 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 =
+ (domain->hash_size > 2
+ ? (const nls_uint32 *)
+ ((char *) data + W (domain->must_swap, data->hash_tab_offset))
+ : NULL);
+ domain->must_swap_hash_tab = domain->must_swap;
+
+ /* Now dispatch on the minor revision. */
+ switch (revision & 0xffff)
+ {
+ case 0:
+ domain->n_sysdep_strings = 0;
+ domain->orig_sysdep_tab = NULL;
+ domain->trans_sysdep_tab = NULL;
+ break;
+ case 1:
+ default:
+ {
+ nls_uint32 n_sysdep_strings;
+
+ if (domain->hash_tab == NULL)
+ /* This is invalid. These minor revisions need a hash table. */
+ goto invalid;
+
+ n_sysdep_strings =
+ W (domain->must_swap, data->n_sysdep_strings);
+ if (n_sysdep_strings > 0)
+ {
+ nls_uint32 n_sysdep_segments;
+ const struct sysdep_segment *sysdep_segments;
+ const char **sysdep_segment_values;
+ const nls_uint32 *orig_sysdep_tab;
+ const nls_uint32 *trans_sysdep_tab;
+ nls_uint32 n_inmem_sysdep_strings;
+ size_t memneed;
+ char *mem;
+ struct sysdep_string_desc *inmem_orig_sysdep_tab;
+ struct sysdep_string_desc *inmem_trans_sysdep_tab;
+ nls_uint32 *inmem_hash_tab;
+ unsigned int i, j;
+
+ /* Get the values of the system dependent segments. */
+ n_sysdep_segments =
+ W (domain->must_swap, data->n_sysdep_segments);
+ sysdep_segments = (const struct sysdep_segment *)
+ ((char *) data
+ + W (domain->must_swap, data->sysdep_segments_offset));
+ sysdep_segment_values =
+ alloca (n_sysdep_segments * sizeof (const char *));
+ for (i = 0; i < n_sysdep_segments; i++)
+ {
+ const char *name =
+ (char *) data
+ + W (domain->must_swap, sysdep_segments[i].offset);
+ nls_uint32 namelen =
+ W (domain->must_swap, sysdep_segments[i].length);
+
+ if (!(namelen > 0 && name[namelen - 1] == '\0'))
+ {
+ freea (sysdep_segment_values);
+ goto invalid;
+ }
+
+ sysdep_segment_values[i] = get_sysdep_segment_value (name);
+ }
+
+ orig_sysdep_tab = (const nls_uint32 *)
+ ((char *) data
+ + W (domain->must_swap, data->orig_sysdep_tab_offset));
+ trans_sysdep_tab = (const nls_uint32 *)
+ ((char *) data
+ + W (domain->must_swap, data->trans_sysdep_tab_offset));
+
+ /* Compute the amount of additional memory needed for the
+ system dependent strings and the augmented hash table.
+ At the same time, also drop string pairs which refer to
+ an undefined system dependent segment. */
+ n_inmem_sysdep_strings = 0;
+ memneed = domain->hash_size * sizeof (nls_uint32);
+ for (i = 0; i < n_sysdep_strings; i++)
+ {
+ int valid = 1;
+ size_t needs[2];
+
+ for (j = 0; j < 2; j++)
+ {
+ const struct sysdep_string *sysdep_string =
+ (const struct sysdep_string *)
+ ((char *) data
+ + W (domain->must_swap,
+ j == 0
+ ? orig_sysdep_tab[i]
+ : trans_sysdep_tab[i]));
+ size_t need = 0;
+ const struct segment_pair *p = sysdep_string->segments;
+
+ if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END)
+ for (p = sysdep_string->segments;; p++)
+ {
+ nls_uint32 sysdepref;
+
+ need += W (domain->must_swap, p->segsize);
+
+ sysdepref = W (domain->must_swap, p->sysdepref);
+ if (sysdepref == SEGMENTS_END)
+ break;
+
+ if (sysdepref >= n_sysdep_segments)
+ {
+ /* Invalid. */
+ freea (sysdep_segment_values);
+ goto invalid;
+ }
+
+ if (sysdep_segment_values[sysdepref] == NULL)
+ {
+ /* This particular string pair is invalid. */
+ valid = 0;
+ break;
+ }
+
+ need += strlen (sysdep_segment_values[sysdepref]);
+ }
+
+ needs[j] = need;
+ if (!valid)
+ break;
+ }
+
+ if (valid)
+ {
+ n_inmem_sysdep_strings++;
+ memneed += needs[0] + needs[1];
+ }
+ }
+ memneed += 2 * n_inmem_sysdep_strings
+ * sizeof (struct sysdep_string_desc);
+
+ if (n_inmem_sysdep_strings > 0)
+ {
+ unsigned int k;
+
+ /* Allocate additional memory. */
+ mem = (char *) malloc (memneed);
+ if (mem == NULL)
+ goto invalid;
+
+ domain->malloced = mem;
+ inmem_orig_sysdep_tab = (struct sysdep_string_desc *) mem;
+ mem += n_inmem_sysdep_strings
+ * sizeof (struct sysdep_string_desc);
+ inmem_trans_sysdep_tab = (struct sysdep_string_desc *) mem;
+ mem += n_inmem_sysdep_strings
+ * sizeof (struct sysdep_string_desc);
+ inmem_hash_tab = (nls_uint32 *) mem;
+ mem += domain->hash_size * sizeof (nls_uint32);
+
+ /* Compute the system dependent strings. */
+ k = 0;
+ for (i = 0; i < n_sysdep_strings; i++)
+ {
+ int valid = 1;
+
+ for (j = 0; j < 2; j++)
+ {
+ const struct sysdep_string *sysdep_string =
+ (const struct sysdep_string *)
+ ((char *) data
+ + W (domain->must_swap,
+ j == 0
+ ? orig_sysdep_tab[i]
+ : trans_sysdep_tab[i]));
+ const struct segment_pair *p =
+ sysdep_string->segments;
+
+ if (W (domain->must_swap, p->sysdepref)
+ != SEGMENTS_END)
+ for (p = sysdep_string->segments;; p++)
+ {
+ nls_uint32 sysdepref;
+
+ sysdepref =
+ W (domain->must_swap, p->sysdepref);
+ if (sysdepref == SEGMENTS_END)
+ break;
+
+ if (sysdep_segment_values[sysdepref] == NULL)
+ {
+ /* This particular string pair is
+ invalid. */
+ valid = 0;
+ break;
+ }
+ }
+
+ if (!valid)
+ break;
+ }
+
+ if (valid)
+ {
+ for (j = 0; j < 2; j++)
+ {
+ const struct sysdep_string *sysdep_string =
+ (const struct sysdep_string *)
+ ((char *) data
+ + W (domain->must_swap,
+ j == 0
+ ? orig_sysdep_tab[i]
+ : trans_sysdep_tab[i]));
+ const char *static_segments =
+ (char *) data
+ + W (domain->must_swap, sysdep_string->offset);
+ const struct segment_pair *p =
+ sysdep_string->segments;
+
+ /* Concatenate the segments, and fill
+ inmem_orig_sysdep_tab[k] (for j == 0) and
+ inmem_trans_sysdep_tab[k] (for j == 1). */
+
+ struct sysdep_string_desc *inmem_tab_entry =
+ (j == 0
+ ? inmem_orig_sysdep_tab
+ : inmem_trans_sysdep_tab)
+ + k;
+
+ if (W (domain->must_swap, p->sysdepref)
+ == SEGMENTS_END)
+ {
+ /* Only one static segment. */
+ inmem_tab_entry->length =
+ W (domain->must_swap, p->segsize);
+ inmem_tab_entry->pointer = static_segments;
+ }
+ else
+ {
+ inmem_tab_entry->pointer = mem;
+
+ for (p = sysdep_string->segments;; p++)
+ {
+ nls_uint32 segsize =
+ W (domain->must_swap, p->segsize);
+ nls_uint32 sysdepref =
+ W (domain->must_swap, p->sysdepref);
+ size_t n;
+
+ if (segsize > 0)
+ {
+ memcpy (mem, static_segments, segsize);
+ mem += segsize;
+ static_segments += segsize;
+ }
+
+ if (sysdepref == SEGMENTS_END)
+ break;
+
+ n = strlen (sysdep_segment_values[sysdepref]);
+ memcpy (mem, sysdep_segment_values[sysdepref], n);
+ mem += n;
+ }
+
+ inmem_tab_entry->length =
+ mem - inmem_tab_entry->pointer;
+ }
+ }
+
+ k++;
+ }
+ }
+ if (k != n_inmem_sysdep_strings)
+ abort ();
+
+ /* Compute the augmented hash table. */
+ for (i = 0; i < domain->hash_size; i++)
+ inmem_hash_tab[i] =
+ W (domain->must_swap_hash_tab, domain->hash_tab[i]);
+ for (i = 0; i < n_inmem_sysdep_strings; i++)
+ {
+ const char *msgid = inmem_orig_sysdep_tab[i].pointer;
+ 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));
+
+ for (;;)
+ {
+ if (inmem_hash_tab[idx] == 0)
+ {
+ /* Hash table entry is empty. Use it. */
+ inmem_hash_tab[idx] = 1 + domain->nstrings + i;
+ break;
+ }
+
+ if (idx >= domain->hash_size - incr)
+ idx -= domain->hash_size - incr;
+ else
+ idx += incr;
+ }
+ }
+
+ domain->n_sysdep_strings = n_inmem_sysdep_strings;
+ domain->orig_sysdep_tab = inmem_orig_sysdep_tab;
+ domain->trans_sysdep_tab = inmem_trans_sysdep_tab;
+
+ domain->hash_tab = inmem_hash_tab;
+ domain->must_swap_hash_tab = 0;
+ }
+ else
+ {
+ domain->n_sysdep_strings = 0;
+ domain->orig_sysdep_tab = NULL;
+ domain->trans_sysdep_tab = NULL;
+ }
+
+ freea (sysdep_segment_values);
+ }
+ else
+ {
+ domain->n_sysdep_strings = 0;
+ domain->orig_sysdep_tab = NULL;
+ domain->trans_sysdep_tab = NULL;
+ }
+ }
+ break;
+ }
+ break;
+ default:
+ /* This is an invalid revision. */
+ invalid:
+ /* This is an invalid .mo file. */
+ if (domain->malloced)
+ free (domain->malloced);
+#ifdef HAVE_MMAP
+ if (use_mmap)
+ munmap ((caddr_t) data, size);
+ else
+#endif
+ free (data);
+ free (domain);
+ domain_file->data = NULL;
+ goto out;
+ }
+
+ /* No caches of converted translations so far. */
+ domain->conversions = NULL;
+ domain->nconversions = 0;
+
+ /* Get the header entry and look for a plural specification. */
+#ifdef IN_LIBGLOCALE
+ nullentry =
+ _nl_find_msg (domain_file, domainbinding, NULL, "", &nullentrylen);
+#else
+ nullentry = _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
+#endif
+ EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
+
+ out:
+ if (fd != -1)
+ close (fd);
+
+ domain_file->decided = 1;
+
+ done:
+ __libc_lock_unlock_recursive (lock);
+}
+
+
+#ifdef _LIBC
+void
+internal_function __libc_freeres_fn_section
+_nl_unload_domain (struct loaded_domain *domain)
+{
+ size_t i;
+
+ if (domain->plural != &__gettext_germanic_plural)
+ __gettext_free_exp (domain->plural);
+
+ for (i = 0; i < domain->nconversions; i++)
+ {
+ struct converted_domain *convd = &domain->conversions[i];
+
+ free (convd->encoding);
+ if (convd->conv_tab != NULL && convd->conv_tab != (char **) -1)
+ free (convd->conv_tab);
+ if (convd->conv != (__gconv_t) -1)
+ __gconv_close (convd->conv);
+ }
+ if (domain->conversions != NULL)
+ free (domain->conversions);
+
+ if (domain->malloced)
+ free (domain->malloced);
+
+# ifdef _POSIX_MAPPED_FILES
+ if (domain->use_mmap)
+ munmap ((caddr_t) domain->data, domain->mmap_size);
+ else
+# endif /* _POSIX_MAPPED_FILES */
+ free ((void *) domain->data);
+
+ free (domain);
+}
+#endif
diff --git a/intl/localcharset.c b/intl/localcharset.c
new file mode 100644
index 000000000..e796ae71c
--- /dev/null
+++ b/intl/localcharset.c
@@ -0,0 +1,461 @@
+/* Determine a canonical name for the current locale's character encoding.
+
+ Copyright (C) 2000-2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Written by Bruno Haible <bruno@clisp.org>. */
+
+#include <config.h>
+
+/* Specification. */
+#include "localcharset.h"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined _WIN32 || defined __WIN32__
+# define WIN32_NATIVE
+#endif
+
+#if defined __EMX__
+/* Assume EMX program runs on OS/2, even if compiled under DOS. */
+# define OS2
+#endif
+
+#if !defined WIN32_NATIVE
+# if HAVE_LANGINFO_CODESET
+# include <langinfo.h>
+# else
+# if 0 /* see comment below */
+# include <locale.h>
+# endif
+# endif
+# ifdef __CYGWIN__
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# endif
+#elif defined WIN32_NATIVE
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+#if defined OS2
+# define INCL_DOS
+# include <os2.h>
+#endif
+
+#if ENABLE_RELOCATABLE
+# include "relocatable.h"
+#else
+# define relocate(pathname) (pathname)
+#endif
+
+/* Get LIBDIR. */
+#ifndef LIBDIR
+# include "configmake.h"
+#endif
+
+#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
+ /* Win32, Cygwin, OS/2, DOS */
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+#endif
+
+#ifndef DIRECTORY_SEPARATOR
+# define DIRECTORY_SEPARATOR '/'
+#endif
+
+#ifndef ISSLASH
+# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
+#endif
+
+#if HAVE_DECL_GETC_UNLOCKED
+# undef getc
+# define getc getc_unlocked
+#endif
+
+/* The following static variable is declared 'volatile' to avoid a
+ possible multithread problem in the function get_charset_aliases. If we
+ are running in a threaded environment, and if two threads initialize
+ 'charset_aliases' simultaneously, both will produce the same value,
+ and everything will be ok if the two assignments to 'charset_aliases'
+ are atomic. But I don't know what will happen if the two assignments mix. */
+#if __STDC__ != 1
+# define volatile /* empty */
+#endif
+/* Pointer to the contents of the charset.alias file, if it has already been
+ read, else NULL. Its format is:
+ ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0' */
+static const char * volatile charset_aliases;
+
+/* Return a pointer to the contents of the charset.alias file. */
+static const char *
+get_charset_aliases (void)
+{
+ const char *cp;
+
+ cp = charset_aliases;
+ if (cp == NULL)
+ {
+#if !(defined VMS || defined WIN32_NATIVE || defined __CYGWIN__)
+ FILE *fp;
+ const char *dir;
+ const char *base = "charset.alias";
+ char *file_name;
+
+ /* Make it possible to override the charset.alias location. This is
+ necessary for running the testsuite before "make install". */
+ dir = getenv ("CHARSETALIASDIR");
+ if (dir == NULL || dir[0] == '\0')
+ dir = relocate (LIBDIR);
+
+ /* Concatenate dir and base into freshly allocated file_name. */
+ {
+ size_t dir_len = strlen (dir);
+ size_t base_len = strlen (base);
+ int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1]));
+ file_name = (char *) malloc (dir_len + add_slash + base_len + 1);
+ if (file_name != NULL)
+ {
+ memcpy (file_name, dir, dir_len);
+ if (add_slash)
+ file_name[dir_len] = DIRECTORY_SEPARATOR;
+ memcpy (file_name + dir_len + add_slash, base, base_len + 1);
+ }
+ }
+
+ if (file_name == NULL || (fp = fopen (file_name, "r")) == NULL)
+ /* Out of memory or file not found, treat it as empty. */
+ cp = "";
+ else
+ {
+ /* Parse the file's contents. */
+ char *res_ptr = NULL;
+ size_t res_size = 0;
+
+ for (;;)
+ {
+ int c;
+ char buf1[50+1];
+ char buf2[50+1];
+ size_t l1, l2;
+ char *old_res_ptr;
+
+ c = getc (fp);
+ if (c == EOF)
+ break;
+ if (c == '\n' || c == ' ' || c == '\t')
+ continue;
+ if (c == '#')
+ {
+ /* Skip comment, to end of line. */
+ do
+ c = getc (fp);
+ while (!(c == EOF || c == '\n'));
+ if (c == EOF)
+ break;
+ continue;
+ }
+ ungetc (c, fp);
+ if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
+ break;
+ l1 = strlen (buf1);
+ l2 = strlen (buf2);
+ old_res_ptr = res_ptr;
+ if (res_size == 0)
+ {
+ res_size = l1 + 1 + l2 + 1;
+ res_ptr = (char *) malloc (res_size + 1);
+ }
+ else
+ {
+ res_size += l1 + 1 + l2 + 1;
+ res_ptr = (char *) realloc (res_ptr, res_size + 1);
+ }
+ if (res_ptr == NULL)
+ {
+ /* Out of memory. */
+ res_size = 0;
+ if (old_res_ptr != NULL)
+ free (old_res_ptr);
+ break;
+ }
+ strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
+ strcpy (res_ptr + res_size - (l2 + 1), buf2);
+ }
+ fclose (fp);
+ if (res_size == 0)
+ cp = "";
+ else
+ {
+ *(res_ptr + res_size) = '\0';
+ cp = res_ptr;
+ }
+ }
+
+ if (file_name != NULL)
+ free (file_name);
+
+#else
+
+# if defined VMS
+ /* To avoid the troubles of an extra file charset.alias_vms in the
+ sources of many GNU packages, simply inline the aliases here. */
+ /* The list of encodings is taken from the OpenVMS 7.3-1 documentation
+ "Compaq C Run-Time Library Reference Manual for OpenVMS systems"
+ section 10.7 "Handling Different Character Sets". */
+ cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
+ "ISO8859-2" "\0" "ISO-8859-2" "\0"
+ "ISO8859-5" "\0" "ISO-8859-5" "\0"
+ "ISO8859-7" "\0" "ISO-8859-7" "\0"
+ "ISO8859-8" "\0" "ISO-8859-8" "\0"
+ "ISO8859-9" "\0" "ISO-8859-9" "\0"
+ /* Japanese */
+ "eucJP" "\0" "EUC-JP" "\0"
+ "SJIS" "\0" "SHIFT_JIS" "\0"
+ "DECKANJI" "\0" "DEC-KANJI" "\0"
+ "SDECKANJI" "\0" "EUC-JP" "\0"
+ /* Chinese */
+ "eucTW" "\0" "EUC-TW" "\0"
+ "DECHANYU" "\0" "DEC-HANYU" "\0"
+ "DECHANZI" "\0" "GB2312" "\0"
+ /* Korean */
+ "DECKOREAN" "\0" "EUC-KR" "\0";
+# endif
+
+# if defined WIN32_NATIVE || defined __CYGWIN__
+ /* To avoid the troubles of installing a separate file in the same
+ directory as the DLL and of retrieving the DLL's directory at
+ runtime, simply inline the aliases here. */
+
+ cp = "CP936" "\0" "GBK" "\0"
+ "CP1361" "\0" "JOHAB" "\0"
+ "CP20127" "\0" "ASCII" "\0"
+ "CP20866" "\0" "KOI8-R" "\0"
+ "CP20936" "\0" "GB2312" "\0"
+ "CP21866" "\0" "KOI8-RU" "\0"
+ "CP28591" "\0" "ISO-8859-1" "\0"
+ "CP28592" "\0" "ISO-8859-2" "\0"
+ "CP28593" "\0" "ISO-8859-3" "\0"
+ "CP28594" "\0" "ISO-8859-4" "\0"
+ "CP28595" "\0" "ISO-8859-5" "\0"
+ "CP28596" "\0" "ISO-8859-6" "\0"
+ "CP28597" "\0" "ISO-8859-7" "\0"
+ "CP28598" "\0" "ISO-8859-8" "\0"
+ "CP28599" "\0" "ISO-8859-9" "\0"
+ "CP28605" "\0" "ISO-8859-15" "\0"
+ "CP38598" "\0" "ISO-8859-8" "\0"
+ "CP51932" "\0" "EUC-JP" "\0"
+ "CP51936" "\0" "GB2312" "\0"
+ "CP51949" "\0" "EUC-KR" "\0"
+ "CP51950" "\0" "EUC-TW" "\0"
+ "CP54936" "\0" "GB18030" "\0"
+ "CP65001" "\0" "UTF-8" "\0";
+# endif
+#endif
+
+ charset_aliases = cp;
+ }
+
+ return cp;
+}
+
+/* Determine the current locale's character encoding, and canonicalize it
+ into one of the canonical names listed in config.charset.
+ The result must not be freed; it is statically allocated.
+ If the canonical name cannot be determined, the result is a non-canonical
+ name. */
+
+#ifdef STATIC
+STATIC
+#endif
+const char *
+locale_charset (void)
+{
+ const char *codeset;
+ const char *aliases;
+
+#if !(defined WIN32_NATIVE || defined OS2)
+
+# if HAVE_LANGINFO_CODESET
+
+ /* Most systems support nl_langinfo (CODESET) nowadays. */
+ codeset = nl_langinfo (CODESET);
+
+# ifdef __CYGWIN__
+ /* Cygwin 2006 does not have locales. nl_langinfo (CODESET) always
+ returns "US-ASCII". As long as this is not fixed, return the suffix
+ of the locale name from the environment variables (if present) or
+ the codepage as a number. */
+ if (codeset != NULL && strcmp (codeset, "US-ASCII") == 0)
+ {
+ const char *locale;
+ static char buf[2 + 10 + 1];
+
+ locale = getenv ("LC_ALL");
+ if (locale == NULL || locale[0] == '\0')
+ {
+ locale = getenv ("LC_CTYPE");
+ if (locale == NULL || locale[0] == '\0')
+ locale = getenv ("LANG");
+ }
+ if (locale != NULL && locale[0] != '\0')
+ {
+ /* If the locale name contains an encoding after the dot, return
+ it. */
+ const char *dot = strchr (locale, '.');
+
+ if (dot != NULL)
+ {
+ const char *modifier;
+
+ dot++;
+ /* Look for the possible @... trailer and remove it, if any. */
+ modifier = strchr (dot, '@');
+ if (modifier == NULL)
+ return dot;
+ if (modifier - dot < sizeof (buf))
+ {
+ memcpy (buf, dot, modifier - dot);
+ buf [modifier - dot] = '\0';
+ return buf;
+ }
+ }
+ }
+
+ /* Woe32 has a function returning the locale's codepage as a number. */
+ sprintf (buf, "CP%u", GetACP ());
+ codeset = buf;
+ }
+# endif
+
+# else
+
+ /* On old systems which lack it, use setlocale or getenv. */
+ const char *locale = NULL;
+
+ /* But most old systems don't have a complete set of locales. Some
+ (like SunOS 4 or DJGPP) have only the C locale. Therefore we don't
+ use setlocale here; it would return "C" when it doesn't support the
+ locale name the user has set. */
+# if 0
+ locale = setlocale (LC_CTYPE, NULL);
+# endif
+ if (locale == NULL || locale[0] == '\0')
+ {
+ locale = getenv ("LC_ALL");
+ if (locale == NULL || locale[0] == '\0')
+ {
+ locale = getenv ("LC_CTYPE");
+ if (locale == NULL || locale[0] == '\0')
+ locale = getenv ("LANG");
+ }
+ }
+
+ /* On some old systems, one used to set locale = "iso8859_1". On others,
+ you set it to "language_COUNTRY.charset". In any case, we resolve it
+ through the charset.alias file. */
+ codeset = locale;
+
+# endif
+
+#elif defined WIN32_NATIVE
+
+ static char buf[2 + 10 + 1];
+
+ /* Woe32 has a function returning the locale's codepage as a number. */
+ sprintf (buf, "CP%u", GetACP ());
+ codeset = buf;
+
+#elif defined OS2
+
+ const char *locale;
+ static char buf[2 + 10 + 1];
+ ULONG cp[3];
+ ULONG cplen;
+
+ /* Allow user to override the codeset, as set in the operating system,
+ with standard language environment variables. */
+ locale = getenv ("LC_ALL");
+ if (locale == NULL || locale[0] == '\0')
+ {
+ locale = getenv ("LC_CTYPE");
+ if (locale == NULL || locale[0] == '\0')
+ locale = getenv ("LANG");
+ }
+ if (locale != NULL && locale[0] != '\0')
+ {
+ /* If the locale name contains an encoding after the dot, return it. */
+ const char *dot = strchr (locale, '.');
+
+ if (dot != NULL)
+ {
+ const char *modifier;
+
+ dot++;
+ /* Look for the possible @... trailer and remove it, if any. */
+ modifier = strchr (dot, '@');
+ if (modifier == NULL)
+ return dot;
+ if (modifier - dot < sizeof (buf))
+ {
+ memcpy (buf, dot, modifier - dot);
+ buf [modifier - dot] = '\0';
+ return buf;
+ }
+ }
+
+ /* Resolve through the charset.alias file. */
+ codeset = locale;
+ }
+ else
+ {
+ /* OS/2 has a function returning the locale's codepage as a number. */
+ if (DosQueryCp (sizeof (cp), cp, &cplen))
+ codeset = "";
+ else
+ {
+ sprintf (buf, "CP%u", cp[0]);
+ codeset = buf;
+ }
+ }
+
+#endif
+
+ if (codeset == NULL)
+ /* The canonical name cannot be determined. */
+ codeset = "";
+
+ /* Resolve alias. */
+ for (aliases = get_charset_aliases ();
+ *aliases != '\0';
+ aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
+ if (strcmp (codeset, aliases) == 0
+ || (aliases[0] == '*' && aliases[1] == '\0'))
+ {
+ codeset = aliases + strlen (aliases) + 1;
+ break;
+ }
+
+ /* Don't return an empty string. GNU libc and GNU libiconv interpret
+ the empty string as denoting "the locale's character encoding",
+ thus GNU libiconv would call this function a second time. */
+ if (codeset[0] == '\0')
+ codeset = "ASCII";
+
+ return codeset;
+}
diff --git a/intl/localcharset.h b/intl/localcharset.h
new file mode 100644
index 000000000..129e4a4a3
--- /dev/null
+++ b/intl/localcharset.h
@@ -0,0 +1,42 @@
+/* Determine a canonical name for the current locale's character encoding.
+ Copyright (C) 2000-2003 Free Software Foundation, Inc.
+ This file is part of the GNU CHARSET Library.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _LOCALCHARSET_H
+#define _LOCALCHARSET_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Determine the current locale's character encoding, and canonicalize it
+ into one of the canonical names listed in config.charset.
+ The result must not be freed; it is statically allocated.
+ If the canonical name cannot be determined, the result is a non-canonical
+ name. */
+extern const char * locale_charset (void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _LOCALCHARSET_H */
diff --git a/intl/localealias.c b/intl/localealias.c
new file mode 100644
index 000000000..26122a011
--- /dev/null
+++ b/intl/localealias.c
@@ -0,0 +1,437 @@
+/* Handle aliases for locale names.
+ Copyright (C) 1995-1999, 2000-2001, 2003, 2005 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Tell glibc's <string.h> to provide a prototype for mempcpy().
+ This must come before <config.h> because <config.h> may include
+ <features.h>, and once <features.h> has been included, it's too late. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#if defined _LIBC || defined HAVE___FSETLOCKING
+# include <stdio_ext.h>
+#endif
+#include <sys/types.h>
+
+#ifdef __GNUC__
+# undef alloca
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+#else
+# ifdef _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# 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
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gettextP.h"
+
+#if ENABLE_RELOCATABLE
+# include "relocatable.h"
+#else
+# define relocate(pathname) (pathname)
+#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. */
+# define strcasecmp __strcasecmp
+
+# ifndef mempcpy
+# define mempcpy __mempcpy
+# endif
+# define HAVE_MEMPCPY 1
+# define HAVE___FSETLOCKING 1
+#endif
+
+/* Handle multi-threaded applications. */
+#ifdef _LIBC
+# include <bits/libc-lock.h>
+#else
+# include "lock.h"
+#endif
+
+#ifndef internal_function
+# define internal_function
+#endif
+
+/* Some optimizations for glibc. */
+#ifdef _LIBC
+# define FEOF(fp) feof_unlocked (fp)
+# define FGETS(buf, n, fp) fgets_unlocked (buf, n, fp)
+#else
+# define FEOF(fp) feof (fp)
+# define FGETS(buf, n, fp) fgets (buf, n, fp)
+#endif
+
+/* For those losing systems which don't have `alloca' we have to add
+ some additional code emulating it. */
+#ifdef HAVE_ALLOCA
+# define freea(p) /* nothing */
+#else
+# define alloca(n) malloc (n)
+# define freea(p) free (p)
+#endif
+
+#if defined _LIBC_REENTRANT || HAVE_DECL_FGETS_UNLOCKED
+# undef fgets
+# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
+#endif
+#if defined _LIBC_REENTRANT || HAVE_DECL_FEOF_UNLOCKED
+# undef feof
+# define feof(s) feof_unlocked (s)
+#endif
+
+
+__libc_lock_define_initialized (static, lock)
+
+
+struct alias_map
+{
+ const char *alias;
+ const char *value;
+};
+
+
+#ifndef _LIBC
+# define libc_freeres_ptr(decl) decl
+#endif
+
+libc_freeres_ptr (static char *string_space);
+static size_t string_space_act;
+static size_t string_space_max;
+libc_freeres_ptr (static struct alias_map *map);
+static size_t nmap;
+static size_t maxmap;
+
+
+/* Prototypes for local functions. */
+static size_t read_alias_file (const char *fname, int fname_len)
+ internal_function;
+static int extend_alias_table (void);
+static int alias_compare (const struct alias_map *map1,
+ const struct alias_map *map2);
+
+
+const char *
+_nl_expand_alias (const char *name)
+{
+ static const char *locale_alias_path;
+ struct alias_map *retval;
+ const char *result = NULL;
+ size_t added;
+
+ __libc_lock_lock (lock);
+
+ if (locale_alias_path == NULL)
+ locale_alias_path = LOCALE_ALIAS_PATH;
+
+ do
+ {
+ struct alias_map item;
+
+ item.alias = name;
+
+ if (nmap > 0)
+ retval = (struct alias_map *) bsearch (&item, map, nmap,
+ sizeof (struct alias_map),
+ (int (*) (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] == PATH_SEPARATOR)
+ ++locale_alias_path;
+ start = locale_alias_path;
+
+ while (locale_alias_path[0] != '\0'
+ && locale_alias_path[0] != PATH_SEPARATOR)
+ ++locale_alias_path;
+
+ if (start < locale_alias_path)
+ added = read_alias_file (start, locale_alias_path - start);
+ }
+ }
+ while (added != 0);
+
+ __libc_lock_unlock (lock);
+
+ return result;
+}
+
+
+static size_t
+internal_function
+read_alias_file (const char *fname, int fname_len)
+{
+ FILE *fp;
+ char *full_fname;
+ size_t added;
+ static const char aliasfile[] = "/locale.alias";
+
+ full_fname = (char *) alloca (fname_len + sizeof aliasfile);
+#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
+
+#ifdef _LIBC
+ /* Note the file is opened with cancellation in the I/O functions
+ disabled. */
+ fp = fopen (relocate (full_fname), "rc");
+#else
+ fp = fopen (relocate (full_fname), "r");
+#endif
+ freea (full_fname);
+ if (fp == NULL)
+ return 0;
+
+#ifdef HAVE___FSETLOCKING
+ /* No threads present. */
+ __fsetlocking (fp, FSETLOCKING_BYCALLER);
+#endif
+
+ 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
+ We avoid a multi-kilobyte buffer here since this would use up
+ stack space which we might not have if the program ran out of
+ memory. */
+ char buf[400];
+ char *alias;
+ char *value;
+ char *cp;
+ int complete_line;
+
+ if (FGETS (buf, sizeof buf, fp) == NULL)
+ /* EOF reached. */
+ break;
+
+ /* Determine whether the line is complete. */
+ complete_line = strchr (buf, '\n') != NULL;
+
+ cp = buf;
+ /* Ignore leading white space. */
+ while (isspace ((unsigned char) cp[0]))
+ ++cp;
+
+ /* A leading '#' signals a comment line. */
+ if (cp[0] != '\0' && cp[0] != '#')
+ {
+ alias = cp++;
+ while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
+ ++cp;
+ /* Terminate alias name. */
+ if (cp[0] != '\0')
+ *cp++ = '\0';
+
+ /* Now look for the beginning of the value. */
+ while (isspace ((unsigned char) cp[0]))
+ ++cp;
+
+ if (cp[0] != '\0')
+ {
+ value = cp++;
+ while (cp[0] != '\0' && !isspace ((unsigned char) 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';
+
+#ifdef IN_LIBGLOCALE
+ /* glibc's locale.alias contains entries for ja_JP and ko_KR
+ that make it impossible to use a Japanese or Korean UTF-8
+ locale under the name "ja_JP" or "ko_KR". Ignore these
+ entries. */
+ if (strchr (alias, '_') == NULL)
+#endif
+ {
+ size_t alias_len;
+ size_t value_len;
+
+ if (nmap >= maxmap)
+ if (__builtin_expect (extend_alias_table (), 0))
+ goto out;
+
+ 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)
+ goto out;
+
+ if (__builtin_expect (string_space != new_pool, 0))
+ {
+ size_t i;
+
+ for (i = 0; i < nmap; i++)
+ {
+ map[i].alias += new_pool - string_space;
+ map[i].value += new_pool - string_space;
+ }
+ }
+
+ 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;
+ }
+ }
+ }
+
+ /* Possibly not the whole line fits into the buffer. Ignore
+ the rest of the line. */
+ if (! complete_line)
+ do
+ if (FGETS (buf, sizeof buf, fp) == NULL)
+ /* Make sure the inner loop will be left. The outer loop
+ will exit at the `feof' test. */
+ break;
+ while (strchr (buf, '\n') == NULL);
+ }
+
+ out:
+ /* 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 (*) (const void *, const void *)) alias_compare);
+
+ return added;
+}
+
+
+static int
+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 -1;
+
+ map = new_map;
+ maxmap = new_size;
+ return 0;
+}
+
+
+static int
+alias_compare (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/localename.c b/intl/localename.c
new file mode 100644
index 000000000..e1b4615a0
--- /dev/null
+++ b/intl/localename.c
@@ -0,0 +1,1499 @@
+/* Determine the current selected locale.
+ Copyright (C) 1995-1999, 2000-2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Written by Ulrich Drepper <drepper@gnu.org>, 1995. */
+/* Win32 code written by Tor Lillqvist <tml@iki.fi>. */
+/* MacOS X code written by Bruno Haible <bruno@clisp.org>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <locale.h>
+
+#if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
+# include <string.h>
+# include <CoreFoundation/CFString.h>
+# if HAVE_CFLOCALECOPYCURRENT
+# include <CoreFoundation/CFLocale.h>
+# elif HAVE_CFPREFERENCESCOPYAPPVALUE
+# include <CoreFoundation/CFPreferences.h>
+# endif
+#endif
+
+#if defined _WIN32 || defined __WIN32__
+# define WIN32_NATIVE
+#endif
+
+#ifdef WIN32_NATIVE
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+/* List of language codes, sorted by value:
+ 0x01 LANG_ARABIC
+ 0x02 LANG_BULGARIAN
+ 0x03 LANG_CATALAN
+ 0x04 LANG_CHINESE
+ 0x05 LANG_CZECH
+ 0x06 LANG_DANISH
+ 0x07 LANG_GERMAN
+ 0x08 LANG_GREEK
+ 0x09 LANG_ENGLISH
+ 0x0a LANG_SPANISH
+ 0x0b LANG_FINNISH
+ 0x0c LANG_FRENCH
+ 0x0d LANG_HEBREW
+ 0x0e LANG_HUNGARIAN
+ 0x0f LANG_ICELANDIC
+ 0x10 LANG_ITALIAN
+ 0x11 LANG_JAPANESE
+ 0x12 LANG_KOREAN
+ 0x13 LANG_DUTCH
+ 0x14 LANG_NORWEGIAN
+ 0x15 LANG_POLISH
+ 0x16 LANG_PORTUGUESE
+ 0x17 LANG_RHAETO_ROMANCE
+ 0x18 LANG_ROMANIAN
+ 0x19 LANG_RUSSIAN
+ 0x1a LANG_CROATIAN == LANG_SERBIAN
+ 0x1b LANG_SLOVAK
+ 0x1c LANG_ALBANIAN
+ 0x1d LANG_SWEDISH
+ 0x1e LANG_THAI
+ 0x1f LANG_TURKISH
+ 0x20 LANG_URDU
+ 0x21 LANG_INDONESIAN
+ 0x22 LANG_UKRAINIAN
+ 0x23 LANG_BELARUSIAN
+ 0x24 LANG_SLOVENIAN
+ 0x25 LANG_ESTONIAN
+ 0x26 LANG_LATVIAN
+ 0x27 LANG_LITHUANIAN
+ 0x28 LANG_TAJIK
+ 0x29 LANG_FARSI
+ 0x2a LANG_VIETNAMESE
+ 0x2b LANG_ARMENIAN
+ 0x2c LANG_AZERI
+ 0x2d LANG_BASQUE
+ 0x2e LANG_SORBIAN
+ 0x2f LANG_MACEDONIAN
+ 0x30 LANG_SUTU
+ 0x31 LANG_TSONGA
+ 0x32 LANG_TSWANA
+ 0x33 LANG_VENDA
+ 0x34 LANG_XHOSA
+ 0x35 LANG_ZULU
+ 0x36 LANG_AFRIKAANS
+ 0x37 LANG_GEORGIAN
+ 0x38 LANG_FAEROESE
+ 0x39 LANG_HINDI
+ 0x3a LANG_MALTESE
+ 0x3b LANG_SAAMI
+ 0x3c LANG_GAELIC
+ 0x3d LANG_YIDDISH
+ 0x3e LANG_MALAY
+ 0x3f LANG_KAZAK
+ 0x40 LANG_KYRGYZ
+ 0x41 LANG_SWAHILI
+ 0x42 LANG_TURKMEN
+ 0x43 LANG_UZBEK
+ 0x44 LANG_TATAR
+ 0x45 LANG_BENGALI
+ 0x46 LANG_PUNJABI
+ 0x47 LANG_GUJARATI
+ 0x48 LANG_ORIYA
+ 0x49 LANG_TAMIL
+ 0x4a LANG_TELUGU
+ 0x4b LANG_KANNADA
+ 0x4c LANG_MALAYALAM
+ 0x4d LANG_ASSAMESE
+ 0x4e LANG_MARATHI
+ 0x4f LANG_SANSKRIT
+ 0x50 LANG_MONGOLIAN
+ 0x51 LANG_TIBETAN
+ 0x52 LANG_WELSH
+ 0x53 LANG_CAMBODIAN
+ 0x54 LANG_LAO
+ 0x55 LANG_BURMESE
+ 0x56 LANG_GALICIAN
+ 0x57 LANG_KONKANI
+ 0x58 LANG_MANIPURI
+ 0x59 LANG_SINDHI
+ 0x5a LANG_SYRIAC
+ 0x5b LANG_SINHALESE
+ 0x5c LANG_CHEROKEE
+ 0x5d LANG_INUKTITUT
+ 0x5e LANG_AMHARIC
+ 0x5f LANG_TAMAZIGHT
+ 0x60 LANG_KASHMIRI
+ 0x61 LANG_NEPALI
+ 0x62 LANG_FRISIAN
+ 0x63 LANG_PASHTO
+ 0x64 LANG_TAGALOG
+ 0x65 LANG_DIVEHI
+ 0x66 LANG_EDO
+ 0x67 LANG_FULFULDE
+ 0x68 LANG_HAUSA
+ 0x69 LANG_IBIBIO
+ 0x6a LANG_YORUBA
+ 0x70 LANG_IGBO
+ 0x71 LANG_KANURI
+ 0x72 LANG_OROMO
+ 0x73 LANG_TIGRINYA
+ 0x74 LANG_GUARANI
+ 0x75 LANG_HAWAIIAN
+ 0x76 LANG_LATIN
+ 0x77 LANG_SOMALI
+ 0x78 LANG_YI
+ 0x79 LANG_PAPIAMENTU
+*/
+/* Mingw headers don't have latest language and sublanguage codes. */
+# ifndef LANG_AFRIKAANS
+# define LANG_AFRIKAANS 0x36
+# endif
+# ifndef LANG_ALBANIAN
+# define LANG_ALBANIAN 0x1c
+# endif
+# ifndef LANG_AMHARIC
+# define LANG_AMHARIC 0x5e
+# endif
+# ifndef LANG_ARABIC
+# define LANG_ARABIC 0x01
+# endif
+# ifndef LANG_ARMENIAN
+# define LANG_ARMENIAN 0x2b
+# endif
+# ifndef LANG_ASSAMESE
+# define LANG_ASSAMESE 0x4d
+# endif
+# ifndef LANG_AZERI
+# define LANG_AZERI 0x2c
+# endif
+# ifndef LANG_BASQUE
+# define LANG_BASQUE 0x2d
+# endif
+# ifndef LANG_BELARUSIAN
+# define LANG_BELARUSIAN 0x23
+# endif
+# ifndef LANG_BENGALI
+# define LANG_BENGALI 0x45
+# endif
+# ifndef LANG_BURMESE
+# define LANG_BURMESE 0x55
+# endif
+# ifndef LANG_CAMBODIAN
+# define LANG_CAMBODIAN 0x53
+# endif
+# ifndef LANG_CATALAN
+# define LANG_CATALAN 0x03
+# endif
+# ifndef LANG_CHEROKEE
+# define LANG_CHEROKEE 0x5c
+# endif
+# ifndef LANG_DIVEHI
+# define LANG_DIVEHI 0x65
+# endif
+# ifndef LANG_EDO
+# define LANG_EDO 0x66
+# endif
+# ifndef LANG_ESTONIAN
+# define LANG_ESTONIAN 0x25
+# endif
+# ifndef LANG_FAEROESE
+# define LANG_FAEROESE 0x38
+# endif
+# ifndef LANG_FARSI
+# define LANG_FARSI 0x29
+# endif
+# ifndef LANG_FRISIAN
+# define LANG_FRISIAN 0x62
+# endif
+# ifndef LANG_FULFULDE
+# define LANG_FULFULDE 0x67
+# endif
+# ifndef LANG_GAELIC
+# define LANG_GAELIC 0x3c
+# endif
+# ifndef LANG_GALICIAN
+# define LANG_GALICIAN 0x56
+# endif
+# ifndef LANG_GEORGIAN
+# define LANG_GEORGIAN 0x37
+# endif
+# ifndef LANG_GUARANI
+# define LANG_GUARANI 0x74
+# endif
+# ifndef LANG_GUJARATI
+# define LANG_GUJARATI 0x47
+# endif
+# ifndef LANG_HAUSA
+# define LANG_HAUSA 0x68
+# endif
+# ifndef LANG_HAWAIIAN
+# define LANG_HAWAIIAN 0x75
+# endif
+# ifndef LANG_HEBREW
+# define LANG_HEBREW 0x0d
+# endif
+# ifndef LANG_HINDI
+# define LANG_HINDI 0x39
+# endif
+# ifndef LANG_IBIBIO
+# define LANG_IBIBIO 0x69
+# endif
+# ifndef LANG_IGBO
+# define LANG_IGBO 0x70
+# endif
+# ifndef LANG_INDONESIAN
+# define LANG_INDONESIAN 0x21
+# endif
+# ifndef LANG_INUKTITUT
+# define LANG_INUKTITUT 0x5d
+# endif
+# ifndef LANG_KANNADA
+# define LANG_KANNADA 0x4b
+# endif
+# ifndef LANG_KANURI
+# define LANG_KANURI 0x71
+# endif
+# ifndef LANG_KASHMIRI
+# define LANG_KASHMIRI 0x60
+# endif
+# ifndef LANG_KAZAK
+# define LANG_KAZAK 0x3f
+# endif
+# ifndef LANG_KONKANI
+# define LANG_KONKANI 0x57
+# endif
+# ifndef LANG_KYRGYZ
+# define LANG_KYRGYZ 0x40
+# endif
+# ifndef LANG_LAO
+# define LANG_LAO 0x54
+# endif
+# ifndef LANG_LATIN
+# define LANG_LATIN 0x76
+# endif
+# ifndef LANG_LATVIAN
+# define LANG_LATVIAN 0x26
+# endif
+# ifndef LANG_LITHUANIAN
+# define LANG_LITHUANIAN 0x27
+# endif
+# ifndef LANG_MACEDONIAN
+# define LANG_MACEDONIAN 0x2f
+# endif
+# ifndef LANG_MALAY
+# define LANG_MALAY 0x3e
+# endif
+# ifndef LANG_MALAYALAM
+# define LANG_MALAYALAM 0x4c
+# endif
+# ifndef LANG_MALTESE
+# define LANG_MALTESE 0x3a
+# endif
+# ifndef LANG_MANIPURI
+# define LANG_MANIPURI 0x58
+# endif
+# ifndef LANG_MARATHI
+# define LANG_MARATHI 0x4e
+# endif
+# ifndef LANG_MONGOLIAN
+# define LANG_MONGOLIAN 0x50
+# endif
+# ifndef LANG_NEPALI
+# define LANG_NEPALI 0x61
+# endif
+# ifndef LANG_ORIYA
+# define LANG_ORIYA 0x48
+# endif
+# ifndef LANG_OROMO
+# define LANG_OROMO 0x72
+# endif
+# ifndef LANG_PAPIAMENTU
+# define LANG_PAPIAMENTU 0x79
+# endif
+# ifndef LANG_PASHTO
+# define LANG_PASHTO 0x63
+# endif
+# ifndef LANG_PUNJABI
+# define LANG_PUNJABI 0x46
+# endif
+# ifndef LANG_RHAETO_ROMANCE
+# define LANG_RHAETO_ROMANCE 0x17
+# endif
+# ifndef LANG_SAAMI
+# define LANG_SAAMI 0x3b
+# endif
+# ifndef LANG_SANSKRIT
+# define LANG_SANSKRIT 0x4f
+# endif
+# ifndef LANG_SERBIAN
+# define LANG_SERBIAN 0x1a
+# endif
+# ifndef LANG_SINDHI
+# define LANG_SINDHI 0x59
+# endif
+# ifndef LANG_SINHALESE
+# define LANG_SINHALESE 0x5b
+# endif
+# ifndef LANG_SLOVAK
+# define LANG_SLOVAK 0x1b
+# endif
+# ifndef LANG_SOMALI
+# define LANG_SOMALI 0x77
+# endif
+# ifndef LANG_SORBIAN
+# define LANG_SORBIAN 0x2e
+# endif
+# ifndef LANG_SUTU
+# define LANG_SUTU 0x30
+# endif
+# ifndef LANG_SWAHILI
+# define LANG_SWAHILI 0x41
+# endif
+# ifndef LANG_SYRIAC
+# define LANG_SYRIAC 0x5a
+# endif
+# ifndef LANG_TAGALOG
+# define LANG_TAGALOG 0x64
+# endif
+# ifndef LANG_TAJIK
+# define LANG_TAJIK 0x28
+# endif
+# ifndef LANG_TAMAZIGHT
+# define LANG_TAMAZIGHT 0x5f
+# endif
+# ifndef LANG_TAMIL
+# define LANG_TAMIL 0x49
+# endif
+# ifndef LANG_TATAR
+# define LANG_TATAR 0x44
+# endif
+# ifndef LANG_TELUGU
+# define LANG_TELUGU 0x4a
+# endif
+# ifndef LANG_THAI
+# define LANG_THAI 0x1e
+# endif
+# ifndef LANG_TIBETAN
+# define LANG_TIBETAN 0x51
+# endif
+# ifndef LANG_TIGRINYA
+# define LANG_TIGRINYA 0x73
+# endif
+# ifndef LANG_TSONGA
+# define LANG_TSONGA 0x31
+# endif
+# ifndef LANG_TSWANA
+# define LANG_TSWANA 0x32
+# endif
+# ifndef LANG_TURKMEN
+# define LANG_TURKMEN 0x42
+# endif
+# ifndef LANG_UKRAINIAN
+# define LANG_UKRAINIAN 0x22
+# endif
+# ifndef LANG_URDU
+# define LANG_URDU 0x20
+# endif
+# ifndef LANG_UZBEK
+# define LANG_UZBEK 0x43
+# endif
+# ifndef LANG_VENDA
+# define LANG_VENDA 0x33
+# endif
+# ifndef LANG_VIETNAMESE
+# define LANG_VIETNAMESE 0x2a
+# endif
+# ifndef LANG_WELSH
+# define LANG_WELSH 0x52
+# endif
+# ifndef LANG_XHOSA
+# define LANG_XHOSA 0x34
+# endif
+# ifndef LANG_YI
+# define LANG_YI 0x78
+# endif
+# ifndef LANG_YIDDISH
+# define LANG_YIDDISH 0x3d
+# endif
+# ifndef LANG_YORUBA
+# define LANG_YORUBA 0x6a
+# endif
+# ifndef LANG_ZULU
+# define LANG_ZULU 0x35
+# endif
+# ifndef SUBLANG_ARABIC_SAUDI_ARABIA
+# define SUBLANG_ARABIC_SAUDI_ARABIA 0x01
+# endif
+# ifndef SUBLANG_ARABIC_IRAQ
+# define SUBLANG_ARABIC_IRAQ 0x02
+# endif
+# ifndef SUBLANG_ARABIC_EGYPT
+# define SUBLANG_ARABIC_EGYPT 0x03
+# endif
+# ifndef SUBLANG_ARABIC_LIBYA
+# define SUBLANG_ARABIC_LIBYA 0x04
+# endif
+# ifndef SUBLANG_ARABIC_ALGERIA
+# define SUBLANG_ARABIC_ALGERIA 0x05
+# endif
+# ifndef SUBLANG_ARABIC_MOROCCO
+# define SUBLANG_ARABIC_MOROCCO 0x06
+# endif
+# ifndef SUBLANG_ARABIC_TUNISIA
+# define SUBLANG_ARABIC_TUNISIA 0x07
+# endif
+# ifndef SUBLANG_ARABIC_OMAN
+# define SUBLANG_ARABIC_OMAN 0x08
+# endif
+# ifndef SUBLANG_ARABIC_YEMEN
+# define SUBLANG_ARABIC_YEMEN 0x09
+# endif
+# ifndef SUBLANG_ARABIC_SYRIA
+# define SUBLANG_ARABIC_SYRIA 0x0a
+# endif
+# ifndef SUBLANG_ARABIC_JORDAN
+# define SUBLANG_ARABIC_JORDAN 0x0b
+# endif
+# ifndef SUBLANG_ARABIC_LEBANON
+# define SUBLANG_ARABIC_LEBANON 0x0c
+# endif
+# ifndef SUBLANG_ARABIC_KUWAIT
+# define SUBLANG_ARABIC_KUWAIT 0x0d
+# endif
+# ifndef SUBLANG_ARABIC_UAE
+# define SUBLANG_ARABIC_UAE 0x0e
+# endif
+# ifndef SUBLANG_ARABIC_BAHRAIN
+# define SUBLANG_ARABIC_BAHRAIN 0x0f
+# endif
+# ifndef SUBLANG_ARABIC_QATAR
+# define SUBLANG_ARABIC_QATAR 0x10
+# endif
+# ifndef SUBLANG_AZERI_LATIN
+# define SUBLANG_AZERI_LATIN 0x01
+# endif
+# ifndef SUBLANG_AZERI_CYRILLIC
+# define SUBLANG_AZERI_CYRILLIC 0x02
+# endif
+# ifndef SUBLANG_BENGALI_INDIA
+# define SUBLANG_BENGALI_INDIA 0x00
+# endif
+# ifndef SUBLANG_BENGALI_BANGLADESH
+# define SUBLANG_BENGALI_BANGLADESH 0x01
+# endif
+# ifndef SUBLANG_CHINESE_MACAU
+# define SUBLANG_CHINESE_MACAU 0x05
+# endif
+# ifndef SUBLANG_ENGLISH_SOUTH_AFRICA
+# define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07
+# endif
+# ifndef SUBLANG_ENGLISH_JAMAICA
+# define SUBLANG_ENGLISH_JAMAICA 0x08
+# endif
+# ifndef SUBLANG_ENGLISH_CARIBBEAN
+# define SUBLANG_ENGLISH_CARIBBEAN 0x09
+# endif
+# ifndef SUBLANG_ENGLISH_BELIZE
+# define SUBLANG_ENGLISH_BELIZE 0x0a
+# endif
+# ifndef SUBLANG_ENGLISH_TRINIDAD
+# define SUBLANG_ENGLISH_TRINIDAD 0x0b
+# endif
+# ifndef SUBLANG_ENGLISH_ZIMBABWE
+# define SUBLANG_ENGLISH_ZIMBABWE 0x0c
+# endif
+# ifndef SUBLANG_ENGLISH_PHILIPPINES
+# define SUBLANG_ENGLISH_PHILIPPINES 0x0d
+# endif
+# ifndef SUBLANG_ENGLISH_INDONESIA
+# define SUBLANG_ENGLISH_INDONESIA 0x0e
+# endif
+# ifndef SUBLANG_ENGLISH_HONGKONG
+# define SUBLANG_ENGLISH_HONGKONG 0x0f
+# endif
+# ifndef SUBLANG_ENGLISH_INDIA
+# define SUBLANG_ENGLISH_INDIA 0x10
+# endif
+# ifndef SUBLANG_ENGLISH_MALAYSIA
+# define SUBLANG_ENGLISH_MALAYSIA 0x11
+# endif
+# ifndef SUBLANG_ENGLISH_SINGAPORE
+# define SUBLANG_ENGLISH_SINGAPORE 0x12
+# endif
+# ifndef SUBLANG_FRENCH_LUXEMBOURG
+# define SUBLANG_FRENCH_LUXEMBOURG 0x05
+# endif
+# ifndef SUBLANG_FRENCH_MONACO
+# define SUBLANG_FRENCH_MONACO 0x06
+# endif
+# ifndef SUBLANG_FRENCH_WESTINDIES
+# define SUBLANG_FRENCH_WESTINDIES 0x07
+# endif
+# ifndef SUBLANG_FRENCH_REUNION
+# define SUBLANG_FRENCH_REUNION 0x08
+# endif
+# ifndef SUBLANG_FRENCH_CONGO
+# define SUBLANG_FRENCH_CONGO 0x09
+# endif
+# ifndef SUBLANG_FRENCH_SENEGAL
+# define SUBLANG_FRENCH_SENEGAL 0x0a
+# endif
+# ifndef SUBLANG_FRENCH_CAMEROON
+# define SUBLANG_FRENCH_CAMEROON 0x0b
+# endif
+# ifndef SUBLANG_FRENCH_COTEDIVOIRE
+# define SUBLANG_FRENCH_COTEDIVOIRE 0x0c
+# endif
+# ifndef SUBLANG_FRENCH_MALI
+# define SUBLANG_FRENCH_MALI 0x0d
+# endif
+# ifndef SUBLANG_FRENCH_MOROCCO
+# define SUBLANG_FRENCH_MOROCCO 0x0e
+# endif
+# ifndef SUBLANG_FRENCH_HAITI
+# define SUBLANG_FRENCH_HAITI 0x0f
+# endif
+# ifndef SUBLANG_GERMAN_LUXEMBOURG
+# define SUBLANG_GERMAN_LUXEMBOURG 0x04
+# endif
+# ifndef SUBLANG_GERMAN_LIECHTENSTEIN
+# define SUBLANG_GERMAN_LIECHTENSTEIN 0x05
+# endif
+# ifndef SUBLANG_KASHMIRI_INDIA
+# define SUBLANG_KASHMIRI_INDIA 0x02
+# endif
+# ifndef SUBLANG_MALAY_MALAYSIA
+# define SUBLANG_MALAY_MALAYSIA 0x01
+# endif
+# ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
+# define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02
+# endif
+# ifndef SUBLANG_NEPALI_INDIA
+# define SUBLANG_NEPALI_INDIA 0x02
+# endif
+# ifndef SUBLANG_PUNJABI_INDIA
+# define SUBLANG_PUNJABI_INDIA 0x00
+# endif
+# ifndef SUBLANG_PUNJABI_PAKISTAN
+# define SUBLANG_PUNJABI_PAKISTAN 0x01
+# endif
+# ifndef SUBLANG_ROMANIAN_ROMANIA
+# define SUBLANG_ROMANIAN_ROMANIA 0x00
+# endif
+# ifndef SUBLANG_ROMANIAN_MOLDOVA
+# define SUBLANG_ROMANIAN_MOLDOVA 0x01
+# endif
+# ifndef SUBLANG_SERBIAN_LATIN
+# define SUBLANG_SERBIAN_LATIN 0x02
+# endif
+# ifndef SUBLANG_SERBIAN_CYRILLIC
+# define SUBLANG_SERBIAN_CYRILLIC 0x03
+# endif
+# ifndef SUBLANG_SINDHI_INDIA
+# define SUBLANG_SINDHI_INDIA 0x00
+# endif
+# ifndef SUBLANG_SINDHI_PAKISTAN
+# define SUBLANG_SINDHI_PAKISTAN 0x01
+# endif
+# ifndef SUBLANG_SPANISH_GUATEMALA
+# define SUBLANG_SPANISH_GUATEMALA 0x04
+# endif
+# ifndef SUBLANG_SPANISH_COSTA_RICA
+# define SUBLANG_SPANISH_COSTA_RICA 0x05
+# endif
+# ifndef SUBLANG_SPANISH_PANAMA
+# define SUBLANG_SPANISH_PANAMA 0x06
+# endif
+# ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC
+# define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07
+# endif
+# ifndef SUBLANG_SPANISH_VENEZUELA
+# define SUBLANG_SPANISH_VENEZUELA 0x08
+# endif
+# ifndef SUBLANG_SPANISH_COLOMBIA
+# define SUBLANG_SPANISH_COLOMBIA 0x09
+# endif
+# ifndef SUBLANG_SPANISH_PERU
+# define SUBLANG_SPANISH_PERU 0x0a
+# endif
+# ifndef SUBLANG_SPANISH_ARGENTINA
+# define SUBLANG_SPANISH_ARGENTINA 0x0b
+# endif
+# ifndef SUBLANG_SPANISH_ECUADOR
+# define SUBLANG_SPANISH_ECUADOR 0x0c
+# endif
+# ifndef SUBLANG_SPANISH_CHILE
+# define SUBLANG_SPANISH_CHILE 0x0d
+# endif
+# ifndef SUBLANG_SPANISH_URUGUAY
+# define SUBLANG_SPANISH_URUGUAY 0x0e
+# endif
+# ifndef SUBLANG_SPANISH_PARAGUAY
+# define SUBLANG_SPANISH_PARAGUAY 0x0f
+# endif
+# ifndef SUBLANG_SPANISH_BOLIVIA
+# define SUBLANG_SPANISH_BOLIVIA 0x10
+# endif
+# ifndef SUBLANG_SPANISH_EL_SALVADOR
+# define SUBLANG_SPANISH_EL_SALVADOR 0x11
+# endif
+# ifndef SUBLANG_SPANISH_HONDURAS
+# define SUBLANG_SPANISH_HONDURAS 0x12
+# endif
+# ifndef SUBLANG_SPANISH_NICARAGUA
+# define SUBLANG_SPANISH_NICARAGUA 0x13
+# endif
+# ifndef SUBLANG_SPANISH_PUERTO_RICO
+# define SUBLANG_SPANISH_PUERTO_RICO 0x14
+# endif
+# ifndef SUBLANG_SWEDISH_FINLAND
+# define SUBLANG_SWEDISH_FINLAND 0x02
+# endif
+# ifndef SUBLANG_TAMAZIGHT_ARABIC
+# define SUBLANG_TAMAZIGHT_ARABIC 0x01
+# endif
+# ifndef SUBLANG_TAMAZIGHT_LATIN
+# define SUBLANG_TAMAZIGHT_LATIN 0x02
+# endif
+# ifndef SUBLANG_TIGRINYA_ETHIOPIA
+# define SUBLANG_TIGRINYA_ETHIOPIA 0x00
+# endif
+# ifndef SUBLANG_TIGRINYA_ERITREA
+# define SUBLANG_TIGRINYA_ERITREA 0x01
+# endif
+# ifndef SUBLANG_URDU_PAKISTAN
+# define SUBLANG_URDU_PAKISTAN 0x01
+# endif
+# ifndef SUBLANG_URDU_INDIA
+# define SUBLANG_URDU_INDIA 0x02
+# endif
+# ifndef SUBLANG_UZBEK_LATIN
+# define SUBLANG_UZBEK_LATIN 0x01
+# endif
+# ifndef SUBLANG_UZBEK_CYRILLIC
+# define SUBLANG_UZBEK_CYRILLIC 0x02
+# endif
+#endif
+
+# if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
+/* MacOS X 10.2 or newer */
+
+/* Canonicalize a MacOS X locale name to a Unix locale name.
+ NAME is a sufficiently large buffer.
+ On input, it contains the MacOS X locale name.
+ On output, it contains the Unix locale name. */
+void
+_nl_locale_name_canonicalize (char *name)
+{
+ /* This conversion is based on a posting by
+ Deborah GoldSmith <goldsmit@apple.com> on 2005-03-08,
+ http://lists.apple.com/archives/carbon-dev/2005/Mar/msg00293.html */
+
+ /* Convert legacy (NeXTstep inherited) English names to Unix (ISO 639 and
+ ISO 3166) names. Prior to MacOS X 10.3, there is no API for doing this.
+ Therefore we do it ourselves, using a table based on the results of the
+ MacOS X 10.3.8 function
+ CFLocaleCreateCanonicalLocaleIdentifierFromString(). */
+ typedef struct { const char legacy[21+1]; const char unixy[5+1]; }
+ legacy_entry;
+ static const legacy_entry legacy_table[] = {
+ { "Afrikaans", "af" },
+ { "Albanian", "sq" },
+ { "Amharic", "am" },
+ { "Arabic", "ar" },
+ { "Armenian", "hy" },
+ { "Assamese", "as" },
+ { "Aymara", "ay" },
+ { "Azerbaijani", "az" },
+ { "Basque", "eu" },
+ { "Belarusian", "be" },
+ { "Belorussian", "be" },
+ { "Bengali", "bn" },
+ { "Brazilian Portugese", "pt_BR" },
+ { "Brazilian Portuguese", "pt_BR" },
+ { "Breton", "br" },
+ { "Bulgarian", "bg" },
+ { "Burmese", "my" },
+ { "Byelorussian", "be" },
+ { "Catalan", "ca" },
+ { "Chewa", "ny" },
+ { "Chichewa", "ny" },
+ { "Chinese", "zh" },
+ { "Chinese, Simplified", "zh_CN" },
+ { "Chinese, Traditional", "zh_TW" },
+ { "Chinese, Tradtional", "zh_TW" },
+ { "Croatian", "hr" },
+ { "Czech", "cs" },
+ { "Danish", "da" },
+ { "Dutch", "nl" },
+ { "Dzongkha", "dz" },
+ { "English", "en" },
+ { "Esperanto", "eo" },
+ { "Estonian", "et" },
+ { "Faroese", "fo" },
+ { "Farsi", "fa" },
+ { "Finnish", "fi" },
+ { "Flemish", "nl_BE" },
+ { "French", "fr" },
+ { "Galician", "gl" },
+ { "Gallegan", "gl" },
+ { "Georgian", "ka" },
+ { "German", "de" },
+ { "Greek", "el" },
+ { "Greenlandic", "kl" },
+ { "Guarani", "gn" },
+ { "Gujarati", "gu" },
+ { "Hawaiian", "haw" }, /* Yes, "haw", not "cpe". */
+ { "Hebrew", "he" },
+ { "Hindi", "hi" },
+ { "Hungarian", "hu" },
+ { "Icelandic", "is" },
+ { "Indonesian", "id" },
+ { "Inuktitut", "iu" },
+ { "Irish", "ga" },
+ { "Italian", "it" },
+ { "Japanese", "ja" },
+ { "Javanese", "jv" },
+ { "Kalaallisut", "kl" },
+ { "Kannada", "kn" },
+ { "Kashmiri", "ks" },
+ { "Kazakh", "kk" },
+ { "Khmer", "km" },
+ { "Kinyarwanda", "rw" },
+ { "Kirghiz", "ky" },
+ { "Korean", "ko" },
+ { "Kurdish", "ku" },
+ { "Latin", "la" },
+ { "Latvian", "lv" },
+ { "Lithuanian", "lt" },
+ { "Macedonian", "mk" },
+ { "Malagasy", "mg" },
+ { "Malay", "ms" },
+ { "Malayalam", "ml" },
+ { "Maltese", "mt" },
+ { "Manx", "gv" },
+ { "Marathi", "mr" },
+ { "Moldavian", "mo" },
+ { "Mongolian", "mn" },
+ { "Nepali", "ne" },
+ { "Norwegian", "nb" }, /* Yes, "nb", not the obsolete "no". */
+ { "Nyanja", "ny" },
+ { "Nynorsk", "nn" },
+ { "Oriya", "or" },
+ { "Oromo", "om" },
+ { "Panjabi", "pa" },
+ { "Pashto", "ps" },
+ { "Persian", "fa" },
+ { "Polish", "pl" },
+ { "Portuguese", "pt" },
+ { "Portuguese, Brazilian", "pt_BR" },
+ { "Punjabi", "pa" },
+ { "Pushto", "ps" },
+ { "Quechua", "qu" },
+ { "Romanian", "ro" },
+ { "Ruanda", "rw" },
+ { "Rundi", "rn" },
+ { "Russian", "ru" },
+ { "Sami", "se_NO" }, /* Not just "se". */
+ { "Sanskrit", "sa" },
+ { "Scottish", "gd" },
+ { "Serbian", "sr" },
+ { "Simplified Chinese", "zh_CN" },
+ { "Sindhi", "sd" },
+ { "Sinhalese", "si" },
+ { "Slovak", "sk" },
+ { "Slovenian", "sl" },
+ { "Somali", "so" },
+ { "Spanish", "es" },
+ { "Sundanese", "su" },
+ { "Swahili", "sw" },
+ { "Swedish", "sv" },
+ { "Tagalog", "tl" },
+ { "Tajik", "tg" },
+ { "Tajiki", "tg" },
+ { "Tamil", "ta" },
+ { "Tatar", "tt" },
+ { "Telugu", "te" },
+ { "Thai", "th" },
+ { "Tibetan", "bo" },
+ { "Tigrinya", "ti" },
+ { "Tongan", "to" },
+ { "Traditional Chinese", "zh_TW" },
+ { "Turkish", "tr" },
+ { "Turkmen", "tk" },
+ { "Uighur", "ug" },
+ { "Ukrainian", "uk" },
+ { "Urdu", "ur" },
+ { "Uzbek", "uz" },
+ { "Vietnamese", "vi" },
+ { "Welsh", "cy" },
+ { "Yiddish", "yi" }
+ };
+
+ /* Convert new-style locale names with language tags (ISO 639 and ISO 15924)
+ to Unix (ISO 639 and ISO 3166) names. */
+ typedef struct { const char langtag[7+1]; const char unixy[12+1]; }
+ langtag_entry;
+ static const langtag_entry langtag_table[] = {
+ /* MacOS X has "az-Arab", "az-Cyrl", "az-Latn".
+ The default script for az on Unix is Latin. */
+ { "az-Latn", "az" },
+ /* MacOS X has "ga-dots". Does not yet exist on Unix. */
+ { "ga-dots", "ga" },
+ /* MacOS X has "kk-Cyrl". Does not yet exist on Unix. */
+ /* MacOS X has "mn-Cyrl", "mn-Mong".
+ The default script for mn on Unix is Cyrillic. */
+ { "mn-Cyrl", "mn" },
+ /* MacOS X has "ms-Arab", "ms-Latn".
+ The default script for ms on Unix is Latin. */
+ { "ms-Latn", "ms" },
+ /* MacOS X has "tg-Cyrl".
+ The default script for tg on Unix is Cyrillic. */
+ { "tg-Cyrl", "tg" },
+ /* MacOS X has "tk-Cyrl". Does not yet exist on Unix. */
+ /* MacOS X has "tt-Cyrl".
+ The default script for tt on Unix is Cyrillic. */
+ { "tt-Cyrl", "tt" },
+ /* MacOS X has "zh-Hans", "zh-Hant".
+ Country codes are used to distinguish these on Unix. */
+ { "zh-Hans", "zh_CN" },
+ { "zh-Hant", "zh_TW" }
+ };
+
+ /* Convert script names (ISO 15924) to Unix conventions.
+ See http://www.unicode.org/iso15924/iso15924-codes.html */
+ typedef struct { const char script[4+1]; const char unixy[9+1]; }
+ script_entry;
+ static const script_entry script_table[] = {
+ { "Arab", "arabic" },
+ { "Cyrl", "cyrillic" },
+ { "Mong", "mongolian" }
+ };
+
+ /* Step 1: Convert using legacy_table. */
+ if (name[0] >= 'A' && name[0] <= 'Z')
+ {
+ unsigned int i1, i2;
+ i1 = 0;
+ i2 = sizeof (legacy_table) / sizeof (legacy_entry);
+ while (i2 - i1 > 1)
+ {
+ /* At this point we know that if name occurs in legacy_table,
+ its index must be >= i1 and < i2. */
+ unsigned int i = (i1 + i2) >> 1;
+ const legacy_entry *p = &legacy_table[i];
+ if (strcmp (name, p->legacy) < 0)
+ i2 = i;
+ else
+ i1 = i;
+ }
+ if (strcmp (name, legacy_table[i1].legacy) == 0)
+ {
+ strcpy (name, legacy_table[i1].unixy);
+ return;
+ }
+ }
+
+ /* Step 2: Convert using langtag_table and script_table. */
+ if (strlen (name) == 7 && name[2] == '-')
+ {
+ unsigned int i1, i2;
+ i1 = 0;
+ i2 = sizeof (langtag_table) / sizeof (langtag_entry);
+ while (i2 - i1 > 1)
+ {
+ /* At this point we know that if name occurs in langtag_table,
+ its index must be >= i1 and < i2. */
+ unsigned int i = (i1 + i2) >> 1;
+ const langtag_entry *p = &langtag_table[i];
+ if (strcmp (name, p->langtag) < 0)
+ i2 = i;
+ else
+ i1 = i;
+ }
+ if (strcmp (name, langtag_table[i1].langtag) == 0)
+ {
+ strcpy (name, langtag_table[i1].unixy);
+ return;
+ }
+
+ i1 = 0;
+ i2 = sizeof (script_table) / sizeof (script_entry);
+ while (i2 - i1 > 1)
+ {
+ /* At this point we know that if (name + 3) occurs in script_table,
+ its index must be >= i1 and < i2. */
+ unsigned int i = (i1 + i2) >> 1;
+ const script_entry *p = &script_table[i];
+ if (strcmp (name + 3, p->script) < 0)
+ i2 = i;
+ else
+ i1 = i;
+ }
+ if (strcmp (name + 3, script_table[i1].script) == 0)
+ {
+ name[2] = '@';
+ strcpy (name + 3, script_table[i1].unixy);
+ return;
+ }
+ }
+
+ /* Step 3: Convert new-style dash to Unix underscore. */
+ {
+ char *p;
+ for (p = name; *p != '\0'; p++)
+ if (*p == '-')
+ *p = '_';
+ }
+}
+
+#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. Neither do SUSV2 and
+ ISO C 99. So we can use this feature only on selected systems (e.g.
+ those using GNU C Library). */
+#if defined _LIBC || (defined __GLIBC__ && __GLIBC__ >= 2)
+# define HAVE_LOCALE_NULL
+#endif
+
+/* Determine the current locale's name, and canonicalize it into XPG syntax
+ language[_territory][.codeset][@modifier]
+ The codeset part in the result is not reliable; the locale_charset()
+ should be used for codeset information instead.
+ The result must not be freed; it is statically allocated. */
+
+const char *
+_nl_locale_name_posix (int category, const char *categoryname)
+{
+ /* Use 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
+ const char *retval;
+
+ /* Setting of LC_ALL overrides 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;
+
+ return NULL;
+#endif
+}
+
+const char *
+_nl_locale_name_default (void)
+{
+ /* POSIX:2001 says:
+ "All implementations shall define a locale as the default locale, to be
+ invoked when no environment variables are set, or set to the empty
+ string. This default locale can be the POSIX locale or any other
+ implementation-defined locale. Some implementations may provide
+ facilities for local installation administrators to set the default
+ locale, customizing it for each location. POSIX:2001 does not require
+ such a facility. */
+
+#if !(HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE || defined(WIN32_NATIVE))
+
+ /* The system does not have a way of setting the locale, other than the
+ POSIX specified environment variables. We use C as default locale. */
+ return "C";
+
+#else
+
+ /* Return an XPG style locale name language[_territory][@modifier].
+ Don't even bother determining the codeset; it's not useful in this
+ context, because message catalogs are not specific to a single
+ codeset. */
+
+# if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
+ /* MacOS X 10.2 or newer */
+ {
+ /* Cache the locale name, since CoreFoundation calls are expensive. */
+ static const char *cached_localename;
+
+ if (cached_localename == NULL)
+ {
+ char namebuf[256];
+# if HAVE_CFLOCALECOPYCURRENT /* MacOS X 10.3 or newer */
+ CFLocaleRef locale = CFLocaleCopyCurrent ();
+ CFStringRef name = CFLocaleGetIdentifier (locale);
+
+ if (CFStringGetCString (name, namebuf, sizeof(namebuf),
+ kCFStringEncodingASCII))
+ {
+ _nl_locale_name_canonicalize (namebuf);
+ cached_localename = strdup (namebuf);
+ }
+ CFRelease (locale);
+# elif HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.2 or newer */
+ CFTypeRef value =
+ CFPreferencesCopyAppValue (CFSTR ("AppleLocale"),
+ kCFPreferencesCurrentApplication);
+ if (value != NULL
+ && CFGetTypeID (value) == CFStringGetTypeID ()
+ && CFStringGetCString ((CFStringRef)value, namebuf, sizeof(namebuf),
+ kCFStringEncodingASCII))
+ {
+ _nl_locale_name_canonicalize (namebuf);
+ cached_localename = strdup (namebuf);
+ }
+# endif
+ if (cached_localename == NULL)
+ cached_localename = "C";
+ }
+ return cached_localename;
+ }
+
+# endif
+
+# if defined(WIN32_NATIVE) /* WIN32, not Cygwin */
+ {
+ LCID lcid;
+ LANGID langid;
+ int primary, sub;
+
+ /* Use native Win32 API locale ID. */
+ lcid = GetThreadLocale ();
+
+ /* Strip off the sorting rules, keep only the language part. */
+ langid = LANGIDFROMLCID (lcid);
+
+ /* Split into language and territory part. */
+ primary = PRIMARYLANGID (langid);
+ sub = SUBLANGID (langid);
+
+ /* Dispatch on language.
+ See also http://www.unicode.org/unicode/onlinedat/languages.html .
+ For details about languages, see http://www.ethnologue.com/ . */
+ switch (primary)
+ {
+ case LANG_AFRIKAANS: return "af_ZA";
+ case LANG_ALBANIAN: return "sq_AL";
+ case LANG_AMHARIC: return "am_ET";
+ case LANG_ARABIC:
+ switch (sub)
+ {
+ case SUBLANG_ARABIC_SAUDI_ARABIA: return "ar_SA";
+ case SUBLANG_ARABIC_IRAQ: return "ar_IQ";
+ case SUBLANG_ARABIC_EGYPT: return "ar_EG";
+ case SUBLANG_ARABIC_LIBYA: return "ar_LY";
+ case SUBLANG_ARABIC_ALGERIA: return "ar_DZ";
+ case SUBLANG_ARABIC_MOROCCO: return "ar_MA";
+ case SUBLANG_ARABIC_TUNISIA: return "ar_TN";
+ case SUBLANG_ARABIC_OMAN: return "ar_OM";
+ case SUBLANG_ARABIC_YEMEN: return "ar_YE";
+ case SUBLANG_ARABIC_SYRIA: return "ar_SY";
+ case SUBLANG_ARABIC_JORDAN: return "ar_JO";
+ case SUBLANG_ARABIC_LEBANON: return "ar_LB";
+ case SUBLANG_ARABIC_KUWAIT: return "ar_KW";
+ case SUBLANG_ARABIC_UAE: return "ar_AE";
+ case SUBLANG_ARABIC_BAHRAIN: return "ar_BH";
+ case SUBLANG_ARABIC_QATAR: return "ar_QA";
+ }
+ return "ar";
+ case LANG_ARMENIAN: return "hy_AM";
+ case LANG_ASSAMESE: return "as_IN";
+ case LANG_AZERI:
+ switch (sub)
+ {
+ /* FIXME: Adjust this when Azerbaijani locales appear on Unix. */
+ case SUBLANG_AZERI_LATIN: return "az_AZ@latin";
+ case SUBLANG_AZERI_CYRILLIC: return "az_AZ@cyrillic";
+ }
+ return "az";
+ case LANG_BASQUE:
+ switch (sub)
+ {
+ case SUBLANG_DEFAULT: return "eu_ES";
+ }
+ return "eu"; /* Ambiguous: could be "eu_ES" or "eu_FR". */
+ case LANG_BELARUSIAN: return "be_BY";
+ case LANG_BENGALI:
+ switch (sub)
+ {
+ case SUBLANG_BENGALI_INDIA: return "bn_IN";
+ case SUBLANG_BENGALI_BANGLADESH: return "bn_BD";
+ }
+ return "bn";
+ case LANG_BULGARIAN: return "bg_BG";
+ case LANG_BURMESE: return "my_MM";
+ case LANG_CAMBODIAN: return "km_KH";
+ case LANG_CATALAN: return "ca_ES";
+ case LANG_CHEROKEE: return "chr_US";
+ case LANG_CHINESE:
+ switch (sub)
+ {
+ case SUBLANG_CHINESE_TRADITIONAL: return "zh_TW";
+ case SUBLANG_CHINESE_SIMPLIFIED: return "zh_CN";
+ case SUBLANG_CHINESE_HONGKONG: return "zh_HK";
+ case SUBLANG_CHINESE_SINGAPORE: return "zh_SG";
+ case SUBLANG_CHINESE_MACAU: return "zh_MO";
+ }
+ return "zh";
+ case LANG_CROATIAN: /* LANG_CROATIAN == LANG_SERBIAN
+ * What used to be called Serbo-Croatian
+ * should really now be two separate
+ * languages because of political reasons.
+ * (Says tml, who knows nothing about Serbian
+ * or Croatian.)
+ * (I can feel those flames coming already.)
+ */
+ switch (sub)
+ {
+ case SUBLANG_DEFAULT: return "hr_HR";
+ case SUBLANG_SERBIAN_LATIN: return "sr_CS";
+ case SUBLANG_SERBIAN_CYRILLIC: return "sr_CS@cyrillic";
+ }
+ return "hr";
+ case LANG_CZECH: return "cs_CZ";
+ case LANG_DANISH: return "da_DK";
+ case LANG_DIVEHI: return "dv_MV";
+ case LANG_DUTCH:
+ switch (sub)
+ {
+ case SUBLANG_DUTCH: return "nl_NL";
+ case SUBLANG_DUTCH_BELGIAN: /* FLEMISH, VLAAMS */ return "nl_BE";
+ }
+ return "nl";
+ case LANG_EDO: return "bin_NG";
+ case LANG_ENGLISH:
+ switch (sub)
+ {
+ /* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought
+ * English was the language spoken in England.
+ * Oh well.
+ */
+ case SUBLANG_ENGLISH_US: return "en_US";
+ case SUBLANG_ENGLISH_UK: return "en_GB";
+ case SUBLANG_ENGLISH_AUS: return "en_AU";
+ case SUBLANG_ENGLISH_CAN: return "en_CA";
+ case SUBLANG_ENGLISH_NZ: return "en_NZ";
+ case SUBLANG_ENGLISH_EIRE: return "en_IE";
+ case SUBLANG_ENGLISH_SOUTH_AFRICA: return "en_ZA";
+ case SUBLANG_ENGLISH_JAMAICA: return "en_JM";
+ case SUBLANG_ENGLISH_CARIBBEAN: return "en_GD"; /* Grenada? */
+ case SUBLANG_ENGLISH_BELIZE: return "en_BZ";
+ case SUBLANG_ENGLISH_TRINIDAD: return "en_TT";
+ case SUBLANG_ENGLISH_ZIMBABWE: return "en_ZW";
+ case SUBLANG_ENGLISH_PHILIPPINES: return "en_PH";
+ case SUBLANG_ENGLISH_INDONESIA: return "en_ID";
+ case SUBLANG_ENGLISH_HONGKONG: return "en_HK";
+ case SUBLANG_ENGLISH_INDIA: return "en_IN";
+ case SUBLANG_ENGLISH_MALAYSIA: return "en_MY";
+ case SUBLANG_ENGLISH_SINGAPORE: return "en_SG";
+ }
+ return "en";
+ case LANG_ESTONIAN: return "et_EE";
+ case LANG_FAEROESE: return "fo_FO";
+ case LANG_FARSI: return "fa_IR";
+ case LANG_FINNISH: return "fi_FI";
+ case LANG_FRENCH:
+ switch (sub)
+ {
+ case SUBLANG_FRENCH: return "fr_FR";
+ case SUBLANG_FRENCH_BELGIAN: /* WALLOON */ return "fr_BE";
+ case SUBLANG_FRENCH_CANADIAN: return "fr_CA";
+ case SUBLANG_FRENCH_SWISS: return "fr_CH";
+ case SUBLANG_FRENCH_LUXEMBOURG: return "fr_LU";
+ case SUBLANG_FRENCH_MONACO: return "fr_MC";
+ case SUBLANG_FRENCH_WESTINDIES: return "fr"; /* Caribbean? */
+ case SUBLANG_FRENCH_REUNION: return "fr_RE";
+ case SUBLANG_FRENCH_CONGO: return "fr_CG";
+ case SUBLANG_FRENCH_SENEGAL: return "fr_SN";
+ case SUBLANG_FRENCH_CAMEROON: return "fr_CM";
+ case SUBLANG_FRENCH_COTEDIVOIRE: return "fr_CI";
+ case SUBLANG_FRENCH_MALI: return "fr_ML";
+ case SUBLANG_FRENCH_MOROCCO: return "fr_MA";
+ case SUBLANG_FRENCH_HAITI: return "fr_HT";
+ }
+ return "fr";
+ case LANG_FRISIAN: return "fy_NL";
+ case LANG_FULFULDE:
+ /* Spoken in Nigeria, Guinea, Senegal, Mali, Niger, Cameroon, Benin. */
+ return "ff_NG";
+ case LANG_GAELIC:
+ switch (sub)
+ {
+ case 0x01: /* SCOTTISH */ return "gd_GB";
+ case 0x02: /* IRISH */ return "ga_IE";
+ }
+ return "C";
+ case LANG_GALICIAN: return "gl_ES";
+ case LANG_GEORGIAN: return "ka_GE";
+ case LANG_GERMAN:
+ switch (sub)
+ {
+ case SUBLANG_GERMAN: return "de_DE";
+ case SUBLANG_GERMAN_SWISS: return "de_CH";
+ case SUBLANG_GERMAN_AUSTRIAN: return "de_AT";
+ case SUBLANG_GERMAN_LUXEMBOURG: return "de_LU";
+ case SUBLANG_GERMAN_LIECHTENSTEIN: return "de_LI";
+ }
+ return "de";
+ case LANG_GREEK: return "el_GR";
+ case LANG_GUARANI: return "gn_PY";
+ case LANG_GUJARATI: return "gu_IN";
+ case LANG_HAUSA: return "ha_NG";
+ case LANG_HAWAIIAN:
+ /* FIXME: Do they mean Hawaiian ("haw_US", 1000 speakers)
+ or Hawaii Creole English ("cpe_US", 600000 speakers)? */
+ return "cpe_US";
+ case LANG_HEBREW: return "he_IL";
+ case LANG_HINDI: return "hi_IN";
+ case LANG_HUNGARIAN: return "hu_HU";
+ case LANG_IBIBIO: return "nic_NG";
+ case LANG_ICELANDIC: return "is_IS";
+ case LANG_IGBO: return "ig_NG";
+ case LANG_INDONESIAN: return "id_ID";
+ case LANG_INUKTITUT: return "iu_CA";
+ case LANG_ITALIAN:
+ switch (sub)
+ {
+ case SUBLANG_ITALIAN: return "it_IT";
+ case SUBLANG_ITALIAN_SWISS: return "it_CH";
+ }
+ return "it";
+ case LANG_JAPANESE: return "ja_JP";
+ case LANG_KANNADA: return "kn_IN";
+ case LANG_KANURI: return "kr_NG";
+ case LANG_KASHMIRI:
+ switch (sub)
+ {
+ case SUBLANG_DEFAULT: return "ks_PK";
+ case SUBLANG_KASHMIRI_INDIA: return "ks_IN";
+ }
+ return "ks";
+ case LANG_KAZAK: return "kk_KZ";
+ case LANG_KONKANI:
+ /* FIXME: Adjust this when such locales appear on Unix. */
+ return "kok_IN";
+ case LANG_KOREAN: return "ko_KR";
+ case LANG_KYRGYZ: return "ky_KG";
+ case LANG_LAO: return "lo_LA";
+ case LANG_LATIN: return "la_VA";
+ case LANG_LATVIAN: return "lv_LV";
+ case LANG_LITHUANIAN: return "lt_LT";
+ case LANG_MACEDONIAN: return "mk_MK";
+ case LANG_MALAY:
+ switch (sub)
+ {
+ case SUBLANG_MALAY_MALAYSIA: return "ms_MY";
+ case SUBLANG_MALAY_BRUNEI_DARUSSALAM: return "ms_BN";
+ }
+ return "ms";
+ case LANG_MALAYALAM: return "ml_IN";
+ case LANG_MALTESE: return "mt_MT";
+ case LANG_MANIPURI:
+ /* FIXME: Adjust this when such locales appear on Unix. */
+ return "mni_IN";
+ case LANG_MARATHI: return "mr_IN";
+ case LANG_MONGOLIAN:
+ switch (sub)
+ {
+ case SUBLANG_DEFAULT: return "mn_MN";
+ }
+ return "mn"; /* Ambiguous: could be "mn_CN" or "mn_MN". */
+ case LANG_NEPALI:
+ switch (sub)
+ {
+ case SUBLANG_DEFAULT: return "ne_NP";
+ case SUBLANG_NEPALI_INDIA: return "ne_IN";
+ }
+ return "ne";
+ case LANG_NORWEGIAN:
+ switch (sub)
+ {
+ case SUBLANG_NORWEGIAN_BOKMAL: return "nb_NO";
+ case SUBLANG_NORWEGIAN_NYNORSK: return "nn_NO";
+ }
+ return "no";
+ case LANG_ORIYA: return "or_IN";
+ case LANG_OROMO: return "om_ET";
+ case LANG_PAPIAMENTU: return "pap_AN";
+ case LANG_PASHTO:
+ return "ps"; /* Ambiguous: could be "ps_PK" or "ps_AF". */
+ case LANG_POLISH: return "pl_PL";
+ case LANG_PORTUGUESE:
+ switch (sub)
+ {
+ case SUBLANG_PORTUGUESE: return "pt_PT";
+ /* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT.
+ Same phenomenon as SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. */
+ case SUBLANG_PORTUGUESE_BRAZILIAN: return "pt_BR";
+ }
+ return "pt";
+ case LANG_PUNJABI:
+ switch (sub)
+ {
+ case SUBLANG_PUNJABI_INDIA: return "pa_IN"; /* Gurmukhi script */
+ case SUBLANG_PUNJABI_PAKISTAN: return "pa_PK"; /* Arabic script */
+ }
+ return "pa";
+ case LANG_RHAETO_ROMANCE: return "rm_CH";
+ case LANG_ROMANIAN:
+ switch (sub)
+ {
+ case SUBLANG_ROMANIAN_ROMANIA: return "ro_RO";
+ case SUBLANG_ROMANIAN_MOLDOVA: return "ro_MD";
+ }
+ return "ro";
+ case LANG_RUSSIAN:
+ switch (sub)
+ {
+ case SUBLANG_DEFAULT: return "ru_RU";
+ }
+ return "ru"; /* Ambiguous: could be "ru_RU" or "ru_UA" or "ru_MD". */
+ case LANG_SAAMI: /* actually Northern Sami */ return "se_NO";
+ case LANG_SANSKRIT: return "sa_IN";
+ case LANG_SINDHI:
+ switch (sub)
+ {
+ case SUBLANG_SINDHI_INDIA: return "sd_IN";
+ case SUBLANG_SINDHI_PAKISTAN: return "sd_PK";
+ }
+ return "sd";
+ case LANG_SINHALESE: return "si_LK";
+ case LANG_SLOVAK: return "sk_SK";
+ case LANG_SLOVENIAN: return "sl_SI";
+ case LANG_SOMALI: return "so_SO";
+ case LANG_SORBIAN:
+ /* FIXME: Adjust this when such locales appear on Unix. */
+ return "wen_DE";
+ case LANG_SPANISH:
+ switch (sub)
+ {
+ case SUBLANG_SPANISH: return "es_ES";
+ case SUBLANG_SPANISH_MEXICAN: return "es_MX";
+ case SUBLANG_SPANISH_MODERN:
+ return "es_ES@modern"; /* not seen on Unix */
+ case SUBLANG_SPANISH_GUATEMALA: return "es_GT";
+ case SUBLANG_SPANISH_COSTA_RICA: return "es_CR";
+ case SUBLANG_SPANISH_PANAMA: return "es_PA";
+ case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: return "es_DO";
+ case SUBLANG_SPANISH_VENEZUELA: return "es_VE";
+ case SUBLANG_SPANISH_COLOMBIA: return "es_CO";
+ case SUBLANG_SPANISH_PERU: return "es_PE";
+ case SUBLANG_SPANISH_ARGENTINA: return "es_AR";
+ case SUBLANG_SPANISH_ECUADOR: return "es_EC";
+ case SUBLANG_SPANISH_CHILE: return "es_CL";
+ case SUBLANG_SPANISH_URUGUAY: return "es_UY";
+ case SUBLANG_SPANISH_PARAGUAY: return "es_PY";
+ case SUBLANG_SPANISH_BOLIVIA: return "es_BO";
+ case SUBLANG_SPANISH_EL_SALVADOR: return "es_SV";
+ case SUBLANG_SPANISH_HONDURAS: return "es_HN";
+ case SUBLANG_SPANISH_NICARAGUA: return "es_NI";
+ case SUBLANG_SPANISH_PUERTO_RICO: return "es_PR";
+ }
+ return "es";
+ case LANG_SUTU: return "bnt_TZ"; /* or "st_LS" or "nso_ZA"? */
+ case LANG_SWAHILI: return "sw_KE";
+ case LANG_SWEDISH:
+ switch (sub)
+ {
+ case SUBLANG_DEFAULT: return "sv_SE";
+ case SUBLANG_SWEDISH_FINLAND: return "sv_FI";
+ }
+ return "sv";
+ case LANG_SYRIAC: return "syr_TR"; /* An extinct language. */
+ case LANG_TAGALOG: return "tl_PH";
+ case LANG_TAJIK: return "tg_TJ";
+ case LANG_TAMAZIGHT:
+ switch (sub)
+ {
+ /* FIXME: Adjust this when Tamazight locales appear on Unix. */
+ case SUBLANG_TAMAZIGHT_ARABIC: return "ber_MA@arabic";
+ case SUBLANG_TAMAZIGHT_LATIN: return "ber_MA@latin";
+ }
+ return "ber_MA";
+ case LANG_TAMIL:
+ switch (sub)
+ {
+ case SUBLANG_DEFAULT: return "ta_IN";
+ }
+ return "ta"; /* Ambiguous: could be "ta_IN" or "ta_LK" or "ta_SG". */
+ case LANG_TATAR: return "tt_RU";
+ case LANG_TELUGU: return "te_IN";
+ case LANG_THAI: return "th_TH";
+ case LANG_TIBETAN: return "bo_CN";
+ case LANG_TIGRINYA:
+ switch (sub)
+ {
+ case SUBLANG_TIGRINYA_ETHIOPIA: return "ti_ET";
+ case SUBLANG_TIGRINYA_ERITREA: return "ti_ER";
+ }
+ return "ti";
+ case LANG_TSONGA: return "ts_ZA";
+ case LANG_TSWANA: return "tn_BW";
+ case LANG_TURKISH: return "tr_TR";
+ case LANG_TURKMEN: return "tk_TM";
+ case LANG_UKRAINIAN: return "uk_UA";
+ case LANG_URDU:
+ switch (sub)
+ {
+ case SUBLANG_URDU_PAKISTAN: return "ur_PK";
+ case SUBLANG_URDU_INDIA: return "ur_IN";
+ }
+ return "ur";
+ case LANG_UZBEK:
+ switch (sub)
+ {
+ case SUBLANG_UZBEK_LATIN: return "uz_UZ";
+ case SUBLANG_UZBEK_CYRILLIC: return "uz_UZ@cyrillic";
+ }
+ return "uz";
+ case LANG_VENDA: return "ve_ZA";
+ case LANG_VIETNAMESE: return "vi_VN";
+ case LANG_WELSH: return "cy_GB";
+ case LANG_XHOSA: return "xh_ZA";
+ case LANG_YI: return "sit_CN";
+ case LANG_YIDDISH: return "yi_IL";
+ case LANG_YORUBA: return "yo_NG";
+ case LANG_ZULU: return "zu_ZA";
+ default: return "C";
+ }
+ }
+# endif
+#endif
+}
+
+const char *
+_nl_locale_name (int category, const char *categoryname)
+{
+ const char *retval;
+
+ retval = _nl_locale_name_posix (category, categoryname);
+ if (retval != NULL)
+ return retval;
+
+ return _nl_locale_name_default ();
+}
diff --git a/intl/lock.c b/intl/lock.c
new file mode 100644
index 000000000..f60a8d9be
--- /dev/null
+++ b/intl/lock.c
@@ -0,0 +1,922 @@
+/* Locking in multithreaded situations.
+ Copyright (C) 2005-2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2005.
+ Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
+ gthr-win32.h. */
+
+#include <config.h>
+
+#include "lock.h"
+
+/* ========================================================================= */
+
+#if USE_POSIX_THREADS
+
+/* Use the POSIX threads library. */
+
+# if PTHREAD_IN_USE_DETECTION_HARD
+
+/* The function to be executed by a dummy thread. */
+static void *
+dummy_thread_func (void *arg)
+{
+ return arg;
+}
+
+int
+glthread_in_use (void)
+{
+ static int tested;
+ static int result; /* 1: linked with -lpthread, 0: only with libc */
+
+ if (!tested)
+ {
+ pthread_t thread;
+
+ if (pthread_create (&thread, NULL, dummy_thread_func, NULL) != 0)
+ /* Thread creation failed. */
+ result = 0;
+ else
+ {
+ /* Thread creation works. */
+ void *retval;
+ if (pthread_join (thread, &retval) != 0)
+ abort ();
+ result = 1;
+ }
+ tested = 1;
+ }
+ return result;
+}
+
+# endif
+
+/* -------------------------- gl_lock_t datatype -------------------------- */
+
+/* ------------------------- gl_rwlock_t datatype ------------------------- */
+
+# if HAVE_PTHREAD_RWLOCK
+
+# if !defined PTHREAD_RWLOCK_INITIALIZER
+
+void
+glthread_rwlock_init (gl_rwlock_t *lock)
+{
+ if (pthread_rwlock_init (&lock->rwlock, NULL) != 0)
+ abort ();
+ lock->initialized = 1;
+}
+
+void
+glthread_rwlock_rdlock (gl_rwlock_t *lock)
+{
+ if (!lock->initialized)
+ {
+ if (pthread_mutex_lock (&lock->guard) != 0)
+ abort ();
+ if (!lock->initialized)
+ glthread_rwlock_init (lock);
+ if (pthread_mutex_unlock (&lock->guard) != 0)
+ abort ();
+ }
+ if (pthread_rwlock_rdlock (&lock->rwlock) != 0)
+ abort ();
+}
+
+void
+glthread_rwlock_wrlock (gl_rwlock_t *lock)
+{
+ if (!lock->initialized)
+ {
+ if (pthread_mutex_lock (&lock->guard) != 0)
+ abort ();
+ if (!lock->initialized)
+ glthread_rwlock_init (lock);
+ if (pthread_mutex_unlock (&lock->guard) != 0)
+ abort ();
+ }
+ if (pthread_rwlock_wrlock (&lock->rwlock) != 0)
+ abort ();
+}
+
+void
+glthread_rwlock_unlock (gl_rwlock_t *lock)
+{
+ if (!lock->initialized)
+ abort ();
+ if (pthread_rwlock_unlock (&lock->rwlock) != 0)
+ abort ();
+}
+
+void
+glthread_rwlock_destroy (gl_rwlock_t *lock)
+{
+ if (!lock->initialized)
+ abort ();
+ if (pthread_rwlock_destroy (&lock->rwlock) != 0)
+ abort ();
+ lock->initialized = 0;
+}
+
+# endif
+
+# else
+
+void
+glthread_rwlock_init (gl_rwlock_t *lock)
+{
+ if (pthread_mutex_init (&lock->lock, NULL) != 0)
+ abort ();
+ if (pthread_cond_init (&lock->waiting_readers, NULL) != 0)
+ abort ();
+ if (pthread_cond_init (&lock->waiting_writers, NULL) != 0)
+ abort ();
+ lock->waiting_writers_count = 0;
+ lock->runcount = 0;
+}
+
+void
+glthread_rwlock_rdlock (gl_rwlock_t *lock)
+{
+ if (pthread_mutex_lock (&lock->lock) != 0)
+ abort ();
+ /* Test whether only readers are currently running, and whether the runcount
+ field will not overflow. */
+ /* POSIX says: "It is implementation-defined whether the calling thread
+ acquires the lock when a writer does not hold the lock and there are
+ writers blocked on the lock." Let's say, no: give the writers a higher
+ priority. */
+ while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
+ {
+ /* This thread has to wait for a while. Enqueue it among the
+ waiting_readers. */
+ if (pthread_cond_wait (&lock->waiting_readers, &lock->lock) != 0)
+ abort ();
+ }
+ lock->runcount++;
+ if (pthread_mutex_unlock (&lock->lock) != 0)
+ abort ();
+}
+
+void
+glthread_rwlock_wrlock (gl_rwlock_t *lock)
+{
+ if (pthread_mutex_lock (&lock->lock) != 0)
+ abort ();
+ /* Test whether no readers or writers are currently running. */
+ while (!(lock->runcount == 0))
+ {
+ /* This thread has to wait for a while. Enqueue it among the
+ waiting_writers. */
+ lock->waiting_writers_count++;
+ if (pthread_cond_wait (&lock->waiting_writers, &lock->lock) != 0)
+ abort ();
+ lock->waiting_writers_count--;
+ }
+ lock->runcount--; /* runcount becomes -1 */
+ if (pthread_mutex_unlock (&lock->lock) != 0)
+ abort ();
+}
+
+void
+glthread_rwlock_unlock (gl_rwlock_t *lock)
+{
+ if (pthread_mutex_lock (&lock->lock) != 0)
+ abort ();
+ if (lock->runcount < 0)
+ {
+ /* Drop a writer lock. */
+ if (!(lock->runcount == -1))
+ abort ();
+ lock->runcount = 0;
+ }
+ else
+ {
+ /* Drop a reader lock. */
+ if (!(lock->runcount > 0))
+ abort ();
+ lock->runcount--;
+ }
+ if (lock->runcount == 0)
+ {
+ /* POSIX recommends that "write locks shall take precedence over read
+ locks", to avoid "writer starvation". */
+ if (lock->waiting_writers_count > 0)
+ {
+ /* Wake up one of the waiting writers. */
+ if (pthread_cond_signal (&lock->waiting_writers) != 0)
+ abort ();
+ }
+ else
+ {
+ /* Wake up all waiting readers. */
+ if (pthread_cond_broadcast (&lock->waiting_readers) != 0)
+ abort ();
+ }
+ }
+ if (pthread_mutex_unlock (&lock->lock) != 0)
+ abort ();
+}
+
+void
+glthread_rwlock_destroy (gl_rwlock_t *lock)
+{
+ if (pthread_mutex_destroy (&lock->lock) != 0)
+ abort ();
+ if (pthread_cond_destroy (&lock->waiting_readers) != 0)
+ abort ();
+ if (pthread_cond_destroy (&lock->waiting_writers) != 0)
+ abort ();
+}
+
+# endif
+
+/* --------------------- gl_recursive_lock_t datatype --------------------- */
+
+# if HAVE_PTHREAD_MUTEX_RECURSIVE
+
+# if !(defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
+
+void
+glthread_recursive_lock_init (gl_recursive_lock_t *lock)
+{
+ pthread_mutexattr_t attributes;
+
+ if (pthread_mutexattr_init (&attributes) != 0)
+ abort ();
+ if (pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE) != 0)
+ abort ();
+ if (pthread_mutex_init (&lock->recmutex, &attributes) != 0)
+ abort ();
+ if (pthread_mutexattr_destroy (&attributes) != 0)
+ abort ();
+ lock->initialized = 1;
+}
+
+void
+glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
+{
+ if (!lock->initialized)
+ {
+ if (pthread_mutex_lock (&lock->guard) != 0)
+ abort ();
+ if (!lock->initialized)
+ glthread_recursive_lock_init (lock);
+ if (pthread_mutex_unlock (&lock->guard) != 0)
+ abort ();
+ }
+ if (pthread_mutex_lock (&lock->recmutex) != 0)
+ abort ();
+}
+
+void
+glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
+{
+ if (!lock->initialized)
+ abort ();
+ if (pthread_mutex_unlock (&lock->recmutex) != 0)
+ abort ();
+}
+
+void
+glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
+{
+ if (!lock->initialized)
+ abort ();
+ if (pthread_mutex_destroy (&lock->recmutex) != 0)
+ abort ();
+ lock->initialized = 0;
+}
+
+# endif
+
+# else
+
+void
+glthread_recursive_lock_init (gl_recursive_lock_t *lock)
+{
+ if (pthread_mutex_init (&lock->mutex, NULL) != 0)
+ abort ();
+ lock->owner = (pthread_t) 0;
+ lock->depth = 0;
+}
+
+void
+glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
+{
+ pthread_t self = pthread_self ();
+ if (lock->owner != self)
+ {
+ if (pthread_mutex_lock (&lock->mutex) != 0)
+ abort ();
+ lock->owner = self;
+ }
+ if (++(lock->depth) == 0) /* wraparound? */
+ abort ();
+}
+
+void
+glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
+{
+ if (lock->owner != pthread_self ())
+ abort ();
+ if (lock->depth == 0)
+ abort ();
+ if (--(lock->depth) == 0)
+ {
+ lock->owner = (pthread_t) 0;
+ if (pthread_mutex_unlock (&lock->mutex) != 0)
+ abort ();
+ }
+}
+
+void
+glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
+{
+ if (lock->owner != (pthread_t) 0)
+ abort ();
+ if (pthread_mutex_destroy (&lock->mutex) != 0)
+ abort ();
+}
+
+# endif
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
+
+int
+glthread_once_singlethreaded (pthread_once_t *once_control)
+{
+ /* We don't know whether pthread_once_t is an integer type, a floating-point
+ type, a pointer type, or a structure type. */
+ char *firstbyte = (char *)once_control;
+ if (*firstbyte == *(const char *)&fresh_once)
+ {
+ /* First time use of once_control. Invert the first byte. */
+ *firstbyte = ~ *(const char *)&fresh_once;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_PTH_THREADS
+
+/* Use the GNU Pth threads library. */
+
+/* -------------------------- gl_lock_t datatype -------------------------- */
+
+/* ------------------------- gl_rwlock_t datatype ------------------------- */
+
+/* --------------------- gl_recursive_lock_t datatype --------------------- */
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+void
+glthread_once_call (void *arg)
+{
+ void (**gl_once_temp_addr) (void) = (void (**) (void)) arg;
+ void (*initfunction) (void) = *gl_once_temp_addr;
+ initfunction ();
+}
+
+int
+glthread_once_singlethreaded (pth_once_t *once_control)
+{
+ /* We know that pth_once_t is an integer type. */
+ if (*once_control == PTH_ONCE_INIT)
+ {
+ /* First time use of once_control. Invert the marker. */
+ *once_control = ~ PTH_ONCE_INIT;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_SOLARIS_THREADS
+
+/* Use the old Solaris threads library. */
+
+/* -------------------------- gl_lock_t datatype -------------------------- */
+
+/* ------------------------- gl_rwlock_t datatype ------------------------- */
+
+/* --------------------- gl_recursive_lock_t datatype --------------------- */
+
+void
+glthread_recursive_lock_init (gl_recursive_lock_t *lock)
+{
+ if (mutex_init (&lock->mutex, USYNC_THREAD, NULL) != 0)
+ abort ();
+ lock->owner = (thread_t) 0;
+ lock->depth = 0;
+}
+
+void
+glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
+{
+ thread_t self = thr_self ();
+ if (lock->owner != self)
+ {
+ if (mutex_lock (&lock->mutex) != 0)
+ abort ();
+ lock->owner = self;
+ }
+ if (++(lock->depth) == 0) /* wraparound? */
+ abort ();
+}
+
+void
+glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
+{
+ if (lock->owner != thr_self ())
+ abort ();
+ if (lock->depth == 0)
+ abort ();
+ if (--(lock->depth) == 0)
+ {
+ lock->owner = (thread_t) 0;
+ if (mutex_unlock (&lock->mutex) != 0)
+ abort ();
+ }
+}
+
+void
+glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
+{
+ if (lock->owner != (thread_t) 0)
+ abort ();
+ if (mutex_destroy (&lock->mutex) != 0)
+ abort ();
+}
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+void
+glthread_once (gl_once_t *once_control, void (*initfunction) (void))
+{
+ if (!once_control->inited)
+ {
+ /* Use the mutex to guarantee that if another thread is already calling
+ the initfunction, this thread waits until it's finished. */
+ if (mutex_lock (&once_control->mutex) != 0)
+ abort ();
+ if (!once_control->inited)
+ {
+ once_control->inited = 1;
+ initfunction ();
+ }
+ if (mutex_unlock (&once_control->mutex) != 0)
+ abort ();
+ }
+}
+
+int
+glthread_once_singlethreaded (gl_once_t *once_control)
+{
+ /* We know that gl_once_t contains an integer type. */
+ if (!once_control->inited)
+ {
+ /* First time use of once_control. Invert the marker. */
+ once_control->inited = ~ 0;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_WIN32_THREADS
+
+/* -------------------------- gl_lock_t datatype -------------------------- */
+
+void
+glthread_lock_init (gl_lock_t *lock)
+{
+ InitializeCriticalSection (&lock->lock);
+ lock->guard.done = 1;
+}
+
+void
+glthread_lock_lock (gl_lock_t *lock)
+{
+ if (!lock->guard.done)
+ {
+ if (InterlockedIncrement (&lock->guard.started) == 0)
+ /* This thread is the first one to need this lock. Initialize it. */
+ glthread_lock_init (lock);
+ else
+ /* Yield the CPU while waiting for another thread to finish
+ initializing this lock. */
+ while (!lock->guard.done)
+ Sleep (0);
+ }
+ EnterCriticalSection (&lock->lock);
+}
+
+void
+glthread_lock_unlock (gl_lock_t *lock)
+{
+ if (!lock->guard.done)
+ abort ();
+ LeaveCriticalSection (&lock->lock);
+}
+
+void
+glthread_lock_destroy (gl_lock_t *lock)
+{
+ if (!lock->guard.done)
+ abort ();
+ DeleteCriticalSection (&lock->lock);
+ lock->guard.done = 0;
+}
+
+/* ------------------------- gl_rwlock_t datatype ------------------------- */
+
+static inline void
+gl_waitqueue_init (gl_waitqueue_t *wq)
+{
+ wq->array = NULL;
+ wq->count = 0;
+ wq->alloc = 0;
+ wq->offset = 0;
+}
+
+/* Enqueues the current thread, represented by an event, in a wait queue.
+ Returns INVALID_HANDLE_VALUE if an allocation failure occurs. */
+static HANDLE
+gl_waitqueue_add (gl_waitqueue_t *wq)
+{
+ HANDLE event;
+ unsigned int index;
+
+ if (wq->count == wq->alloc)
+ {
+ unsigned int new_alloc = 2 * wq->alloc + 1;
+ HANDLE *new_array =
+ (HANDLE *) realloc (wq->array, new_alloc * sizeof (HANDLE));
+ if (new_array == NULL)
+ /* No more memory. */
+ return INVALID_HANDLE_VALUE;
+ /* Now is a good opportunity to rotate the array so that its contents
+ starts at offset 0. */
+ if (wq->offset > 0)
+ {
+ unsigned int old_count = wq->count;
+ unsigned int old_alloc = wq->alloc;
+ unsigned int old_offset = wq->offset;
+ unsigned int i;
+ if (old_offset + old_count > old_alloc)
+ {
+ unsigned int limit = old_offset + old_count - old_alloc;
+ for (i = 0; i < limit; i++)
+ new_array[old_alloc + i] = new_array[i];
+ }
+ for (i = 0; i < old_count; i++)
+ new_array[i] = new_array[old_offset + i];
+ wq->offset = 0;
+ }
+ wq->array = new_array;
+ wq->alloc = new_alloc;
+ }
+ event = CreateEvent (NULL, TRUE, FALSE, NULL);
+ if (event == INVALID_HANDLE_VALUE)
+ /* No way to allocate an event. */
+ return INVALID_HANDLE_VALUE;
+ index = wq->offset + wq->count;
+ if (index >= wq->alloc)
+ index -= wq->alloc;
+ wq->array[index] = event;
+ wq->count++;
+ return event;
+}
+
+/* Notifies the first thread from a wait queue and dequeues it. */
+static inline void
+gl_waitqueue_notify_first (gl_waitqueue_t *wq)
+{
+ SetEvent (wq->array[wq->offset + 0]);
+ wq->offset++;
+ wq->count--;
+ if (wq->count == 0 || wq->offset == wq->alloc)
+ wq->offset = 0;
+}
+
+/* Notifies all threads from a wait queue and dequeues them all. */
+static inline void
+gl_waitqueue_notify_all (gl_waitqueue_t *wq)
+{
+ unsigned int i;
+
+ for (i = 0; i < wq->count; i++)
+ {
+ unsigned int index = wq->offset + i;
+ if (index >= wq->alloc)
+ index -= wq->alloc;
+ SetEvent (wq->array[index]);
+ }
+ wq->count = 0;
+ wq->offset = 0;
+}
+
+void
+glthread_rwlock_init (gl_rwlock_t *lock)
+{
+ InitializeCriticalSection (&lock->lock);
+ gl_waitqueue_init (&lock->waiting_readers);
+ gl_waitqueue_init (&lock->waiting_writers);
+ lock->runcount = 0;
+ lock->guard.done = 1;
+}
+
+void
+glthread_rwlock_rdlock (gl_rwlock_t *lock)
+{
+ if (!lock->guard.done)
+ {
+ if (InterlockedIncrement (&lock->guard.started) == 0)
+ /* This thread is the first one to need this lock. Initialize it. */
+ glthread_rwlock_init (lock);
+ else
+ /* Yield the CPU while waiting for another thread to finish
+ initializing this lock. */
+ while (!lock->guard.done)
+ Sleep (0);
+ }
+ EnterCriticalSection (&lock->lock);
+ /* Test whether only readers are currently running, and whether the runcount
+ field will not overflow. */
+ if (!(lock->runcount + 1 > 0))
+ {
+ /* This thread has to wait for a while. Enqueue it among the
+ waiting_readers. */
+ HANDLE event = gl_waitqueue_add (&lock->waiting_readers);
+ if (event != INVALID_HANDLE_VALUE)
+ {
+ DWORD result;
+ LeaveCriticalSection (&lock->lock);
+ /* Wait until another thread signals this event. */
+ result = WaitForSingleObject (event, INFINITE);
+ if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
+ abort ();
+ CloseHandle (event);
+ /* The thread which signalled the event already did the bookkeeping:
+ removed us from the waiting_readers, incremented lock->runcount. */
+ if (!(lock->runcount > 0))
+ abort ();
+ return;
+ }
+ else
+ {
+ /* Allocation failure. Weird. */
+ do
+ {
+ LeaveCriticalSection (&lock->lock);
+ Sleep (1);
+ EnterCriticalSection (&lock->lock);
+ }
+ while (!(lock->runcount + 1 > 0));
+ }
+ }
+ lock->runcount++;
+ LeaveCriticalSection (&lock->lock);
+}
+
+void
+glthread_rwlock_wrlock (gl_rwlock_t *lock)
+{
+ if (!lock->guard.done)
+ {
+ if (InterlockedIncrement (&lock->guard.started) == 0)
+ /* This thread is the first one to need this lock. Initialize it. */
+ glthread_rwlock_init (lock);
+ else
+ /* Yield the CPU while waiting for another thread to finish
+ initializing this lock. */
+ while (!lock->guard.done)
+ Sleep (0);
+ }
+ EnterCriticalSection (&lock->lock);
+ /* Test whether no readers or writers are currently running. */
+ if (!(lock->runcount == 0))
+ {
+ /* This thread has to wait for a while. Enqueue it among the
+ waiting_writers. */
+ HANDLE event = gl_waitqueue_add (&lock->waiting_writers);
+ if (event != INVALID_HANDLE_VALUE)
+ {
+ DWORD result;
+ LeaveCriticalSection (&lock->lock);
+ /* Wait until another thread signals this event. */
+ result = WaitForSingleObject (event, INFINITE);
+ if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
+ abort ();
+ CloseHandle (event);
+ /* The thread which signalled the event already did the bookkeeping:
+ removed us from the waiting_writers, set lock->runcount = -1. */
+ if (!(lock->runcount == -1))
+ abort ();
+ return;
+ }
+ else
+ {
+ /* Allocation failure. Weird. */
+ do
+ {
+ LeaveCriticalSection (&lock->lock);
+ Sleep (1);
+ EnterCriticalSection (&lock->lock);
+ }
+ while (!(lock->runcount == 0));
+ }
+ }
+ lock->runcount--; /* runcount becomes -1 */
+ LeaveCriticalSection (&lock->lock);
+}
+
+void
+glthread_rwlock_unlock (gl_rwlock_t *lock)
+{
+ if (!lock->guard.done)
+ abort ();
+ EnterCriticalSection (&lock->lock);
+ if (lock->runcount < 0)
+ {
+ /* Drop a writer lock. */
+ if (!(lock->runcount == -1))
+ abort ();
+ lock->runcount = 0;
+ }
+ else
+ {
+ /* Drop a reader lock. */
+ if (!(lock->runcount > 0))
+ abort ();
+ lock->runcount--;
+ }
+ if (lock->runcount == 0)
+ {
+ /* POSIX recommends that "write locks shall take precedence over read
+ locks", to avoid "writer starvation". */
+ if (lock->waiting_writers.count > 0)
+ {
+ /* Wake up one of the waiting writers. */
+ lock->runcount--;
+ gl_waitqueue_notify_first (&lock->waiting_writers);
+ }
+ else
+ {
+ /* Wake up all waiting readers. */
+ lock->runcount += lock->waiting_readers.count;
+ gl_waitqueue_notify_all (&lock->waiting_readers);
+ }
+ }
+ LeaveCriticalSection (&lock->lock);
+}
+
+void
+glthread_rwlock_destroy (gl_rwlock_t *lock)
+{
+ if (!lock->guard.done)
+ abort ();
+ if (lock->runcount != 0)
+ abort ();
+ DeleteCriticalSection (&lock->lock);
+ if (lock->waiting_readers.array != NULL)
+ free (lock->waiting_readers.array);
+ if (lock->waiting_writers.array != NULL)
+ free (lock->waiting_writers.array);
+ lock->guard.done = 0;
+}
+
+/* --------------------- gl_recursive_lock_t datatype --------------------- */
+
+void
+glthread_recursive_lock_init (gl_recursive_lock_t *lock)
+{
+ lock->owner = 0;
+ lock->depth = 0;
+ InitializeCriticalSection (&lock->lock);
+ lock->guard.done = 1;
+}
+
+void
+glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
+{
+ if (!lock->guard.done)
+ {
+ if (InterlockedIncrement (&lock->guard.started) == 0)
+ /* This thread is the first one to need this lock. Initialize it. */
+ glthread_recursive_lock_init (lock);
+ else
+ /* Yield the CPU while waiting for another thread to finish
+ initializing this lock. */
+ while (!lock->guard.done)
+ Sleep (0);
+ }
+ {
+ DWORD self = GetCurrentThreadId ();
+ if (lock->owner != self)
+ {
+ EnterCriticalSection (&lock->lock);
+ lock->owner = self;
+ }
+ if (++(lock->depth) == 0) /* wraparound? */
+ abort ();
+ }
+}
+
+void
+glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
+{
+ if (lock->owner != GetCurrentThreadId ())
+ abort ();
+ if (lock->depth == 0)
+ abort ();
+ if (--(lock->depth) == 0)
+ {
+ lock->owner = 0;
+ LeaveCriticalSection (&lock->lock);
+ }
+}
+
+void
+glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
+{
+ if (lock->owner != 0)
+ abort ();
+ DeleteCriticalSection (&lock->lock);
+ lock->guard.done = 0;
+}
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+void
+glthread_once (gl_once_t *once_control, void (*initfunction) (void))
+{
+ if (once_control->inited <= 0)
+ {
+ if (InterlockedIncrement (&once_control->started) == 0)
+ {
+ /* This thread is the first one to come to this once_control. */
+ InitializeCriticalSection (&once_control->lock);
+ EnterCriticalSection (&once_control->lock);
+ once_control->inited = 0;
+ initfunction ();
+ once_control->inited = 1;
+ LeaveCriticalSection (&once_control->lock);
+ }
+ else
+ {
+ /* Undo last operation. */
+ InterlockedDecrement (&once_control->started);
+ /* Some other thread has already started the initialization.
+ Yield the CPU while waiting for the other thread to finish
+ initializing and taking the lock. */
+ while (once_control->inited < 0)
+ Sleep (0);
+ if (once_control->inited <= 0)
+ {
+ /* Take the lock. This blocks until the other thread has
+ finished calling the initfunction. */
+ EnterCriticalSection (&once_control->lock);
+ LeaveCriticalSection (&once_control->lock);
+ if (!(once_control->inited > 0))
+ abort ();
+ }
+ }
+ }
+}
+
+#endif
+
+/* ========================================================================= */
diff --git a/intl/lock.h b/intl/lock.h
new file mode 100644
index 000000000..04d136922
--- /dev/null
+++ b/intl/lock.h
@@ -0,0 +1,833 @@
+/* Locking in multithreaded situations.
+ Copyright (C) 2005-2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2005.
+ Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
+ gthr-win32.h. */
+
+/* This file contains locking primitives for use with a given thread library.
+ It does not contain primitives for creating threads or for other
+ synchronization primitives.
+
+ Normal (non-recursive) locks:
+ Type: gl_lock_t
+ Declaration: gl_lock_define(extern, name)
+ Initializer: gl_lock_define_initialized(, name)
+ Initialization: gl_lock_init (name);
+ Taking the lock: gl_lock_lock (name);
+ Releasing the lock: gl_lock_unlock (name);
+ De-initialization: gl_lock_destroy (name);
+
+ Read-Write (non-recursive) locks:
+ Type: gl_rwlock_t
+ Declaration: gl_rwlock_define(extern, name)
+ Initializer: gl_rwlock_define_initialized(, name)
+ Initialization: gl_rwlock_init (name);
+ Taking the lock: gl_rwlock_rdlock (name);
+ gl_rwlock_wrlock (name);
+ Releasing the lock: gl_rwlock_unlock (name);
+ De-initialization: gl_rwlock_destroy (name);
+
+ Recursive locks:
+ Type: gl_recursive_lock_t
+ Declaration: gl_recursive_lock_define(extern, name)
+ Initializer: gl_recursive_lock_define_initialized(, name)
+ Initialization: gl_recursive_lock_init (name);
+ Taking the lock: gl_recursive_lock_lock (name);
+ Releasing the lock: gl_recursive_lock_unlock (name);
+ De-initialization: gl_recursive_lock_destroy (name);
+
+ Once-only execution:
+ Type: gl_once_t
+ Initializer: gl_once_define(extern, name)
+ Execution: gl_once (name, initfunction);
+*/
+
+
+#ifndef _LOCK_H
+#define _LOCK_H
+
+/* ========================================================================= */
+
+#if USE_POSIX_THREADS
+
+/* Use the POSIX threads library. */
+
+# include <pthread.h>
+# include <stdlib.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if PTHREAD_IN_USE_DETECTION_HARD
+
+/* The pthread_in_use() detection needs to be done at runtime. */
+# define pthread_in_use() \
+ glthread_in_use ()
+extern int glthread_in_use (void);
+
+# endif
+
+# if USE_POSIX_THREADS_WEAK
+
+/* Use weak references to the POSIX threads library. */
+
+/* Weak references avoid dragging in external libraries if the other parts
+ of the program don't use them. Here we use them, because we don't want
+ every program that uses libintl to depend on libpthread. This assumes
+ that libpthread would not be loaded after libintl; i.e. if libintl is
+ loaded first, by an executable that does not depend on libpthread, and
+ then a module is dynamically loaded that depends on libpthread, libintl
+ will not be multithread-safe. */
+
+/* The way to test at runtime whether libpthread is present is to test
+ whether a function pointer's value, such as &pthread_mutex_init, is
+ non-NULL. However, some versions of GCC have a bug through which, in
+ PIC mode, &foo != NULL always evaluates to true if there is a direct
+ call to foo(...) in the same function. To avoid this, we test the
+ address of a function in libpthread that we don't use. */
+
+# pragma weak pthread_mutex_init
+# pragma weak pthread_mutex_lock
+# pragma weak pthread_mutex_unlock
+# pragma weak pthread_mutex_destroy
+# pragma weak pthread_rwlock_init
+# pragma weak pthread_rwlock_rdlock
+# pragma weak pthread_rwlock_wrlock
+# pragma weak pthread_rwlock_unlock
+# pragma weak pthread_rwlock_destroy
+# pragma weak pthread_once
+# pragma weak pthread_cond_init
+# pragma weak pthread_cond_wait
+# pragma weak pthread_cond_signal
+# pragma weak pthread_cond_broadcast
+# pragma weak pthread_cond_destroy
+# pragma weak pthread_mutexattr_init
+# pragma weak pthread_mutexattr_settype
+# pragma weak pthread_mutexattr_destroy
+# ifndef pthread_self
+# pragma weak pthread_self
+# endif
+
+# if !PTHREAD_IN_USE_DETECTION_HARD
+# pragma weak pthread_cancel
+# define pthread_in_use() (pthread_cancel != NULL)
+# endif
+
+# else
+
+# if !PTHREAD_IN_USE_DETECTION_HARD
+# define pthread_in_use() 1
+# endif
+
+# endif
+
+/* -------------------------- gl_lock_t datatype -------------------------- */
+
+typedef pthread_mutex_t gl_lock_t;
+# define gl_lock_define(STORAGECLASS, NAME) \
+ STORAGECLASS pthread_mutex_t NAME;
+# define gl_lock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
+# define gl_lock_initializer \
+ PTHREAD_MUTEX_INITIALIZER
+# define gl_lock_init(NAME) \
+ if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
+# define gl_lock_lock(NAME) \
+ if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
+# define gl_lock_unlock(NAME) \
+ if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
+# define gl_lock_destroy(NAME) \
+ if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
+
+/* ------------------------- gl_rwlock_t datatype ------------------------- */
+
+# if HAVE_PTHREAD_RWLOCK
+
+# ifdef PTHREAD_RWLOCK_INITIALIZER
+
+typedef pthread_rwlock_t gl_rwlock_t;
+# define gl_rwlock_define(STORAGECLASS, NAME) \
+ STORAGECLASS pthread_rwlock_t NAME;
+# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
+# define gl_rwlock_initializer \
+ PTHREAD_RWLOCK_INITIALIZER
+# define gl_rwlock_init(NAME) \
+ if (pthread_in_use () && pthread_rwlock_init (&NAME, NULL) != 0) abort ()
+# define gl_rwlock_rdlock(NAME) \
+ if (pthread_in_use () && pthread_rwlock_rdlock (&NAME) != 0) abort ()
+# define gl_rwlock_wrlock(NAME) \
+ if (pthread_in_use () && pthread_rwlock_wrlock (&NAME) != 0) abort ()
+# define gl_rwlock_unlock(NAME) \
+ if (pthread_in_use () && pthread_rwlock_unlock (&NAME) != 0) abort ()
+# define gl_rwlock_destroy(NAME) \
+ if (pthread_in_use () && pthread_rwlock_destroy (&NAME) != 0) abort ()
+
+# else
+
+typedef struct
+ {
+ int initialized;
+ pthread_mutex_t guard; /* protects the initialization */
+ pthread_rwlock_t rwlock; /* read-write lock */
+ }
+ gl_rwlock_t;
+# define gl_rwlock_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_rwlock_t NAME;
+# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
+# define gl_rwlock_initializer \
+ { 0, PTHREAD_MUTEX_INITIALIZER }
+# define gl_rwlock_init(NAME) \
+ if (pthread_in_use ()) glthread_rwlock_init (&NAME)
+# define gl_rwlock_rdlock(NAME) \
+ if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
+# define gl_rwlock_wrlock(NAME) \
+ if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
+# define gl_rwlock_unlock(NAME) \
+ if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
+# define gl_rwlock_destroy(NAME) \
+ if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
+extern void glthread_rwlock_init (gl_rwlock_t *lock);
+extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
+extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
+extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
+extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
+
+# endif
+
+# else
+
+typedef struct
+ {
+ pthread_mutex_t lock; /* protects the remaining fields */
+ pthread_cond_t waiting_readers; /* waiting readers */
+ pthread_cond_t waiting_writers; /* waiting writers */
+ unsigned int waiting_writers_count; /* number of waiting writers */
+ int runcount; /* number of readers running, or -1 when a writer runs */
+ }
+ gl_rwlock_t;
+# define gl_rwlock_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_rwlock_t NAME;
+# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
+# define gl_rwlock_initializer \
+ { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
+# define gl_rwlock_init(NAME) \
+ if (pthread_in_use ()) glthread_rwlock_init (&NAME)
+# define gl_rwlock_rdlock(NAME) \
+ if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
+# define gl_rwlock_wrlock(NAME) \
+ if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
+# define gl_rwlock_unlock(NAME) \
+ if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
+# define gl_rwlock_destroy(NAME) \
+ if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
+extern void glthread_rwlock_init (gl_rwlock_t *lock);
+extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
+extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
+extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
+extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
+
+# endif
+
+/* --------------------- gl_recursive_lock_t datatype --------------------- */
+
+# if HAVE_PTHREAD_MUTEX_RECURSIVE
+
+# if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+
+typedef pthread_mutex_t gl_recursive_lock_t;
+# define gl_recursive_lock_define(STORAGECLASS, NAME) \
+ STORAGECLASS pthread_mutex_t NAME;
+# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
+# ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
+# define gl_recursive_lock_initializer \
+ PTHREAD_RECURSIVE_MUTEX_INITIALIZER
+# else
+# define gl_recursive_lock_initializer \
+ PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+# endif
+# define gl_recursive_lock_init(NAME) \
+ if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
+# define gl_recursive_lock_lock(NAME) \
+ if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
+# define gl_recursive_lock_unlock(NAME) \
+ if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
+# define gl_recursive_lock_destroy(NAME) \
+ if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
+
+# else
+
+typedef struct
+ {
+ pthread_mutex_t recmutex; /* recursive mutex */
+ pthread_mutex_t guard; /* protects the initialization */
+ int initialized;
+ }
+ gl_recursive_lock_t;
+# define gl_recursive_lock_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_recursive_lock_t NAME;
+# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
+# define gl_recursive_lock_initializer \
+ { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
+# define gl_recursive_lock_init(NAME) \
+ if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
+# define gl_recursive_lock_lock(NAME) \
+ if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
+# define gl_recursive_lock_unlock(NAME) \
+ if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
+# define gl_recursive_lock_destroy(NAME) \
+ if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
+extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
+
+# endif
+
+# else
+
+/* Old versions of POSIX threads on Solaris did not have recursive locks.
+ We have to implement them ourselves. */
+
+typedef struct
+ {
+ pthread_mutex_t mutex;
+ pthread_t owner;
+ unsigned long depth;
+ }
+ gl_recursive_lock_t;
+# define gl_recursive_lock_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_recursive_lock_t NAME;
+# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
+# define gl_recursive_lock_initializer \
+ { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
+# define gl_recursive_lock_init(NAME) \
+ if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
+# define gl_recursive_lock_lock(NAME) \
+ if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
+# define gl_recursive_lock_unlock(NAME) \
+ if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
+# define gl_recursive_lock_destroy(NAME) \
+ if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
+extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
+
+# endif
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef pthread_once_t gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+ STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
+# define gl_once(NAME, INITFUNCTION) \
+ do \
+ { \
+ if (pthread_in_use ()) \
+ { \
+ if (pthread_once (&NAME, INITFUNCTION) != 0) \
+ abort (); \
+ } \
+ else \
+ { \
+ if (glthread_once_singlethreaded (&NAME)) \
+ INITFUNCTION (); \
+ } \
+ } \
+ while (0)
+extern int glthread_once_singlethreaded (pthread_once_t *once_control);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_PTH_THREADS
+
+/* Use the GNU Pth threads library. */
+
+# include <pth.h>
+# include <stdlib.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if USE_PTH_THREADS_WEAK
+
+/* Use weak references to the GNU Pth threads library. */
+
+# pragma weak pth_mutex_init
+# pragma weak pth_mutex_acquire
+# pragma weak pth_mutex_release
+# pragma weak pth_rwlock_init
+# pragma weak pth_rwlock_acquire
+# pragma weak pth_rwlock_release
+# pragma weak pth_once
+
+# pragma weak pth_cancel
+# define pth_in_use() (pth_cancel != NULL)
+
+# else
+
+# define pth_in_use() 1
+
+# endif
+
+/* -------------------------- gl_lock_t datatype -------------------------- */
+
+typedef pth_mutex_t gl_lock_t;
+# define gl_lock_define(STORAGECLASS, NAME) \
+ STORAGECLASS pth_mutex_t NAME;
+# define gl_lock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
+# define gl_lock_initializer \
+ PTH_MUTEX_INIT
+# define gl_lock_init(NAME) \
+ if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
+# define gl_lock_lock(NAME) \
+ if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
+# define gl_lock_unlock(NAME) \
+ if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
+# define gl_lock_destroy(NAME) \
+ (void)(&NAME)
+
+/* ------------------------- gl_rwlock_t datatype ------------------------- */
+
+typedef pth_rwlock_t gl_rwlock_t;
+# define gl_rwlock_define(STORAGECLASS, NAME) \
+ STORAGECLASS pth_rwlock_t NAME;
+# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
+# define gl_rwlock_initializer \
+ PTH_RWLOCK_INIT
+# define gl_rwlock_init(NAME) \
+ if (pth_in_use() && !pth_rwlock_init (&NAME)) abort ()
+# define gl_rwlock_rdlock(NAME) \
+ if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RD, 0, NULL)) abort ()
+# define gl_rwlock_wrlock(NAME) \
+ if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RW, 0, NULL)) abort ()
+# define gl_rwlock_unlock(NAME) \
+ if (pth_in_use() && !pth_rwlock_release (&NAME)) abort ()
+# define gl_rwlock_destroy(NAME) \
+ (void)(&NAME)
+
+/* --------------------- gl_recursive_lock_t datatype --------------------- */
+
+/* In Pth, mutexes are recursive by default. */
+typedef pth_mutex_t gl_recursive_lock_t;
+# define gl_recursive_lock_define(STORAGECLASS, NAME) \
+ STORAGECLASS pth_mutex_t NAME;
+# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
+# define gl_recursive_lock_initializer \
+ PTH_MUTEX_INIT
+# define gl_recursive_lock_init(NAME) \
+ if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
+# define gl_recursive_lock_lock(NAME) \
+ if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
+# define gl_recursive_lock_unlock(NAME) \
+ if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
+# define gl_recursive_lock_destroy(NAME) \
+ (void)(&NAME)
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef pth_once_t gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+ STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
+# define gl_once(NAME, INITFUNCTION) \
+ do \
+ { \
+ if (pth_in_use ()) \
+ { \
+ void (*gl_once_temp) (void) = INITFUNCTION; \
+ if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \
+ abort (); \
+ } \
+ else \
+ { \
+ if (glthread_once_singlethreaded (&NAME)) \
+ INITFUNCTION (); \
+ } \
+ } \
+ while (0)
+extern void glthread_once_call (void *arg);
+extern int glthread_once_singlethreaded (pth_once_t *once_control);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_SOLARIS_THREADS
+
+/* Use the old Solaris threads library. */
+
+# include <thread.h>
+# include <synch.h>
+# include <stdlib.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if USE_SOLARIS_THREADS_WEAK
+
+/* Use weak references to the old Solaris threads library. */
+
+# pragma weak mutex_init
+# pragma weak mutex_lock
+# pragma weak mutex_unlock
+# pragma weak mutex_destroy
+# pragma weak rwlock_init
+# pragma weak rw_rdlock
+# pragma weak rw_wrlock
+# pragma weak rw_unlock
+# pragma weak rwlock_destroy
+# pragma weak thr_self
+
+# pragma weak thr_suspend
+# define thread_in_use() (thr_suspend != NULL)
+
+# else
+
+# define thread_in_use() 1
+
+# endif
+
+/* -------------------------- gl_lock_t datatype -------------------------- */
+
+typedef mutex_t gl_lock_t;
+# define gl_lock_define(STORAGECLASS, NAME) \
+ STORAGECLASS mutex_t NAME;
+# define gl_lock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS mutex_t NAME = gl_lock_initializer;
+# define gl_lock_initializer \
+ DEFAULTMUTEX
+# define gl_lock_init(NAME) \
+ if (thread_in_use () && mutex_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
+# define gl_lock_lock(NAME) \
+ if (thread_in_use () && mutex_lock (&NAME) != 0) abort ()
+# define gl_lock_unlock(NAME) \
+ if (thread_in_use () && mutex_unlock (&NAME) != 0) abort ()
+# define gl_lock_destroy(NAME) \
+ if (thread_in_use () && mutex_destroy (&NAME) != 0) abort ()
+
+/* ------------------------- gl_rwlock_t datatype ------------------------- */
+
+typedef rwlock_t gl_rwlock_t;
+# define gl_rwlock_define(STORAGECLASS, NAME) \
+ STORAGECLASS rwlock_t NAME;
+# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
+# define gl_rwlock_initializer \
+ DEFAULTRWLOCK
+# define gl_rwlock_init(NAME) \
+ if (thread_in_use () && rwlock_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
+# define gl_rwlock_rdlock(NAME) \
+ if (thread_in_use () && rw_rdlock (&NAME) != 0) abort ()
+# define gl_rwlock_wrlock(NAME) \
+ if (thread_in_use () && rw_wrlock (&NAME) != 0) abort ()
+# define gl_rwlock_unlock(NAME) \
+ if (thread_in_use () && rw_unlock (&NAME) != 0) abort ()
+# define gl_rwlock_destroy(NAME) \
+ if (thread_in_use () && rwlock_destroy (&NAME) != 0) abort ()
+
+/* --------------------- gl_recursive_lock_t datatype --------------------- */
+
+/* Old Solaris threads did not have recursive locks.
+ We have to implement them ourselves. */
+
+typedef struct
+ {
+ mutex_t mutex;
+ thread_t owner;
+ unsigned long depth;
+ }
+ gl_recursive_lock_t;
+# define gl_recursive_lock_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_recursive_lock_t NAME;
+# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
+# define gl_recursive_lock_initializer \
+ { DEFAULTMUTEX, (thread_t) 0, 0 }
+# define gl_recursive_lock_init(NAME) \
+ if (thread_in_use ()) glthread_recursive_lock_init (&NAME)
+# define gl_recursive_lock_lock(NAME) \
+ if (thread_in_use ()) glthread_recursive_lock_lock (&NAME)
+# define gl_recursive_lock_unlock(NAME) \
+ if (thread_in_use ()) glthread_recursive_lock_unlock (&NAME)
+# define gl_recursive_lock_destroy(NAME) \
+ if (thread_in_use ()) glthread_recursive_lock_destroy (&NAME)
+extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef struct
+ {
+ volatile int inited;
+ mutex_t mutex;
+ }
+ gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
+# define gl_once(NAME, INITFUNCTION) \
+ do \
+ { \
+ if (thread_in_use ()) \
+ { \
+ glthread_once (&NAME, INITFUNCTION); \
+ } \
+ else \
+ { \
+ if (glthread_once_singlethreaded (&NAME)) \
+ INITFUNCTION (); \
+ } \
+ } \
+ while (0)
+extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
+extern int glthread_once_singlethreaded (gl_once_t *once_control);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_WIN32_THREADS
+
+# include <windows.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
+ Semaphore types, because
+ - we need only to synchronize inside a single process (address space),
+ not inter-process locking,
+ - we don't need to support trylock operations. (TryEnterCriticalSection
+ does not work on Windows 95/98/ME. Packages that need trylock usually
+ define their own mutex type.) */
+
+/* There is no way to statically initialize a CRITICAL_SECTION. It needs
+ to be done lazily, once only. For this we need spinlocks. */
+
+typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
+
+/* -------------------------- gl_lock_t datatype -------------------------- */
+
+typedef struct
+ {
+ gl_spinlock_t guard; /* protects the initialization */
+ CRITICAL_SECTION lock;
+ }
+ gl_lock_t;
+# define gl_lock_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_lock_t NAME;
+# define gl_lock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
+# define gl_lock_initializer \
+ { { 0, -1 } }
+# define gl_lock_init(NAME) \
+ glthread_lock_init (&NAME)
+# define gl_lock_lock(NAME) \
+ glthread_lock_lock (&NAME)
+# define gl_lock_unlock(NAME) \
+ glthread_lock_unlock (&NAME)
+# define gl_lock_destroy(NAME) \
+ glthread_lock_destroy (&NAME)
+extern void glthread_lock_init (gl_lock_t *lock);
+extern void glthread_lock_lock (gl_lock_t *lock);
+extern void glthread_lock_unlock (gl_lock_t *lock);
+extern void glthread_lock_destroy (gl_lock_t *lock);
+
+/* ------------------------- gl_rwlock_t datatype ------------------------- */
+
+/* It is impossible to implement read-write locks using plain locks, without
+ introducing an extra thread dedicated to managing read-write locks.
+ Therefore here we need to use the low-level Event type. */
+
+typedef struct
+ {
+ HANDLE *array; /* array of waiting threads, each represented by an event */
+ unsigned int count; /* number of waiting threads */
+ unsigned int alloc; /* length of allocated array */
+ unsigned int offset; /* index of first waiting thread in array */
+ }
+ gl_waitqueue_t;
+typedef struct
+ {
+ gl_spinlock_t guard; /* protects the initialization */
+ CRITICAL_SECTION lock; /* protects the remaining fields */
+ gl_waitqueue_t waiting_readers; /* waiting readers */
+ gl_waitqueue_t waiting_writers; /* waiting writers */
+ int runcount; /* number of readers running, or -1 when a writer runs */
+ }
+ gl_rwlock_t;
+# define gl_rwlock_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_rwlock_t NAME;
+# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
+# define gl_rwlock_initializer \
+ { { 0, -1 } }
+# define gl_rwlock_init(NAME) \
+ glthread_rwlock_init (&NAME)
+# define gl_rwlock_rdlock(NAME) \
+ glthread_rwlock_rdlock (&NAME)
+# define gl_rwlock_wrlock(NAME) \
+ glthread_rwlock_wrlock (&NAME)
+# define gl_rwlock_unlock(NAME) \
+ glthread_rwlock_unlock (&NAME)
+# define gl_rwlock_destroy(NAME) \
+ glthread_rwlock_destroy (&NAME)
+extern void glthread_rwlock_init (gl_rwlock_t *lock);
+extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
+extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
+extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
+extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
+
+/* --------------------- gl_recursive_lock_t datatype --------------------- */
+
+/* The Win32 documentation says that CRITICAL_SECTION already implements a
+ recursive lock. But we need not rely on it: It's easy to implement a
+ recursive lock without this assumption. */
+
+typedef struct
+ {
+ gl_spinlock_t guard; /* protects the initialization */
+ DWORD owner;
+ unsigned long depth;
+ CRITICAL_SECTION lock;
+ }
+ gl_recursive_lock_t;
+# define gl_recursive_lock_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_recursive_lock_t NAME;
+# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
+# define gl_recursive_lock_initializer \
+ { { 0, -1 }, 0, 0 }
+# define gl_recursive_lock_init(NAME) \
+ glthread_recursive_lock_init (&NAME)
+# define gl_recursive_lock_lock(NAME) \
+ glthread_recursive_lock_lock (&NAME)
+# define gl_recursive_lock_unlock(NAME) \
+ glthread_recursive_lock_unlock (&NAME)
+# define gl_recursive_lock_destroy(NAME) \
+ glthread_recursive_lock_destroy (&NAME)
+extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
+extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef struct
+ {
+ volatile int inited;
+ volatile long started;
+ CRITICAL_SECTION lock;
+ }
+ gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_once_t NAME = { -1, -1 };
+# define gl_once(NAME, INITFUNCTION) \
+ glthread_once (&NAME, INITFUNCTION)
+extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
+
+/* ========================================================================= */
+
+#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
+
+/* Provide dummy implementation if threads are not supported. */
+
+/* -------------------------- gl_lock_t datatype -------------------------- */
+
+typedef int gl_lock_t;
+# define gl_lock_define(STORAGECLASS, NAME)
+# define gl_lock_define_initialized(STORAGECLASS, NAME)
+# define gl_lock_init(NAME)
+# define gl_lock_lock(NAME)
+# define gl_lock_unlock(NAME)
+
+/* ------------------------- gl_rwlock_t datatype ------------------------- */
+
+typedef int gl_rwlock_t;
+# define gl_rwlock_define(STORAGECLASS, NAME)
+# define gl_rwlock_define_initialized(STORAGECLASS, NAME)
+# define gl_rwlock_init(NAME)
+# define gl_rwlock_rdlock(NAME)
+# define gl_rwlock_wrlock(NAME)
+# define gl_rwlock_unlock(NAME)
+
+/* --------------------- gl_recursive_lock_t datatype --------------------- */
+
+typedef int gl_recursive_lock_t;
+# define gl_recursive_lock_define(STORAGECLASS, NAME)
+# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
+# define gl_recursive_lock_init(NAME)
+# define gl_recursive_lock_lock(NAME)
+# define gl_recursive_lock_unlock(NAME)
+
+/* -------------------------- gl_once_t datatype -------------------------- */
+
+typedef int gl_once_t;
+# define gl_once_define(STORAGECLASS, NAME) \
+ STORAGECLASS gl_once_t NAME = 0;
+# define gl_once(NAME, INITFUNCTION) \
+ do \
+ { \
+ if (NAME == 0) \
+ { \
+ NAME = ~ 0; \
+ INITFUNCTION (); \
+ } \
+ } \
+ while (0)
+
+#endif
+
+/* ========================================================================= */
+
+#endif /* _LOCK_H */
diff --git a/intl/log.c b/intl/log.c
new file mode 100644
index 000000000..e3ab5d0e6
--- /dev/null
+++ b/intl/log.c
@@ -0,0 +1,116 @@
+/* Log file output.
+ Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Written by Bruno Haible <bruno@clisp.org>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Handle multi-threaded applications. */
+#ifdef _LIBC
+# include <bits/libc-lock.h>
+#else
+# include "lock.h"
+#endif
+
+/* Print an ASCII string with quotes and escape sequences where needed. */
+static void
+print_escaped (FILE *stream, const char *str)
+{
+ putc ('"', stream);
+ for (; *str != '\0'; str++)
+ if (*str == '\n')
+ {
+ fputs ("\\n\"", stream);
+ if (str[1] == '\0')
+ return;
+ fputs ("\n\"", stream);
+ }
+ else
+ {
+ if (*str == '"' || *str == '\\')
+ putc ('\\', stream);
+ putc (*str, stream);
+ }
+ putc ('"', stream);
+}
+
+static char *last_logfilename = NULL;
+static FILE *last_logfile = NULL;
+__libc_lock_define_initialized (static, lock)
+
+static inline void
+_nl_log_untranslated_locked (const char *logfilename, const char *domainname,
+ const char *msgid1, const char *msgid2, int plural)
+{
+ FILE *logfile;
+
+ /* Can we reuse the last opened logfile? */
+ if (last_logfilename == NULL || strcmp (logfilename, last_logfilename) != 0)
+ {
+ /* Close the last used logfile. */
+ if (last_logfilename != NULL)
+ {
+ if (last_logfile != NULL)
+ {
+ fclose (last_logfile);
+ last_logfile = NULL;
+ }
+ free (last_logfilename);
+ last_logfilename = NULL;
+ }
+ /* Open the logfile. */
+ last_logfilename = (char *) malloc (strlen (logfilename) + 1);
+ if (last_logfilename == NULL)
+ return;
+ strcpy (last_logfilename, logfilename);
+ last_logfile = fopen (logfilename, "a");
+ if (last_logfile == NULL)
+ return;
+ }
+ logfile = last_logfile;
+
+ fprintf (logfile, "domain ");
+ print_escaped (logfile, domainname);
+ fprintf (logfile, "\nmsgid ");
+ print_escaped (logfile, msgid1);
+ if (plural)
+ {
+ fprintf (logfile, "\nmsgid_plural ");
+ print_escaped (logfile, msgid2);
+ fprintf (logfile, "\nmsgstr[0] \"\"\n");
+ }
+ else
+ fprintf (logfile, "\nmsgstr \"\"\n");
+ putc ('\n', logfile);
+}
+
+/* Add to the log file an entry denoting a failed translation. */
+void
+_nl_log_untranslated (const char *logfilename, const char *domainname,
+ const char *msgid1, const char *msgid2, int plural)
+{
+ __libc_lock_lock (lock);
+ _nl_log_untranslated_locked (logfilename, domainname, msgid1, msgid2, plural);
+ __libc_lock_unlock (lock);
+}
diff --git a/intl/ngettext.c b/intl/ngettext.c
new file mode 100644
index 000000000..a33529c20
--- /dev/null
+++ b/intl/ngettext.c
@@ -0,0 +1,65 @@
+/* Implementation of ngettext(3) function.
+ Copyright (C) 1995, 1997, 2000-2003 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define __need_NULL
+# include <stddef.h>
+#else
+# include <stdlib.h> /* Just for NULL. */
+#endif
+
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgnuintl.h"
+#endif
+
+#include <locale.h>
+
+/* @@ 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 NGETTEXT __ngettext
+# define DCNGETTEXT __dcngettext
+#else
+# define NGETTEXT libintl_ngettext
+# define DCNGETTEXT libintl_dcngettext
+#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 *
+NGETTEXT (const char *msgid1, const char *msgid2, unsigned long int n)
+{
+ return DCNGETTEXT (NULL, msgid1, msgid2, n, LC_MESSAGES);
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library. */
+weak_alias (__ngettext, ngettext);
+#endif
diff --git a/intl/os2compat.c b/intl/os2compat.c
new file mode 100644
index 000000000..d041de2af
--- /dev/null
+++ b/intl/os2compat.c
@@ -0,0 +1,98 @@
+/* OS/2 compatibility functions.
+ Copyright (C) 2001-2002 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#define OS2_AWARE
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+/* A version of getenv() that works from DLLs */
+extern unsigned long DosScanEnv (const unsigned char *pszName, unsigned char **ppszValue);
+
+char *
+_nl_getenv (const char *name)
+{
+ unsigned char *value;
+ if (DosScanEnv (name, &value))
+ return NULL;
+ else
+ return value;
+}
+
+/* A fixed size buffer. */
+char libintl_nl_default_dirname[MAXPATHLEN+1];
+
+char *_nlos2_libdir = NULL;
+char *_nlos2_localealiaspath = NULL;
+char *_nlos2_localedir = NULL;
+
+static __attribute__((constructor)) void
+nlos2_initialize ()
+{
+ char *root = getenv ("UNIXROOT");
+ char *gnulocaledir = getenv ("GNULOCALEDIR");
+
+ _nlos2_libdir = gnulocaledir;
+ if (!_nlos2_libdir)
+ {
+ if (root)
+ {
+ size_t sl = strlen (root);
+ _nlos2_libdir = (char *) malloc (sl + strlen (LIBDIR) + 1);
+ memcpy (_nlos2_libdir, root, sl);
+ memcpy (_nlos2_libdir + sl, LIBDIR, strlen (LIBDIR) + 1);
+ }
+ else
+ _nlos2_libdir = LIBDIR;
+ }
+
+ _nlos2_localealiaspath = gnulocaledir;
+ if (!_nlos2_localealiaspath)
+ {
+ if (root)
+ {
+ size_t sl = strlen (root);
+ _nlos2_localealiaspath = (char *) malloc (sl + strlen (LOCALE_ALIAS_PATH) + 1);
+ memcpy (_nlos2_localealiaspath, root, sl);
+ memcpy (_nlos2_localealiaspath + sl, LOCALE_ALIAS_PATH, strlen (LOCALE_ALIAS_PATH) + 1);
+ }
+ else
+ _nlos2_localealiaspath = LOCALE_ALIAS_PATH;
+ }
+
+ _nlos2_localedir = gnulocaledir;
+ if (!_nlos2_localedir)
+ {
+ if (root)
+ {
+ size_t sl = strlen (root);
+ _nlos2_localedir = (char *) malloc (sl + strlen (LOCALEDIR) + 1);
+ memcpy (_nlos2_localedir, root, sl);
+ memcpy (_nlos2_localedir + sl, LOCALEDIR, strlen (LOCALEDIR) + 1);
+ }
+ else
+ _nlos2_localedir = LOCALEDIR;
+ }
+
+ if (strlen (_nlos2_localedir) <= MAXPATHLEN)
+ strcpy (libintl_nl_default_dirname, _nlos2_localedir);
+}
diff --git a/intl/os2compat.h b/intl/os2compat.h
new file mode 100644
index 000000000..a18d582cd
--- /dev/null
+++ b/intl/os2compat.h
@@ -0,0 +1,46 @@
+/* OS/2 compatibility defines.
+ This file is intended to be included from config.h
+ Copyright (C) 2001-2002 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* When included from os2compat.h we need all the original definitions */
+#ifndef OS2_AWARE
+
+#undef LIBDIR
+#define LIBDIR _nlos2_libdir
+extern char *_nlos2_libdir;
+
+#undef LOCALEDIR
+#define LOCALEDIR _nlos2_localedir
+extern char *_nlos2_localedir;
+
+#undef LOCALE_ALIAS_PATH
+#define LOCALE_ALIAS_PATH _nlos2_localealiaspath
+extern char *_nlos2_localealiaspath;
+
+#endif
+
+#undef HAVE_STRCASECMP
+#define HAVE_STRCASECMP 1
+#define strcasecmp stricmp
+#define strncasecmp strnicmp
+
+/* We have our own getenv() which works even if library is compiled as DLL */
+#define getenv _nl_getenv
+
+/* Older versions of gettext used -1 as the value of LC_MESSAGES */
+#define LC_MESSAGES_COMPAT (-1)
diff --git a/intl/osdep.c b/intl/osdep.c
new file mode 100644
index 000000000..3cc35c03b
--- /dev/null
+++ b/intl/osdep.c
@@ -0,0 +1,26 @@
+/* OS dependent parts of libintl.
+ Copyright (C) 2001-2002, 2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#if defined __CYGWIN__
+# include "intl-exports.c"
+#elif defined __EMX__
+# include "os2compat.c"
+#else
+/* Avoid AIX compiler warning. */
+typedef int dummy;
+#endif
diff --git a/intl/plural-exp.c b/intl/plural-exp.c
new file mode 100644
index 000000000..f518bf1dc
--- /dev/null
+++ b/intl/plural-exp.c
@@ -0,0 +1,154 @@
+/* Expression parsing for plural form selection.
+ Copyright (C) 2000-2001, 2003, 2005 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "plural-exp.h"
+
+#if (defined __GNUC__ && !(__APPLE_CC__ > 1)) \
+ || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+
+/* These structs are the constant expression for the germanic plural
+ form determination. It represents the expression "n != 1". */
+static const struct expression plvar =
+{
+ .nargs = 0,
+ .operation = var,
+};
+static const struct expression plone =
+{
+ .nargs = 0,
+ .operation = num,
+ .val =
+ {
+ .num = 1
+ }
+};
+struct expression GERMANIC_PLURAL =
+{
+ .nargs = 2,
+ .operation = not_equal,
+ .val =
+ {
+ .args =
+ {
+ [0] = (struct expression *) &plvar,
+ [1] = (struct expression *) &plone
+ }
+ }
+};
+
+# define INIT_GERMANIC_PLURAL()
+
+#else
+
+/* For compilers without support for ISO C 99 struct/union initializers:
+ Initialization at run-time. */
+
+static struct expression plvar;
+static struct expression plone;
+struct expression GERMANIC_PLURAL;
+
+static void
+init_germanic_plural ()
+{
+ if (plone.val.num == 0)
+ {
+ plvar.nargs = 0;
+ plvar.operation = var;
+
+ plone.nargs = 0;
+ plone.operation = num;
+ plone.val.num = 1;
+
+ GERMANIC_PLURAL.nargs = 2;
+ GERMANIC_PLURAL.operation = not_equal;
+ GERMANIC_PLURAL.val.args[0] = &plvar;
+ GERMANIC_PLURAL.val.args[1] = &plone;
+ }
+}
+
+# define INIT_GERMANIC_PLURAL() init_germanic_plural ()
+
+#endif
+
+void
+internal_function
+EXTRACT_PLURAL_EXPRESSION (const char *nullentry, struct expression **pluralp,
+ unsigned long int *npluralsp)
+{
+ if (nullentry != NULL)
+ {
+ const char *plural;
+ const char *nplurals;
+
+ plural = strstr (nullentry, "plural=");
+ nplurals = strstr (nullentry, "nplurals=");
+ if (plural == NULL || nplurals == NULL)
+ goto no_plural;
+ else
+ {
+ char *endp;
+ unsigned long int n;
+ struct parse_args args;
+
+ /* First get the number. */
+ nplurals += 9;
+ while (*nplurals != '\0' && isspace ((unsigned char) *nplurals))
+ ++nplurals;
+ if (!(*nplurals >= '0' && *nplurals <= '9'))
+ goto no_plural;
+#if defined HAVE_STRTOUL || defined _LIBC
+ n = strtoul (nplurals, &endp, 10);
+#else
+ for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
+ n = n * 10 + (*endp - '0');
+#endif
+ if (nplurals == endp)
+ goto no_plural;
+ *npluralsp = n;
+
+ /* Due to the restrictions bison imposes onto the interface of the
+ scanner function we have to put the input string and the result
+ passed up from the parser into the same structure which address
+ is passed down to the parser. */
+ plural += 7;
+ args.cp = plural;
+ if (PLURAL_PARSE (&args) != 0)
+ goto no_plural;
+ *pluralp = args.res;
+ }
+ }
+ else
+ {
+ /* By default we are using the Germanic form: singular form only
+ for `one', the plural form otherwise. Yes, this is also what
+ English is using since English is a Germanic language. */
+ no_plural:
+ INIT_GERMANIC_PLURAL ();
+ *pluralp = &GERMANIC_PLURAL;
+ *npluralsp = 2;
+ }
+}
diff --git a/intl/plural-exp.h b/intl/plural-exp.h
new file mode 100644
index 000000000..dc590d374
--- /dev/null
+++ b/intl/plural-exp.h
@@ -0,0 +1,118 @@
+/* Expression parsing and evaluation for plural form selection.
+ Copyright (C) 2000-2003, 2005 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _PLURAL_EXP_H
+#define _PLURAL_EXP_H
+
+#ifndef internal_function
+# define internal_function
+#endif
+
+#ifndef attribute_hidden
+# define attribute_hidden
+#endif
+
+
+/* This is the representation of the expressions to determine the
+ plural form. */
+struct expression
+{
+ int nargs; /* Number of arguments. */
+ enum operator
+ {
+ /* Without arguments: */
+ var, /* The variable "n". */
+ num, /* Decimal number. */
+ /* Unary operators: */
+ lnot, /* Logical NOT. */
+ /* Binary operators: */
+ mult, /* Multiplication. */
+ divide, /* Division. */
+ module, /* Modulo operation. */
+ plus, /* Addition. */
+ minus, /* Subtraction. */
+ less_than, /* Comparison. */
+ greater_than, /* Comparison. */
+ less_or_equal, /* Comparison. */
+ greater_or_equal, /* Comparison. */
+ equal, /* Comparison for equality. */
+ not_equal, /* Comparison for inequality. */
+ land, /* Logical AND. */
+ lor, /* Logical OR. */
+ /* Ternary operators: */
+ qmop /* Question mark operator. */
+ } operation;
+ union
+ {
+ unsigned long int num; /* Number value for `num'. */
+ struct expression *args[3]; /* Up to three arguments. */
+ } val;
+};
+
+/* This is the data structure to pass information to the parser and get
+ the result in a thread-safe way. */
+struct parse_args
+{
+ const char *cp;
+ struct expression *res;
+};
+
+
+/* Names for the libintl functions are a problem. This source code is used
+ 1. in the GNU C Library library,
+ 2. in the GNU libintl library,
+ 3. in the GNU gettext tools.
+ The function names in each situation must be different, to allow for
+ binary incompatible changes in 'struct expression'. Furthermore,
+ 1. in the GNU C Library library, the names have a __ prefix,
+ 2.+3. in the GNU libintl library and in the GNU gettext tools, the names
+ must follow ANSI C and not start with __.
+ So we have to distinguish the three cases. */
+#ifdef _LIBC
+# define FREE_EXPRESSION __gettext_free_exp
+# define PLURAL_PARSE __gettextparse
+# define GERMANIC_PLURAL __gettext_germanic_plural
+# define EXTRACT_PLURAL_EXPRESSION __gettext_extract_plural
+#elif defined (IN_LIBINTL)
+# define FREE_EXPRESSION libintl_gettext_free_exp
+# define PLURAL_PARSE libintl_gettextparse
+# define GERMANIC_PLURAL libintl_gettext_germanic_plural
+# define EXTRACT_PLURAL_EXPRESSION libintl_gettext_extract_plural
+#else
+# define FREE_EXPRESSION free_plural_expression
+# define PLURAL_PARSE parse_plural_expression
+# define GERMANIC_PLURAL germanic_plural
+# define EXTRACT_PLURAL_EXPRESSION extract_plural_expression
+#endif
+
+extern void FREE_EXPRESSION (struct expression *exp)
+ internal_function;
+extern int PLURAL_PARSE (void *arg);
+extern struct expression GERMANIC_PLURAL attribute_hidden;
+extern void EXTRACT_PLURAL_EXPRESSION (const char *nullentry,
+ struct expression **pluralp,
+ unsigned long int *npluralsp)
+ internal_function;
+
+#if !defined (_LIBC) && !defined (IN_LIBINTL) && !defined (IN_LIBGLOCALE)
+extern unsigned long int plural_eval (struct expression *pexp,
+ unsigned long int n);
+#endif
+
+#endif /* _PLURAL_EXP_H */
diff --git a/intl/plural.c b/intl/plural.c
new file mode 100644
index 000000000..5f73b403f
--- /dev/null
+++ b/intl/plural.c
@@ -0,0 +1,1492 @@
+/* A Bison parser, made from plural.y
+ by GNU bison 1.35. */
+
+#define YYBISON 1 /* Identify Bison output. */
+
+#define yyparse __gettextparse
+#define yylex __gettextlex
+#define yyerror __gettexterror
+#define yylval __gettextlval
+#define yychar __gettextchar
+#define yydebug __gettextdebug
+#define yynerrs __gettextnerrs
+# define EQUOP2 257
+# define CMPOP2 258
+# define ADDOP2 259
+# define MULOP2 260
+# define NUMBER 261
+
+#line 1 "plural.y"
+
+/* Expression parsing for plural form selection.
+ Copyright (C) 2000-2001, 2003, 2005 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* For bison < 2.0, the bison generated parser uses alloca. AIX 3 forces us
+ to put this declaration at the beginning of the file. The declaration in
+ bison's skeleton file comes too late. This must come before <config.h>
+ because <config.h> may include arbitrary system headers.
+ This can go away once the AM_INTL_SUBDIR macro requires bison >= 2.0. */
+#if defined _AIX && !defined __GNUC__
+ #pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include "plural-exp.h"
+
+/* The main function generated by the parser is called __gettextparse,
+ but we want it to be called PLURAL_PARSE. */
+#ifndef _LIBC
+# define __gettextparse PLURAL_PARSE
+#endif
+
+#define YYLEX_PARAM &((struct parse_args *) arg)->cp
+#define YYPARSE_PARAM arg
+
+#line 51 "plural.y"
+#ifndef YYSTYPE
+typedef union {
+ unsigned long int num;
+ enum operator op;
+ struct expression *exp;
+} yystype;
+# define YYSTYPE yystype
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+#line 57 "plural.y"
+
+/* Prototypes for local functions. */
+static int yylex (YYSTYPE *lval, const char **pexp);
+static void yyerror (const char *str);
+
+/* Allocation of expressions. */
+
+static struct expression *
+new_exp (int nargs, enum operator op, struct expression * const *args)
+{
+ int i;
+ struct expression *newp;
+
+ /* If any of the argument could not be malloc'ed, just return NULL. */
+ for (i = nargs - 1; i >= 0; i--)
+ if (args[i] == NULL)
+ goto fail;
+
+ /* Allocate a new expression. */
+ newp = (struct expression *) malloc (sizeof (*newp));
+ if (newp != NULL)
+ {
+ newp->nargs = nargs;
+ newp->operation = op;
+ for (i = nargs - 1; i >= 0; i--)
+ newp->val.args[i] = args[i];
+ return newp;
+ }
+
+ fail:
+ for (i = nargs - 1; i >= 0; i--)
+ FREE_EXPRESSION (args[i]);
+
+ return NULL;
+}
+
+static inline struct expression *
+new_exp_0 (enum operator op)
+{
+ return new_exp (0, op, NULL);
+}
+
+static inline struct expression *
+new_exp_1 (enum operator op, struct expression *right)
+{
+ struct expression *args[1];
+
+ args[0] = right;
+ return new_exp (1, op, args);
+}
+
+static struct expression *
+new_exp_2 (enum operator op, struct expression *left, struct expression *right)
+{
+ struct expression *args[2];
+
+ args[0] = left;
+ args[1] = right;
+ return new_exp (2, op, args);
+}
+
+static inline struct expression *
+new_exp_3 (enum operator op, struct expression *bexp,
+ struct expression *tbranch, struct expression *fbranch)
+{
+ struct expression *args[3];
+
+ args[0] = bexp;
+ args[1] = tbranch;
+ args[2] = fbranch;
+ return new_exp (3, op, args);
+}
+
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+
+
+#define YYFINAL 27
+#define YYFLAG -32768
+#define YYNTBASE 16
+
+/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */
+#define YYTRANSLATE(x) ((unsigned)(x) <= 261 ? yytranslate[x] : 18)
+
+/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */
+static const char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 10, 2, 2, 2, 2, 5, 2,
+ 14, 15, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 12, 2,
+ 2, 2, 2, 3, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 13, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 4, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 6, 7, 8,
+ 9, 11
+};
+
+#if YYDEBUG
+static const short yyprhs[] =
+{
+ 0, 0, 2, 8, 12, 16, 20, 24, 28, 32,
+ 35, 37, 39
+};
+static const short yyrhs[] =
+{
+ 17, 0, 17, 3, 17, 12, 17, 0, 17, 4,
+ 17, 0, 17, 5, 17, 0, 17, 6, 17, 0,
+ 17, 7, 17, 0, 17, 8, 17, 0, 17, 9,
+ 17, 0, 10, 17, 0, 13, 0, 11, 0, 14,
+ 17, 15, 0
+};
+
+#endif
+
+#if YYDEBUG
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const short yyrline[] =
+{
+ 0, 152, 160, 164, 168, 172, 176, 180, 184, 188,
+ 192, 196, 201
+};
+#endif
+
+
+#if (YYDEBUG) || defined YYERROR_VERBOSE
+
+/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */
+static const char *const yytname[] =
+{
+ "$", "error", "$undefined.", "'?'", "'|'", "'&'", "EQUOP2", "CMPOP2",
+ "ADDOP2", "MULOP2", "'!'", "NUMBER", "':'", "'n'", "'('", "')'",
+ "start", "exp", 0
+};
+#endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const short yyr1[] =
+{
+ 0, 16, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const short yyr2[] =
+{
+ 0, 1, 5, 3, 3, 3, 3, 3, 3, 2,
+ 1, 1, 3
+};
+
+/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE
+ doesn't specify something else to do. Zero means the default is an
+ error. */
+static const short yydefact[] =
+{
+ 0, 0, 11, 10, 0, 1, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 12, 0, 3, 4, 5,
+ 6, 7, 8, 0, 2, 0, 0, 0
+};
+
+static const short yydefgoto[] =
+{
+ 25, 5
+};
+
+static const short yypact[] =
+{
+ -9, -9,-32768,-32768, -9, 34,-32768, 11, -9, -9,
+ -9, -9, -9, -9, -9,-32768, 24, 39, 43, 16,
+ 26, -3,-32768, -9, 34, 21, 53,-32768
+};
+
+static const short yypgoto[] =
+{
+ -32768, -1
+};
+
+
+#define YYLAST 53
+
+
+static const short yytable[] =
+{
+ 6, 1, 2, 7, 3, 4, 14, 16, 17, 18,
+ 19, 20, 21, 22, 8, 9, 10, 11, 12, 13,
+ 14, 26, 24, 12, 13, 14, 15, 8, 9, 10,
+ 11, 12, 13, 14, 13, 14, 23, 8, 9, 10,
+ 11, 12, 13, 14, 10, 11, 12, 13, 14, 11,
+ 12, 13, 14, 27
+};
+
+static const short yycheck[] =
+{
+ 1, 10, 11, 4, 13, 14, 9, 8, 9, 10,
+ 11, 12, 13, 14, 3, 4, 5, 6, 7, 8,
+ 9, 0, 23, 7, 8, 9, 15, 3, 4, 5,
+ 6, 7, 8, 9, 8, 9, 12, 3, 4, 5,
+ 6, 7, 8, 9, 5, 6, 7, 8, 9, 6,
+ 7, 8, 9, 0
+};
+#define YYPURE 1
+
+/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
+#line 3 "bison.simple"
+
+/* Skeleton output parser for bison,
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 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. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* This is the parser code that is written into each bison parser when
+ the %semantic_parser declaration is not specified in the grammar.
+ It was written by Richard Stallman by simplifying the hairy parser
+ used when %semantic_parser is specified. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE)
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# else
+# ifndef YYSTACK_USE_ALLOCA
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC malloc
+# define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+# if YYLSP_NEEDED
+ YYLTYPE yyls;
+# endif
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# if YYLSP_NEEDED
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+ + 2 * YYSTACK_GAP_MAX)
+# else
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAX)
+# endif
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY -2
+#define YYEOF 0
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrlab1
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+#define YYFAIL goto yyerrlab
+#define YYRECOVERING() (!!yyerrstatus)
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yychar1 = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up"); \
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run).
+
+ When YYLLOC_DEFAULT is run, CURRENT is set the location of the
+ first token. By default, to implement support for ranges, extend
+ its range to the last symbol. */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#if YYPURE
+# if YYLSP_NEEDED
+# ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+# else
+# define YYLEX yylex (&yylval, &yylloc)
+# endif
+# else /* !YYLSP_NEEDED */
+# ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+# else
+# define YYLEX yylex (&yylval)
+# endif
+# endif /* !YYLSP_NEEDED */
+#else /* !YYPURE */
+# define YYLEX yylex ()
+#endif /* !YYPURE */
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+#endif /* !YYDEBUG */
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+#ifdef YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+#endif
+
+#line 315 "bison.simple"
+
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+ into yyparse. The argument should have type void *.
+ It should actually point to an object.
+ Grammar actions can access the variable by casting it
+ to the proper pointer type. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+# define YYPARSE_PARAM_DECL
+# else
+# define YYPARSE_PARAM_ARG YYPARSE_PARAM
+# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+# endif
+#else /* !YYPARSE_PARAM */
+# define YYPARSE_PARAM_ARG
+# define YYPARSE_PARAM_DECL
+#endif /* !YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes. */
+#ifdef __GNUC__
+# ifdef YYPARSE_PARAM
+int yyparse (void *);
+# else
+int yyparse (void);
+# endif
+#endif
+
+/* YY_DECL_VARIABLES -- depending whether we use a pure parser,
+ variables are global, or local to YYPARSE. */
+
+#define YY_DECL_NON_LSP_VARIABLES \
+/* The lookahead symbol. */ \
+int yychar; \
+ \
+/* The semantic value of the lookahead symbol. */ \
+YYSTYPE yylval; \
+ \
+/* Number of parse errors so far. */ \
+int yynerrs;
+
+#if YYLSP_NEEDED
+# define YY_DECL_VARIABLES \
+YY_DECL_NON_LSP_VARIABLES \
+ \
+/* Location data for the lookahead symbol. */ \
+YYLTYPE yylloc;
+#else
+# define YY_DECL_VARIABLES \
+YY_DECL_NON_LSP_VARIABLES
+#endif
+
+
+/* If nonreentrant, generate the variables here. */
+
+#if !YYPURE
+YY_DECL_VARIABLES
+#endif /* !YYPURE */
+
+int
+yyparse (YYPARSE_PARAM_ARG)
+ YYPARSE_PARAM_DECL
+{
+ /* If reentrant, generate the variables here. */
+#if YYPURE
+ YY_DECL_VARIABLES
+#endif /* !YYPURE */
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yychar1 = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+#if YYLSP_NEEDED
+ /* The location stack. */
+ YYLTYPE yylsa[YYINITDEPTH];
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp;
+#endif
+
+#if YYLSP_NEEDED
+# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
+#else
+# define YYPOPSTACK (yyvsp--, yyssp--)
+#endif
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+#if YYLSP_NEEDED
+ YYLTYPE yyloc;
+#endif
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+#if YYLSP_NEEDED
+ yylsp = yyls;
+#endif
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. */
+# if YYLSP_NEEDED
+ YYLTYPE *yyls1 = yyls;
+ /* This used to be a conditional around just the two extra args,
+ but that might be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yyls1, yysize * sizeof (*yylsp),
+ &yystacksize);
+ yyls = yyls1;
+# else
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+# endif
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (yystacksize >= YYMAXDEPTH)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (yystacksize > YYMAXDEPTH)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+# if YYLSP_NEEDED
+ YYSTACK_RELOCATE (yyls);
+# endif
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+#if YYLSP_NEEDED
+ yylsp = yyls + yysize - 1;
+#endif
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyssp >= yyss + yystacksize - 1)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* yychar is either YYEMPTY or YYEOF
+ or a valid token in external form. */
+
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ /* Convert token to internal form (in yychar1) for indexing tables with */
+
+ if (yychar <= 0) /* This means end of input. */
+ {
+ yychar1 = 0;
+ yychar = YYEOF; /* Don't call YYLEX any more */
+
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yychar1 = YYTRANSLATE (yychar);
+
+#if YYDEBUG
+ /* We have to keep this `#if YYDEBUG', since we use variables
+ which are defined only if `YYDEBUG' is set. */
+ if (yydebug)
+ {
+ YYFPRINTF (stderr, "Next token is %d (%s",
+ yychar, yytname[yychar1]);
+ /* Give the individual parser a way to print the precise
+ meaning of a token, for further debugging info. */
+# ifdef YYPRINT
+ YYPRINT (stderr, yychar, yylval);
+# endif
+ YYFPRINTF (stderr, ")\n");
+ }
+#endif
+ }
+
+ yyn += yychar1;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+ goto yydefault;
+
+ yyn = yytable[yyn];
+
+ /* yyn is what to do for this token type in this state.
+ Negative => reduce, -yyn is rule number.
+ Positive => shift, yyn is new state.
+ New state is final state => don't bother to shift,
+ just return success.
+ 0, or most negative number => error. */
+
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrlab;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %d (%s), ",
+ yychar, yytname[yychar1]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+#if YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to the semantic value of
+ the lookahead token. This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+#if YYLSP_NEEDED
+ /* Similarly for the default location. Let the user run additional
+ commands if for instance locations are ranges. */
+ yyloc = yylsp[1-yylen];
+ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+#endif
+
+#if YYDEBUG
+ /* We have to keep this `#if YYDEBUG', since we use variables which
+ are defined only if `YYDEBUG' is set. */
+ if (yydebug)
+ {
+ int yyi;
+
+ YYFPRINTF (stderr, "Reducing via rule %d (line %d), ",
+ yyn, yyrline[yyn]);
+
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
+ YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+ }
+#endif
+
+ switch (yyn) {
+
+case 1:
+#line 153 "plural.y"
+{
+ if (yyvsp[0].exp == NULL)
+ YYABORT;
+ ((struct parse_args *) arg)->res = yyvsp[0].exp;
+ }
+ break;
+case 2:
+#line 161 "plural.y"
+{
+ yyval.exp = new_exp_3 (qmop, yyvsp[-4].exp, yyvsp[-2].exp, yyvsp[0].exp);
+ }
+ break;
+case 3:
+#line 165 "plural.y"
+{
+ yyval.exp = new_exp_2 (lor, yyvsp[-2].exp, yyvsp[0].exp);
+ }
+ break;
+case 4:
+#line 169 "plural.y"
+{
+ yyval.exp = new_exp_2 (land, yyvsp[-2].exp, yyvsp[0].exp);
+ }
+ break;
+case 5:
+#line 173 "plural.y"
+{
+ yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp);
+ }
+ break;
+case 6:
+#line 177 "plural.y"
+{
+ yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp);
+ }
+ break;
+case 7:
+#line 181 "plural.y"
+{
+ yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp);
+ }
+ break;
+case 8:
+#line 185 "plural.y"
+{
+ yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp);
+ }
+ break;
+case 9:
+#line 189 "plural.y"
+{
+ yyval.exp = new_exp_1 (lnot, yyvsp[0].exp);
+ }
+ break;
+case 10:
+#line 193 "plural.y"
+{
+ yyval.exp = new_exp_0 (var);
+ }
+ break;
+case 11:
+#line 197 "plural.y"
+{
+ if ((yyval.exp = new_exp_0 (num)) != NULL)
+ yyval.exp->val.num = yyvsp[0].num;
+ }
+ break;
+case 12:
+#line 202 "plural.y"
+{
+ yyval.exp = yyvsp[-1].exp;
+ }
+ break;
+}
+
+#line 705 "bison.simple"
+
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+#if YYLSP_NEEDED
+ yylsp -= yylen;
+#endif
+
+#if YYDEBUG
+ if (yydebug)
+ {
+ short *yyssp1 = yyss - 1;
+ YYFPRINTF (stderr, "state stack now");
+ while (yyssp1 != yyssp)
+ YYFPRINTF (stderr, " %d", *++yyssp1);
+ YYFPRINTF (stderr, "\n");
+ }
+#endif
+
+ *++yyvsp = yyval;
+#if YYLSP_NEEDED
+ *++yylsp = yyloc;
+#endif
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+ if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTBASE];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (yyn > YYFLAG && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ char *yymsg;
+ int yyx, yycount;
+
+ yycount = 0;
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+ if (yycheck[yyx + yyn] == yyx)
+ yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+ yysize += yystrlen ("parse error, unexpected ") + 1;
+ yysize += yystrlen (yytname[YYTRANSLATE (yychar)]);
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "parse error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]);
+
+ if (yycount < 5)
+ {
+ yycount = 0;
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *));
+ yyx++)
+ if (yycheck[yyx + yyn] == yyx)
+ {
+ const char *yyq = ! yycount ? ", expecting " : " or ";
+ yyp = yystpcpy (yyp, yyq);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yycount++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("parse error; also virtual memory exhausted");
+ }
+ else
+#endif /* defined (YYERROR_VERBOSE) */
+ yyerror ("parse error");
+ }
+ goto yyerrlab1;
+
+
+/*--------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action |
+`--------------------------------------------------*/
+yyerrlab1:
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ /* return failure if at end of input */
+ if (yychar == YYEOF)
+ YYABORT;
+ YYDPRINTF ((stderr, "Discarding token %d (%s).\n",
+ yychar, yytname[yychar1]));
+ yychar = YYEMPTY;
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+
+ yyerrstatus = 3; /* Each real token shifted decrements this */
+
+ goto yyerrhandle;
+
+
+/*-------------------------------------------------------------------.
+| yyerrdefault -- current state does not do anything special for the |
+| error token. |
+`-------------------------------------------------------------------*/
+yyerrdefault:
+#if 0
+ /* This is wrong; only states that explicitly want error tokens
+ should shift them. */
+
+ /* If its default is to accept any token, ok. Otherwise pop it. */
+ yyn = yydefact[yystate];
+ if (yyn)
+ goto yydefault;
+#endif
+
+
+/*---------------------------------------------------------------.
+| yyerrpop -- pop the current state because it cannot handle the |
+| error token |
+`---------------------------------------------------------------*/
+yyerrpop:
+ if (yyssp == yyss)
+ YYABORT;
+ yyvsp--;
+ yystate = *--yyssp;
+#if YYLSP_NEEDED
+ yylsp--;
+#endif
+
+#if YYDEBUG
+ if (yydebug)
+ {
+ short *yyssp1 = yyss - 1;
+ YYFPRINTF (stderr, "Error: state stack now");
+ while (yyssp1 != yyssp)
+ YYFPRINTF (stderr, " %d", *++yyssp1);
+ YYFPRINTF (stderr, "\n");
+ }
+#endif
+
+/*--------------.
+| yyerrhandle. |
+`--------------*/
+yyerrhandle:
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yyerrdefault;
+
+ yyn += YYTERROR;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+ goto yyerrdefault;
+
+ yyn = yytable[yyn];
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrpop;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrpop;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+#if YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+/*---------------------------------------------.
+| yyoverflowab -- parser overflow comes here. |
+`---------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+#line 207 "plural.y"
+
+
+void
+internal_function
+FREE_EXPRESSION (struct expression *exp)
+{
+ if (exp == NULL)
+ return;
+
+ /* Handle the recursive case. */
+ switch (exp->nargs)
+ {
+ case 3:
+ FREE_EXPRESSION (exp->val.args[2]);
+ /* FALLTHROUGH */
+ case 2:
+ FREE_EXPRESSION (exp->val.args[1]);
+ /* FALLTHROUGH */
+ case 1:
+ FREE_EXPRESSION (exp->val.args[0]);
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+
+ free (exp);
+}
+
+
+static int
+yylex (YYSTYPE *lval, const char **pexp)
+{
+ const char *exp = *pexp;
+ int result;
+
+ while (1)
+ {
+ if (exp[0] == '\0')
+ {
+ *pexp = exp;
+ return YYEOF;
+ }
+
+ if (exp[0] != ' ' && exp[0] != '\t')
+ break;
+
+ ++exp;
+ }
+
+ result = *exp++;
+ switch (result)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ unsigned long int n = result - '0';
+ while (exp[0] >= '0' && exp[0] <= '9')
+ {
+ n *= 10;
+ n += exp[0] - '0';
+ ++exp;
+ }
+ lval->num = n;
+ result = NUMBER;
+ }
+ break;
+
+ case '=':
+ if (exp[0] == '=')
+ {
+ ++exp;
+ lval->op = equal;
+ result = EQUOP2;
+ }
+ else
+ result = YYERRCODE;
+ break;
+
+ case '!':
+ if (exp[0] == '=')
+ {
+ ++exp;
+ lval->op = not_equal;
+ result = EQUOP2;
+ }
+ break;
+
+ case '&':
+ case '|':
+ if (exp[0] == result)
+ ++exp;
+ else
+ result = YYERRCODE;
+ break;
+
+ case '<':
+ if (exp[0] == '=')
+ {
+ ++exp;
+ lval->op = less_or_equal;
+ }
+ else
+ lval->op = less_than;
+ result = CMPOP2;
+ break;
+
+ case '>':
+ if (exp[0] == '=')
+ {
+ ++exp;
+ lval->op = greater_or_equal;
+ }
+ else
+ lval->op = greater_than;
+ result = CMPOP2;
+ break;
+
+ case '*':
+ lval->op = mult;
+ result = MULOP2;
+ break;
+
+ case '/':
+ lval->op = divide;
+ result = MULOP2;
+ break;
+
+ case '%':
+ lval->op = module;
+ result = MULOP2;
+ break;
+
+ case '+':
+ lval->op = plus;
+ result = ADDOP2;
+ break;
+
+ case '-':
+ lval->op = minus;
+ result = ADDOP2;
+ break;
+
+ case 'n':
+ case '?':
+ case ':':
+ case '(':
+ case ')':
+ /* Nothing, just return the character. */
+ break;
+
+ case ';':
+ case '\n':
+ case '\0':
+ /* Be safe and let the user call this function again. */
+ --exp;
+ result = YYEOF;
+ break;
+
+ default:
+ result = YYERRCODE;
+#if YYDEBUG != 0
+ --exp;
+#endif
+ break;
+ }
+
+ *pexp = exp;
+
+ return result;
+}
+
+
+static void
+yyerror (const char *str)
+{
+ /* Do nothing. We don't print error messages here. */
+}
diff --git a/intl/printf-args.c b/intl/printf-args.c
new file mode 100644
index 000000000..ee0faba16
--- /dev/null
+++ b/intl/printf-args.c
@@ -0,0 +1,142 @@
+/* Decomposed printf argument list.
+ Copyright (C) 1999, 2002-2003, 2005-2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#include <config.h>
+
+/* Specification. */
+#include "printf-args.h"
+
+#ifdef STATIC
+STATIC
+#endif
+int
+printf_fetchargs (va_list args, arguments *a)
+{
+ size_t i;
+ argument *ap;
+
+ for (i = 0, ap = &a->arg[0]; i < a->count; i++, ap++)
+ switch (ap->type)
+ {
+ case TYPE_SCHAR:
+ ap->a.a_schar = va_arg (args, /*signed char*/ int);
+ break;
+ case TYPE_UCHAR:
+ ap->a.a_uchar = va_arg (args, /*unsigned char*/ int);
+ break;
+ case TYPE_SHORT:
+ ap->a.a_short = va_arg (args, /*short*/ int);
+ break;
+ case TYPE_USHORT:
+ ap->a.a_ushort = va_arg (args, /*unsigned short*/ int);
+ break;
+ case TYPE_INT:
+ ap->a.a_int = va_arg (args, int);
+ break;
+ case TYPE_UINT:
+ ap->a.a_uint = va_arg (args, unsigned int);
+ break;
+ case TYPE_LONGINT:
+ ap->a.a_longint = va_arg (args, long int);
+ break;
+ case TYPE_ULONGINT:
+ ap->a.a_ulongint = va_arg (args, unsigned long int);
+ break;
+#ifdef HAVE_LONG_LONG_INT
+ case TYPE_LONGLONGINT:
+ ap->a.a_longlongint = va_arg (args, long long int);
+ break;
+ case TYPE_ULONGLONGINT:
+ ap->a.a_ulonglongint = va_arg (args, unsigned long long int);
+ break;
+#endif
+ case TYPE_DOUBLE:
+ ap->a.a_double = va_arg (args, double);
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case TYPE_LONGDOUBLE:
+ ap->a.a_longdouble = va_arg (args, long double);
+ break;
+#endif
+ case TYPE_CHAR:
+ ap->a.a_char = va_arg (args, int);
+ break;
+#ifdef HAVE_WINT_T
+ case TYPE_WIDE_CHAR:
+ /* Although ISO C 99 7.24.1.(2) says that wint_t is "unchanged by
+ default argument promotions", this is not the case in mingw32,
+ where wint_t is 'unsigned short'. */
+ ap->a.a_wide_char =
+ (sizeof (wint_t) < sizeof (int)
+ ? va_arg (args, int)
+ : va_arg (args, wint_t));
+ break;
+#endif
+ case TYPE_STRING:
+ ap->a.a_string = va_arg (args, const char *);
+ /* A null pointer is an invalid argument for "%s", but in practice
+ it occurs quite frequently in printf statements that produce
+ debug output. Use a fallback in this case. */
+ if (ap->a.a_string == NULL)
+ ap->a.a_string = "(NULL)";
+ break;
+#ifdef HAVE_WCHAR_T
+ case TYPE_WIDE_STRING:
+ ap->a.a_wide_string = va_arg (args, const wchar_t *);
+ /* A null pointer is an invalid argument for "%ls", but in practice
+ it occurs quite frequently in printf statements that produce
+ debug output. Use a fallback in this case. */
+ if (ap->a.a_wide_string == NULL)
+ {
+ static const wchar_t wide_null_string[] =
+ {
+ (wchar_t)'(',
+ (wchar_t)'N', (wchar_t)'U', (wchar_t)'L', (wchar_t)'L',
+ (wchar_t)')',
+ (wchar_t)0
+ };
+ ap->a.a_wide_string = wide_null_string;
+ }
+ break;
+#endif
+ case TYPE_POINTER:
+ ap->a.a_pointer = va_arg (args, void *);
+ break;
+ case TYPE_COUNT_SCHAR_POINTER:
+ ap->a.a_count_schar_pointer = va_arg (args, signed char *);
+ break;
+ case TYPE_COUNT_SHORT_POINTER:
+ ap->a.a_count_short_pointer = va_arg (args, short *);
+ break;
+ case TYPE_COUNT_INT_POINTER:
+ ap->a.a_count_int_pointer = va_arg (args, int *);
+ break;
+ case TYPE_COUNT_LONGINT_POINTER:
+ ap->a.a_count_longint_pointer = va_arg (args, long int *);
+ break;
+#ifdef HAVE_LONG_LONG_INT
+ case TYPE_COUNT_LONGLONGINT_POINTER:
+ ap->a.a_count_longlongint_pointer = va_arg (args, long long int *);
+ break;
+#endif
+ default:
+ /* Unknown type. */
+ return -1;
+ }
+ return 0;
+}
diff --git a/intl/printf-args.h b/intl/printf-args.h
new file mode 100644
index 000000000..886febe66
--- /dev/null
+++ b/intl/printf-args.h
@@ -0,0 +1,137 @@
+/* Decomposed printf argument list.
+ Copyright (C) 1999, 2002-2003, 2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _PRINTF_ARGS_H
+#define _PRINTF_ARGS_H
+
+/* Get size_t. */
+#include <stddef.h>
+
+/* Get wchar_t. */
+#ifdef HAVE_WCHAR_T
+# include <stddef.h>
+#endif
+
+/* Get wint_t. */
+#ifdef HAVE_WINT_T
+# include <wchar.h>
+#endif
+
+/* Get va_list. */
+#include <stdarg.h>
+
+
+/* Argument types */
+typedef enum
+{
+ TYPE_NONE,
+ TYPE_SCHAR,
+ TYPE_UCHAR,
+ TYPE_SHORT,
+ TYPE_USHORT,
+ TYPE_INT,
+ TYPE_UINT,
+ TYPE_LONGINT,
+ TYPE_ULONGINT,
+#ifdef HAVE_LONG_LONG_INT
+ TYPE_LONGLONGINT,
+ TYPE_ULONGLONGINT,
+#endif
+ TYPE_DOUBLE,
+#ifdef HAVE_LONG_DOUBLE
+ TYPE_LONGDOUBLE,
+#endif
+ TYPE_CHAR,
+#ifdef HAVE_WINT_T
+ TYPE_WIDE_CHAR,
+#endif
+ TYPE_STRING,
+#ifdef HAVE_WCHAR_T
+ TYPE_WIDE_STRING,
+#endif
+ TYPE_POINTER,
+ TYPE_COUNT_SCHAR_POINTER,
+ TYPE_COUNT_SHORT_POINTER,
+ TYPE_COUNT_INT_POINTER,
+ TYPE_COUNT_LONGINT_POINTER
+#ifdef HAVE_LONG_LONG_INT
+, TYPE_COUNT_LONGLONGINT_POINTER
+#endif
+} arg_type;
+
+/* Polymorphic argument */
+typedef struct
+{
+ arg_type type;
+ union
+ {
+ signed char a_schar;
+ unsigned char a_uchar;
+ short a_short;
+ unsigned short a_ushort;
+ int a_int;
+ unsigned int a_uint;
+ long int a_longint;
+ unsigned long int a_ulongint;
+#ifdef HAVE_LONG_LONG_INT
+ long long int a_longlongint;
+ unsigned long long int a_ulonglongint;
+#endif
+ float a_float;
+ double a_double;
+#ifdef HAVE_LONG_DOUBLE
+ long double a_longdouble;
+#endif
+ int a_char;
+#ifdef HAVE_WINT_T
+ wint_t a_wide_char;
+#endif
+ const char* a_string;
+#ifdef HAVE_WCHAR_T
+ const wchar_t* a_wide_string;
+#endif
+ void* a_pointer;
+ signed char * a_count_schar_pointer;
+ short * a_count_short_pointer;
+ int * a_count_int_pointer;
+ long int * a_count_longint_pointer;
+#ifdef HAVE_LONG_LONG_INT
+ long long int * a_count_longlongint_pointer;
+#endif
+ }
+ a;
+}
+argument;
+
+typedef struct
+{
+ size_t count;
+ argument *arg;
+}
+arguments;
+
+
+/* Fetch the arguments, putting them into a. */
+#ifdef STATIC
+STATIC
+#else
+extern
+#endif
+int printf_fetchargs (va_list args, arguments *a);
+
+#endif /* _PRINTF_ARGS_H */
diff --git a/intl/printf-parse.c b/intl/printf-parse.c
new file mode 100644
index 000000000..1a06b1a90
--- /dev/null
+++ b/intl/printf-parse.c
@@ -0,0 +1,544 @@
+/* Formatted output to strings.
+ Copyright (C) 1999-2000, 2002-2003, 2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#include <config.h>
+
+/* Specification. */
+#if WIDE_CHAR_VERSION
+# include "wprintf-parse.h"
+#else
+# include "printf-parse.h"
+#endif
+
+/* Get size_t, NULL. */
+#include <stddef.h>
+
+/* Get intmax_t. */
+#if HAVE_STDINT_H_WITH_UINTMAX
+# include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H_WITH_UINTMAX
+# include <inttypes.h>
+#endif
+
+/* malloc(), realloc(), free(). */
+#include <stdlib.h>
+
+/* Checked size_t computations. */
+#include "xsize.h"
+
+#if WIDE_CHAR_VERSION
+# define PRINTF_PARSE wprintf_parse
+# define CHAR_T wchar_t
+# define DIRECTIVE wchar_t_directive
+# define DIRECTIVES wchar_t_directives
+#else
+# define PRINTF_PARSE printf_parse
+# define CHAR_T char
+# define DIRECTIVE char_directive
+# define DIRECTIVES char_directives
+#endif
+
+#ifdef STATIC
+STATIC
+#endif
+int
+PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
+{
+ const CHAR_T *cp = format; /* pointer into format */
+ size_t arg_posn = 0; /* number of regular arguments consumed */
+ size_t d_allocated; /* allocated elements of d->dir */
+ size_t a_allocated; /* allocated elements of a->arg */
+ size_t max_width_length = 0;
+ size_t max_precision_length = 0;
+
+ d->count = 0;
+ d_allocated = 1;
+ d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
+ if (d->dir == NULL)
+ /* Out of memory. */
+ return -1;
+
+ a->count = 0;
+ a_allocated = 0;
+ a->arg = NULL;
+
+#define REGISTER_ARG(_index_,_type_) \
+ { \
+ size_t n = (_index_); \
+ if (n >= a_allocated) \
+ { \
+ size_t memory_size; \
+ argument *memory; \
+ \
+ a_allocated = xtimes (a_allocated, 2); \
+ if (a_allocated <= n) \
+ a_allocated = xsum (n, 1); \
+ memory_size = xtimes (a_allocated, sizeof (argument)); \
+ if (size_overflow_p (memory_size)) \
+ /* Overflow, would lead to out of memory. */ \
+ goto error; \
+ memory = (a->arg \
+ ? realloc (a->arg, memory_size) \
+ : malloc (memory_size)); \
+ if (memory == NULL) \
+ /* Out of memory. */ \
+ goto error; \
+ a->arg = memory; \
+ } \
+ while (a->count <= n) \
+ a->arg[a->count++].type = TYPE_NONE; \
+ if (a->arg[n].type == TYPE_NONE) \
+ a->arg[n].type = (_type_); \
+ else if (a->arg[n].type != (_type_)) \
+ /* Ambiguous type for positional argument. */ \
+ goto error; \
+ }
+
+ while (*cp != '\0')
+ {
+ CHAR_T c = *cp++;
+ if (c == '%')
+ {
+ size_t arg_index = ARG_NONE;
+ DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
+
+ /* Initialize the next directive. */
+ dp->dir_start = cp - 1;
+ dp->flags = 0;
+ dp->width_start = NULL;
+ dp->width_end = NULL;
+ dp->width_arg_index = ARG_NONE;
+ dp->precision_start = NULL;
+ dp->precision_end = NULL;
+ dp->precision_arg_index = ARG_NONE;
+ dp->arg_index = ARG_NONE;
+
+ /* Test for positional argument. */
+ if (*cp >= '0' && *cp <= '9')
+ {
+ const CHAR_T *np;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ ;
+ if (*np == '$')
+ {
+ size_t n = 0;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ n = xsum (xtimes (n, 10), *np - '0');
+ if (n == 0)
+ /* Positional argument 0. */
+ goto error;
+ if (size_overflow_p (n))
+ /* n too large, would lead to out of memory later. */
+ goto error;
+ arg_index = n - 1;
+ cp = np + 1;
+ }
+ }
+
+ /* Read the flags. */
+ for (;;)
+ {
+ if (*cp == '\'')
+ {
+ dp->flags |= FLAG_GROUP;
+ cp++;
+ }
+ else if (*cp == '-')
+ {
+ dp->flags |= FLAG_LEFT;
+ cp++;
+ }
+ else if (*cp == '+')
+ {
+ dp->flags |= FLAG_SHOWSIGN;
+ cp++;
+ }
+ else if (*cp == ' ')
+ {
+ dp->flags |= FLAG_SPACE;
+ cp++;
+ }
+ else if (*cp == '#')
+ {
+ dp->flags |= FLAG_ALT;
+ cp++;
+ }
+ else if (*cp == '0')
+ {
+ dp->flags |= FLAG_ZERO;
+ cp++;
+ }
+ else
+ break;
+ }
+
+ /* Parse the field width. */
+ if (*cp == '*')
+ {
+ dp->width_start = cp;
+ cp++;
+ dp->width_end = cp;
+ if (max_width_length < 1)
+ max_width_length = 1;
+
+ /* Test for positional argument. */
+ if (*cp >= '0' && *cp <= '9')
+ {
+ const CHAR_T *np;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ ;
+ if (*np == '$')
+ {
+ size_t n = 0;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ n = xsum (xtimes (n, 10), *np - '0');
+ if (n == 0)
+ /* Positional argument 0. */
+ goto error;
+ if (size_overflow_p (n))
+ /* n too large, would lead to out of memory later. */
+ goto error;
+ dp->width_arg_index = n - 1;
+ cp = np + 1;
+ }
+ }
+ if (dp->width_arg_index == ARG_NONE)
+ {
+ dp->width_arg_index = arg_posn++;
+ if (dp->width_arg_index == ARG_NONE)
+ /* arg_posn wrapped around. */
+ goto error;
+ }
+ REGISTER_ARG (dp->width_arg_index, TYPE_INT);
+ }
+ else if (*cp >= '0' && *cp <= '9')
+ {
+ size_t width_length;
+
+ dp->width_start = cp;
+ for (; *cp >= '0' && *cp <= '9'; cp++)
+ ;
+ dp->width_end = cp;
+ width_length = dp->width_end - dp->width_start;
+ if (max_width_length < width_length)
+ max_width_length = width_length;
+ }
+
+ /* Parse the precision. */
+ if (*cp == '.')
+ {
+ cp++;
+ if (*cp == '*')
+ {
+ dp->precision_start = cp - 1;
+ cp++;
+ dp->precision_end = cp;
+ if (max_precision_length < 2)
+ max_precision_length = 2;
+
+ /* Test for positional argument. */
+ if (*cp >= '0' && *cp <= '9')
+ {
+ const CHAR_T *np;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ ;
+ if (*np == '$')
+ {
+ size_t n = 0;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ n = xsum (xtimes (n, 10), *np - '0');
+ if (n == 0)
+ /* Positional argument 0. */
+ goto error;
+ if (size_overflow_p (n))
+ /* n too large, would lead to out of memory
+ later. */
+ goto error;
+ dp->precision_arg_index = n - 1;
+ cp = np + 1;
+ }
+ }
+ if (dp->precision_arg_index == ARG_NONE)
+ {
+ dp->precision_arg_index = arg_posn++;
+ if (dp->precision_arg_index == ARG_NONE)
+ /* arg_posn wrapped around. */
+ goto error;
+ }
+ REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
+ }
+ else
+ {
+ size_t precision_length;
+
+ dp->precision_start = cp - 1;
+ for (; *cp >= '0' && *cp <= '9'; cp++)
+ ;
+ dp->precision_end = cp;
+ precision_length = dp->precision_end - dp->precision_start;
+ if (max_precision_length < precision_length)
+ max_precision_length = precision_length;
+ }
+ }
+
+ {
+ arg_type type;
+
+ /* Parse argument type/size specifiers. */
+ {
+ int flags = 0;
+
+ for (;;)
+ {
+ if (*cp == 'h')
+ {
+ flags |= (1 << (flags & 1));
+ cp++;
+ }
+ else if (*cp == 'L')
+ {
+ flags |= 4;
+ cp++;
+ }
+ else if (*cp == 'l')
+ {
+ flags += 8;
+ cp++;
+ }
+#ifdef HAVE_INTMAX_T
+ else if (*cp == 'j')
+ {
+ if (sizeof (intmax_t) > sizeof (long))
+ {
+ /* intmax_t = long long */
+ flags += 16;
+ }
+ else if (sizeof (intmax_t) > sizeof (int))
+ {
+ /* intmax_t = long */
+ flags += 8;
+ }
+ cp++;
+ }
+#endif
+ else if (*cp == 'z' || *cp == 'Z')
+ {
+ /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
+ because the warning facility in gcc-2.95.2 understands
+ only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
+ if (sizeof (size_t) > sizeof (long))
+ {
+ /* size_t = long long */
+ flags += 16;
+ }
+ else if (sizeof (size_t) > sizeof (int))
+ {
+ /* size_t = long */
+ flags += 8;
+ }
+ cp++;
+ }
+ else if (*cp == 't')
+ {
+ if (sizeof (ptrdiff_t) > sizeof (long))
+ {
+ /* ptrdiff_t = long long */
+ flags += 16;
+ }
+ else if (sizeof (ptrdiff_t) > sizeof (int))
+ {
+ /* ptrdiff_t = long */
+ flags += 8;
+ }
+ cp++;
+ }
+ else
+ break;
+ }
+
+ /* Read the conversion character. */
+ c = *cp++;
+ switch (c)
+ {
+ case 'd': case 'i':
+#ifdef HAVE_LONG_LONG_INT
+ /* If 'long long' exists and is larger than 'long': */
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_LONGLONGINT;
+ else
+#endif
+ /* If 'long long' exists and is the same as 'long', we parse
+ "lld" into TYPE_LONGINT. */
+ if (flags >= 8)
+ type = TYPE_LONGINT;
+ else if (flags & 2)
+ type = TYPE_SCHAR;
+ else if (flags & 1)
+ type = TYPE_SHORT;
+ else
+ type = TYPE_INT;
+ break;
+ case 'o': case 'u': case 'x': case 'X':
+#ifdef HAVE_LONG_LONG_INT
+ /* If 'long long' exists and is larger than 'long': */
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_ULONGLONGINT;
+ else
+#endif
+ /* If 'unsigned long long' exists and is the same as
+ 'unsigned long', we parse "llu" into TYPE_ULONGINT. */
+ if (flags >= 8)
+ type = TYPE_ULONGINT;
+ else if (flags & 2)
+ type = TYPE_UCHAR;
+ else if (flags & 1)
+ type = TYPE_USHORT;
+ else
+ type = TYPE_UINT;
+ break;
+ case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
+ case 'a': case 'A':
+#ifdef HAVE_LONG_DOUBLE
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_LONGDOUBLE;
+ else
+#endif
+ type = TYPE_DOUBLE;
+ break;
+ case 'c':
+ if (flags >= 8)
+#ifdef HAVE_WINT_T
+ type = TYPE_WIDE_CHAR;
+#else
+ goto error;
+#endif
+ else
+ type = TYPE_CHAR;
+ break;
+#ifdef HAVE_WINT_T
+ case 'C':
+ type = TYPE_WIDE_CHAR;
+ c = 'c';
+ break;
+#endif
+ case 's':
+ if (flags >= 8)
+#ifdef HAVE_WCHAR_T
+ type = TYPE_WIDE_STRING;
+#else
+ goto error;
+#endif
+ else
+ type = TYPE_STRING;
+ break;
+#ifdef HAVE_WCHAR_T
+ case 'S':
+ type = TYPE_WIDE_STRING;
+ c = 's';
+ break;
+#endif
+ case 'p':
+ type = TYPE_POINTER;
+ break;
+ case 'n':
+#ifdef HAVE_LONG_LONG_INT
+ /* If 'long long' exists and is larger than 'long': */
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_COUNT_LONGLONGINT_POINTER;
+ else
+#endif
+ /* If 'long long' exists and is the same as 'long', we parse
+ "lln" into TYPE_COUNT_LONGINT_POINTER. */
+ if (flags >= 8)
+ type = TYPE_COUNT_LONGINT_POINTER;
+ else if (flags & 2)
+ type = TYPE_COUNT_SCHAR_POINTER;
+ else if (flags & 1)
+ type = TYPE_COUNT_SHORT_POINTER;
+ else
+ type = TYPE_COUNT_INT_POINTER;
+ break;
+ case '%':
+ type = TYPE_NONE;
+ break;
+ default:
+ /* Unknown conversion character. */
+ goto error;
+ }
+ }
+
+ if (type != TYPE_NONE)
+ {
+ dp->arg_index = arg_index;
+ if (dp->arg_index == ARG_NONE)
+ {
+ dp->arg_index = arg_posn++;
+ if (dp->arg_index == ARG_NONE)
+ /* arg_posn wrapped around. */
+ goto error;
+ }
+ REGISTER_ARG (dp->arg_index, type);
+ }
+ dp->conversion = c;
+ dp->dir_end = cp;
+ }
+
+ d->count++;
+ if (d->count >= d_allocated)
+ {
+ size_t memory_size;
+ DIRECTIVE *memory;
+
+ d_allocated = xtimes (d_allocated, 2);
+ memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
+ if (size_overflow_p (memory_size))
+ /* Overflow, would lead to out of memory. */
+ goto error;
+ memory = realloc (d->dir, memory_size);
+ if (memory == NULL)
+ /* Out of memory. */
+ goto error;
+ d->dir = memory;
+ }
+ }
+ }
+ d->dir[d->count].dir_start = cp;
+
+ d->max_width_length = max_width_length;
+ d->max_precision_length = max_precision_length;
+ return 0;
+
+error:
+ if (a->arg)
+ free (a->arg);
+ if (d->dir)
+ free (d->dir);
+ return -1;
+}
+
+#undef DIRECTIVES
+#undef DIRECTIVE
+#undef CHAR_T
+#undef PRINTF_PARSE
diff --git a/intl/printf-parse.h b/intl/printf-parse.h
new file mode 100644
index 000000000..e78533895
--- /dev/null
+++ b/intl/printf-parse.h
@@ -0,0 +1,75 @@
+/* Parse printf format string.
+ Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _PRINTF_PARSE_H
+#define _PRINTF_PARSE_H
+
+#include "printf-args.h"
+
+
+/* Flags */
+#define FLAG_GROUP 1 /* ' flag */
+#define FLAG_LEFT 2 /* - flag */
+#define FLAG_SHOWSIGN 4 /* + flag */
+#define FLAG_SPACE 8 /* space flag */
+#define FLAG_ALT 16 /* # flag */
+#define FLAG_ZERO 32
+
+/* arg_index value indicating that no argument is consumed. */
+#define ARG_NONE (~(size_t)0)
+
+/* A parsed directive. */
+typedef struct
+{
+ const char* dir_start;
+ const char* dir_end;
+ int flags;
+ const char* width_start;
+ const char* width_end;
+ size_t width_arg_index;
+ const char* precision_start;
+ const char* precision_end;
+ size_t precision_arg_index;
+ char conversion; /* d i o u x X f e E g G c s p n U % but not C S */
+ size_t arg_index;
+}
+char_directive;
+
+/* A parsed format string. */
+typedef struct
+{
+ size_t count;
+ char_directive *dir;
+ size_t max_width_length;
+ size_t max_precision_length;
+}
+char_directives;
+
+
+/* Parses the format string. Fills in the number N of directives, and fills
+ in directives[0], ..., directives[N-1], and sets directives[N].dir_start
+ to the end of the format string. Also fills in the arg_type fields of the
+ arguments and the needed count of arguments. */
+#ifdef STATIC
+STATIC
+#else
+extern
+#endif
+int printf_parse (const char *format, char_directives *d, arguments *a);
+
+#endif /* _PRINTF_PARSE_H */
diff --git a/intl/printf.c b/intl/printf.c
new file mode 100644
index 000000000..004c66f78
--- /dev/null
+++ b/intl/printf.c
@@ -0,0 +1,422 @@
+/* Formatted output to strings, using POSIX/XSI format strings with positions.
+ Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+#else
+# ifdef _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# 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
+#endif
+
+#include <stdio.h>
+
+#if !HAVE_POSIX_PRINTF
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
+#ifndef EOVERFLOW
+# define EOVERFLOW E2BIG
+#endif
+
+/* When building a DLL, we must export some functions. Note that because
+ the functions are only defined for binary backward compatibility, we
+ don't need to use __declspec(dllimport) in any case. */
+#if defined _MSC_VER && BUILDING_DLL
+# define DLL_EXPORTED __declspec(dllexport)
+#else
+# define DLL_EXPORTED
+#endif
+
+#define STATIC static
+
+/* This needs to be consistent with libgnuintl.h.in. */
+#if defined __NetBSD__ || defined __CYGWIN__ || defined __MINGW32__
+/* Don't break __attribute__((format(printf,M,N))).
+ This redefinition is only possible because the libc in NetBSD, Cygwin,
+ mingw does not have a function __printf__. */
+# define libintl_printf __printf__
+#endif
+
+/* Define auxiliary functions declared in "printf-args.h". */
+#include "printf-args.c"
+
+/* Define auxiliary functions declared in "printf-parse.h". */
+#include "printf-parse.c"
+
+/* Define functions declared in "vasnprintf.h". */
+#define vasnprintf libintl_vasnprintf
+#include "vasnprintf.c"
+#if 0 /* not needed */
+#define asnprintf libintl_asnprintf
+#include "asnprintf.c"
+#endif
+
+DLL_EXPORTED
+int
+libintl_vfprintf (FILE *stream, const char *format, va_list args)
+{
+ if (strchr (format, '$') == NULL)
+ return vfprintf (stream, format, args);
+ else
+ {
+ size_t length;
+ char *result = libintl_vasnprintf (NULL, &length, format, args);
+ int retval = -1;
+ if (result != NULL)
+ {
+ size_t written = fwrite (result, 1, length, stream);
+ free (result);
+ if (written == length)
+ {
+ if (length > INT_MAX)
+ errno = EOVERFLOW;
+ else
+ retval = length;
+ }
+ }
+ return retval;
+ }
+}
+
+DLL_EXPORTED
+int
+libintl_fprintf (FILE *stream, const char *format, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start (args, format);
+ retval = libintl_vfprintf (stream, format, args);
+ va_end (args);
+ return retval;
+}
+
+DLL_EXPORTED
+int
+libintl_vprintf (const char *format, va_list args)
+{
+ return libintl_vfprintf (stdout, format, args);
+}
+
+DLL_EXPORTED
+int
+libintl_printf (const char *format, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start (args, format);
+ retval = libintl_vprintf (format, args);
+ va_end (args);
+ return retval;
+}
+
+DLL_EXPORTED
+int
+libintl_vsprintf (char *resultbuf, const char *format, va_list args)
+{
+ if (strchr (format, '$') == NULL)
+ return vsprintf (resultbuf, format, args);
+ else
+ {
+ size_t length = (size_t) ~0 / (4 * sizeof (char));
+ char *result = libintl_vasnprintf (resultbuf, &length, format, args);
+ if (result != resultbuf)
+ {
+ free (result);
+ return -1;
+ }
+ if (length > INT_MAX)
+ {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ else
+ return length;
+ }
+}
+
+DLL_EXPORTED
+int
+libintl_sprintf (char *resultbuf, const char *format, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start (args, format);
+ retval = libintl_vsprintf (resultbuf, format, args);
+ va_end (args);
+ return retval;
+}
+
+#if HAVE_SNPRINTF
+
+# if HAVE_DECL__SNPRINTF
+ /* Windows. */
+# define system_vsnprintf _vsnprintf
+# else
+ /* Unix. */
+# define system_vsnprintf vsnprintf
+# endif
+
+DLL_EXPORTED
+int
+libintl_vsnprintf (char *resultbuf, size_t length, const char *format, va_list args)
+{
+ if (strchr (format, '$') == NULL)
+ return system_vsnprintf (resultbuf, length, format, args);
+ else
+ {
+ size_t maxlength = length;
+ char *result = libintl_vasnprintf (resultbuf, &length, format, args);
+ if (result != resultbuf)
+ {
+ if (maxlength > 0)
+ {
+ size_t pruned_length =
+ (length < maxlength ? length : maxlength - 1);
+ memcpy (resultbuf, result, pruned_length);
+ resultbuf[pruned_length] = '\0';
+ }
+ free (result);
+ }
+ if (length > INT_MAX)
+ {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ else
+ return length;
+ }
+}
+
+DLL_EXPORTED
+int
+libintl_snprintf (char *resultbuf, size_t length, const char *format, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start (args, format);
+ retval = libintl_vsnprintf (resultbuf, length, format, args);
+ va_end (args);
+ return retval;
+}
+
+#endif
+
+#if HAVE_ASPRINTF
+
+DLL_EXPORTED
+int
+libintl_vasprintf (char **resultp, const char *format, va_list args)
+{
+ size_t length;
+ char *result = libintl_vasnprintf (NULL, &length, format, args);
+ if (result == NULL)
+ return -1;
+ if (length > INT_MAX)
+ {
+ free (result);
+ errno = EOVERFLOW;
+ return -1;
+ }
+ *resultp = result;
+ return length;
+}
+
+DLL_EXPORTED
+int
+libintl_asprintf (char **resultp, const char *format, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start (args, format);
+ retval = libintl_vasprintf (resultp, format, args);
+ va_end (args);
+ return retval;
+}
+
+#endif
+
+#if HAVE_FWPRINTF
+
+#include <wchar.h>
+
+#define WIDE_CHAR_VERSION 1
+
+/* Define auxiliary functions declared in "wprintf-parse.h". */
+#include "printf-parse.c"
+
+/* Define functions declared in "vasnprintf.h". */
+#define vasnwprintf libintl_vasnwprintf
+#include "vasnprintf.c"
+#if 0 /* not needed */
+#define asnwprintf libintl_asnwprintf
+#include "asnprintf.c"
+#endif
+
+# if HAVE_DECL__SNWPRINTF
+ /* Windows. */
+# define system_vswprintf _vsnwprintf
+# else
+ /* Unix. */
+# define system_vswprintf vswprintf
+# endif
+
+DLL_EXPORTED
+int
+libintl_vfwprintf (FILE *stream, const wchar_t *format, va_list args)
+{
+ if (wcschr (format, '$') == NULL)
+ return vfwprintf (stream, format, args);
+ else
+ {
+ size_t length;
+ wchar_t *result = libintl_vasnwprintf (NULL, &length, format, args);
+ int retval = -1;
+ if (result != NULL)
+ {
+ size_t i;
+ for (i = 0; i < length; i++)
+ if (fputwc (result[i], stream) == WEOF)
+ break;
+ free (result);
+ if (i == length)
+ {
+ if (length > INT_MAX)
+ errno = EOVERFLOW;
+ else
+ retval = length;
+ }
+ }
+ return retval;
+ }
+}
+
+DLL_EXPORTED
+int
+libintl_fwprintf (FILE *stream, const wchar_t *format, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start (args, format);
+ retval = libintl_vfwprintf (stream, format, args);
+ va_end (args);
+ return retval;
+}
+
+DLL_EXPORTED
+int
+libintl_vwprintf (const wchar_t *format, va_list args)
+{
+ return libintl_vfwprintf (stdout, format, args);
+}
+
+DLL_EXPORTED
+int
+libintl_wprintf (const wchar_t *format, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start (args, format);
+ retval = libintl_vwprintf (format, args);
+ va_end (args);
+ return retval;
+}
+
+DLL_EXPORTED
+int
+libintl_vswprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, va_list args)
+{
+ if (wcschr (format, '$') == NULL)
+ return system_vswprintf (resultbuf, length, format, args);
+ else
+ {
+ size_t maxlength = length;
+ wchar_t *result = libintl_vasnwprintf (resultbuf, &length, format, args);
+ if (result != resultbuf)
+ {
+ if (maxlength > 0)
+ {
+ size_t pruned_length =
+ (length < maxlength ? length : maxlength - 1);
+ memcpy (resultbuf, result, pruned_length * sizeof (wchar_t));
+ resultbuf[pruned_length] = 0;
+ }
+ free (result);
+ /* Unlike vsnprintf, which has to return the number of character that
+ would have been produced if the resultbuf had been sufficiently
+ large, the vswprintf function has to return a negative value if
+ the resultbuf was not sufficiently large. */
+ if (length >= maxlength)
+ return -1;
+ }
+ if (length > INT_MAX)
+ {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ else
+ return length;
+ }
+}
+
+DLL_EXPORTED
+int
+libintl_swprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start (args, format);
+ retval = libintl_vswprintf (resultbuf, length, format, args);
+ va_end (args);
+ return retval;
+}
+
+#endif
+
+#endif
diff --git a/intl/relocatable.c b/intl/relocatable.c
new file mode 100644
index 000000000..5e1dde6c8
--- /dev/null
+++ b/intl/relocatable.c
@@ -0,0 +1,468 @@
+/* Provide relocatable packages.
+ Copyright (C) 2003-2006 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+
+/* Tell glibc's <stdio.h> to provide a prototype for getline().
+ This must come before <config.h> because <config.h> may include
+ <features.h>, and once <features.h> has been included, it's too late. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#include <config.h>
+
+/* Specification. */
+#include "relocatable.h"
+
+#if ENABLE_RELOCATABLE
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef NO_XMALLOC
+# define xmalloc malloc
+#else
+# include "xalloc.h"
+#endif
+
+#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+
+#if DEPENDS_ON_LIBCHARSET
+# include <libcharset.h>
+#endif
+#if DEPENDS_ON_LIBICONV && HAVE_ICONV
+# include <iconv.h>
+#endif
+#if DEPENDS_ON_LIBINTL && ENABLE_NLS
+# include <libintl.h>
+#endif
+
+/* Faked cheap 'bool'. */
+#undef bool
+#undef false
+#undef true
+#define bool int
+#define false 0
+#define true 1
+
+/* Pathname support.
+ ISSLASH(C) tests whether C is a directory separator character.
+ IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
+ */
+#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
+ /* Win32, Cygwin, OS/2, DOS */
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+# define HAS_DEVICE(P) \
+ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
+ && (P)[1] == ':')
+# define IS_PATH_WITH_DIR(P) \
+ (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
+# define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
+#else
+ /* Unix */
+# define ISSLASH(C) ((C) == '/')
+# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
+# define FILE_SYSTEM_PREFIX_LEN(P) 0
+#endif
+
+/* Original installation prefix. */
+static char *orig_prefix;
+static size_t orig_prefix_len;
+/* Current installation prefix. */
+static char *curr_prefix;
+static size_t curr_prefix_len;
+/* These prefixes do not end in a slash. Anything that will be concatenated
+ to them must start with a slash. */
+
+/* Sets the original and the current installation prefix of this module.
+ Relocation simply replaces a pathname starting with the original prefix
+ by the corresponding pathname with the current prefix instead. Both
+ prefixes should be directory names without trailing slash (i.e. use ""
+ instead of "/"). */
+static void
+set_this_relocation_prefix (const char *orig_prefix_arg,
+ const char *curr_prefix_arg)
+{
+ if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
+ /* Optimization: if orig_prefix and curr_prefix are equal, the
+ relocation is a nop. */
+ && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
+ {
+ /* Duplicate the argument strings. */
+ char *memory;
+
+ orig_prefix_len = strlen (orig_prefix_arg);
+ curr_prefix_len = strlen (curr_prefix_arg);
+ memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
+#ifdef NO_XMALLOC
+ if (memory != NULL)
+#endif
+ {
+ memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
+ orig_prefix = memory;
+ memory += orig_prefix_len + 1;
+ memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
+ curr_prefix = memory;
+ return;
+ }
+ }
+ orig_prefix = NULL;
+ curr_prefix = NULL;
+ /* Don't worry about wasted memory here - this function is usually only
+ called once. */
+}
+
+/* Sets the original and the current installation prefix of the package.
+ Relocation simply replaces a pathname starting with the original prefix
+ by the corresponding pathname with the current prefix instead. Both
+ prefixes should be directory names without trailing slash (i.e. use ""
+ instead of "/"). */
+void
+set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
+{
+ set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
+
+ /* Now notify all dependent libraries. */
+#if DEPENDS_ON_LIBCHARSET
+ libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
+#endif
+#if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
+ libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
+#endif
+#if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
+ libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
+#endif
+}
+
+#if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
+
+/* Convenience function:
+ Computes the current installation prefix, based on the original
+ installation prefix, the original installation directory of a particular
+ file, and the current pathname of this file. Returns NULL upon failure. */
+#ifdef IN_LIBRARY
+#define compute_curr_prefix local_compute_curr_prefix
+static
+#endif
+const char *
+compute_curr_prefix (const char *orig_installprefix,
+ const char *orig_installdir,
+ const char *curr_pathname)
+{
+ const char *curr_installdir;
+ const char *rel_installdir;
+
+ if (curr_pathname == NULL)
+ return NULL;
+
+ /* Determine the relative installation directory, relative to the prefix.
+ This is simply the difference between orig_installprefix and
+ orig_installdir. */
+ if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
+ != 0)
+ /* Shouldn't happen - nothing should be installed outside $(prefix). */
+ return NULL;
+ rel_installdir = orig_installdir + strlen (orig_installprefix);
+
+ /* Determine the current installation directory. */
+ {
+ const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
+ const char *p = curr_pathname + strlen (curr_pathname);
+ char *q;
+
+ while (p > p_base)
+ {
+ p--;
+ if (ISSLASH (*p))
+ break;
+ }
+
+ q = (char *) xmalloc (p - curr_pathname + 1);
+#ifdef NO_XMALLOC
+ if (q == NULL)
+ return NULL;
+#endif
+ memcpy (q, curr_pathname, p - curr_pathname);
+ q[p - curr_pathname] = '\0';
+ curr_installdir = q;
+ }
+
+ /* Compute the current installation prefix by removing the trailing
+ rel_installdir from it. */
+ {
+ const char *rp = rel_installdir + strlen (rel_installdir);
+ const char *cp = curr_installdir + strlen (curr_installdir);
+ const char *cp_base =
+ curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
+
+ while (rp > rel_installdir && cp > cp_base)
+ {
+ bool same = false;
+ const char *rpi = rp;
+ const char *cpi = cp;
+
+ while (rpi > rel_installdir && cpi > cp_base)
+ {
+ rpi--;
+ cpi--;
+ if (ISSLASH (*rpi) || ISSLASH (*cpi))
+ {
+ if (ISSLASH (*rpi) && ISSLASH (*cpi))
+ same = true;
+ break;
+ }
+ /* Do case-insensitive comparison if the filesystem is always or
+ often case-insensitive. It's better to accept the comparison
+ if the difference is only in case, rather than to fail. */
+#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
+ /* Win32, Cygwin, OS/2, DOS - case insignificant filesystem */
+ if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
+ != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
+ break;
+#else
+ if (*rpi != *cpi)
+ break;
+#endif
+ }
+ if (!same)
+ break;
+ /* The last pathname component was the same. opi and cpi now point
+ to the slash before it. */
+ rp = rpi;
+ cp = cpi;
+ }
+
+ if (rp > rel_installdir)
+ /* Unexpected: The curr_installdir does not end with rel_installdir. */
+ return NULL;
+
+ {
+ size_t curr_prefix_len = cp - curr_installdir;
+ char *curr_prefix;
+
+ curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
+#ifdef NO_XMALLOC
+ if (curr_prefix == NULL)
+ return NULL;
+#endif
+ memcpy (curr_prefix, curr_installdir, curr_prefix_len);
+ curr_prefix[curr_prefix_len] = '\0';
+
+ return curr_prefix;
+ }
+ }
+}
+
+#endif /* !IN_LIBRARY || PIC */
+
+#if defined PIC && defined INSTALLDIR
+
+/* Full pathname of shared library, or NULL. */
+static char *shared_library_fullname;
+
+#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__
+
+/* Determine the full pathname of the shared library when it is loaded. */
+
+BOOL WINAPI
+DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
+{
+ (void) reserved;
+
+ if (event == DLL_PROCESS_ATTACH)
+ {
+ /* The DLL is being loaded into an application's address range. */
+ static char location[MAX_PATH];
+
+ if (!GetModuleFileName (module_handle, location, sizeof (location)))
+ /* Shouldn't happen. */
+ return FALSE;
+
+ if (!IS_PATH_WITH_DIR (location))
+ /* Shouldn't happen. */
+ return FALSE;
+
+ {
+#if defined __CYGWIN__
+ /* On Cygwin, we need to convert paths coming from Win32 system calls
+ to the Unix-like slashified notation. */
+ static char location_as_posix_path[2 * MAX_PATH];
+ /* There's no error return defined for cygwin_conv_to_posix_path.
+ See cygwin-api/func-cygwin-conv-to-posix-path.html.
+ Does it overflow the buffer of expected size MAX_PATH or does it
+ truncate the path? I don't know. Let's catch both. */
+ cygwin_conv_to_posix_path (location, location_as_posix_path);
+ location_as_posix_path[MAX_PATH - 1] = '\0';
+ if (strlen (location_as_posix_path) >= MAX_PATH - 1)
+ /* A sign of buffer overflow or path truncation. */
+ return FALSE;
+ shared_library_fullname = strdup (location_as_posix_path);
+#else
+ shared_library_fullname = strdup (location);
+#endif
+ }
+ }
+
+ return TRUE;
+}
+
+#else /* Unix except Cygwin */
+
+static void
+find_shared_library_fullname ()
+{
+#if defined __linux__ && __GLIBC__ >= 2
+ /* Linux has /proc/self/maps. glibc 2 has the getline() function. */
+ FILE *fp;
+
+ /* Open the current process' maps file. It describes one VMA per line. */
+ fp = fopen ("/proc/self/maps", "r");
+ if (fp)
+ {
+ unsigned long address = (unsigned long) &find_shared_library_fullname;
+ for (;;)
+ {
+ unsigned long start, end;
+ int c;
+
+ if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
+ break;
+ if (address >= start && address <= end - 1)
+ {
+ /* Found it. Now see if this line contains a filename. */
+ while (c = getc (fp), c != EOF && c != '\n' && c != '/')
+ continue;
+ if (c == '/')
+ {
+ size_t size;
+ int len;
+
+ ungetc (c, fp);
+ shared_library_fullname = NULL; size = 0;
+ len = getline (&shared_library_fullname, &size, fp);
+ if (len >= 0)
+ {
+ /* Success: filled shared_library_fullname. */
+ if (len > 0 && shared_library_fullname[len - 1] == '\n')
+ shared_library_fullname[len - 1] = '\0';
+ }
+ }
+ break;
+ }
+ while (c = getc (fp), c != EOF && c != '\n')
+ continue;
+ }
+ fclose (fp);
+ }
+#endif
+}
+
+#endif /* (WIN32 or Cygwin) / (Unix except Cygwin) */
+
+/* Return the full pathname of the current shared library.
+ Return NULL if unknown.
+ Guaranteed to work only on Linux, Cygwin and Woe32. */
+static char *
+get_shared_library_fullname ()
+{
+#if !(defined _WIN32 || defined __WIN32__ || defined __CYGWIN__)
+ static bool tried_find_shared_library_fullname;
+ if (!tried_find_shared_library_fullname)
+ {
+ find_shared_library_fullname ();
+ tried_find_shared_library_fullname = true;
+ }
+#endif
+ return shared_library_fullname;
+}
+
+#endif /* PIC */
+
+/* Returns the pathname, relocated according to the current installation
+ directory. */
+const char *
+relocate (const char *pathname)
+{
+#if defined PIC && defined INSTALLDIR
+ static int initialized;
+
+ /* Initialization code for a shared library. */
+ if (!initialized)
+ {
+ /* At this point, orig_prefix and curr_prefix likely have already been
+ set through the main program's set_program_name_and_installdir
+ function. This is sufficient in the case that the library has
+ initially been installed in the same orig_prefix. But we can do
+ better, to also cover the cases that 1. it has been installed
+ in a different prefix before being moved to orig_prefix and (later)
+ to curr_prefix, 2. unlike the program, it has not moved away from
+ orig_prefix. */
+ const char *orig_installprefix = INSTALLPREFIX;
+ const char *orig_installdir = INSTALLDIR;
+ const char *curr_prefix_better;
+
+ curr_prefix_better =
+ compute_curr_prefix (orig_installprefix, orig_installdir,
+ get_shared_library_fullname ());
+ if (curr_prefix_better == NULL)
+ curr_prefix_better = curr_prefix;
+
+ set_relocation_prefix (orig_installprefix, curr_prefix_better);
+
+ initialized = 1;
+ }
+#endif
+
+ /* Note: It is not necessary to perform case insensitive comparison here,
+ even for DOS-like filesystems, because the pathname argument was
+ typically created from the same Makefile variable as orig_prefix came
+ from. */
+ if (orig_prefix != NULL && curr_prefix != NULL
+ && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
+ {
+ if (pathname[orig_prefix_len] == '\0')
+ /* pathname equals orig_prefix. */
+ return curr_prefix;
+ if (ISSLASH (pathname[orig_prefix_len]))
+ {
+ /* pathname starts with orig_prefix. */
+ const char *pathname_tail = &pathname[orig_prefix_len];
+ char *result =
+ (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
+
+#ifdef NO_XMALLOC
+ if (result != NULL)
+#endif
+ {
+ memcpy (result, curr_prefix, curr_prefix_len);
+ strcpy (result + curr_prefix_len, pathname_tail);
+ return result;
+ }
+ }
+ }
+ /* Nothing to relocate. */
+ return pathname;
+}
+
+#endif
diff --git a/intl/relocatable.h b/intl/relocatable.h
new file mode 100644
index 000000000..f6d38321a
--- /dev/null
+++ b/intl/relocatable.h
@@ -0,0 +1,79 @@
+/* Provide relocatable packages.
+ Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _RELOCATABLE_H
+#define _RELOCATABLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* This can be enabled through the configure --enable-relocatable option. */
+#if ENABLE_RELOCATABLE
+
+/* When building a DLL, we must export some functions. Note that because
+ this is a private .h file, we don't need to use __declspec(dllimport)
+ in any case. */
+#if HAVE_VISIBILITY && BUILDING_DLL
+# define RELOCATABLE_DLL_EXPORTED __attribute__((__visibility__("default")))
+#elif defined _MSC_VER && BUILDING_DLL
+# define RELOCATABLE_DLL_EXPORTED __declspec(dllexport)
+#else
+# define RELOCATABLE_DLL_EXPORTED
+#endif
+
+/* Sets the original and the current installation prefix of the package.
+ Relocation simply replaces a pathname starting with the original prefix
+ by the corresponding pathname with the current prefix instead. Both
+ prefixes should be directory names without trailing slash (i.e. use ""
+ instead of "/"). */
+extern RELOCATABLE_DLL_EXPORTED void
+ set_relocation_prefix (const char *orig_prefix,
+ const char *curr_prefix);
+
+/* Returns the pathname, relocated according to the current installation
+ directory. */
+extern const char * relocate (const char *pathname);
+
+/* Memory management: relocate() leaks memory, because it has to construct
+ a fresh pathname. If this is a problem because your program calls
+ relocate() frequently, think about caching the result. */
+
+/* Convenience function:
+ Computes the current installation prefix, based on the original
+ installation prefix, the original installation directory of a particular
+ file, and the current pathname of this file. Returns NULL upon failure. */
+extern const char * compute_curr_prefix (const char *orig_installprefix,
+ const char *orig_installdir,
+ const char *curr_pathname);
+
+#else
+
+/* By default, we use the hardwired pathnames. */
+#define relocate(pathname) (pathname)
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RELOCATABLE_H */
diff --git a/intl/textdomain.c b/intl/textdomain.c
new file mode 100644
index 000000000..c316460fd
--- /dev/null
+++ b/intl/textdomain.c
@@ -0,0 +1,141 @@
+/* Implementation of the textdomain(3) function.
+ Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgnuintl.h"
+#endif
+
+/* Handle multi-threaded applications. */
+#ifdef _LIBC
+# include <bits/libc-lock.h>
+# define gl_rwlock_define __libc_rwlock_define
+# define gl_rwlock_wrlock __libc_rwlock_wrlock
+# define gl_rwlock_unlock __libc_rwlock_unlock
+#else
+# include "lock.h"
+#endif
+
+/* The internal variables in the standalone libintl.a must have different
+ names than the internal variables in GNU libc, otherwise programs
+ using libintl.a cannot be linked statically. */
+#if !defined _LIBC
+# define _nl_default_default_domain libintl_nl_default_default_domain
+# define _nl_current_default_domain libintl_nl_current_default_domain
+#endif
+
+/* @@ end of prolog @@ */
+
+/* Name of the default text domain. */
+extern const char _nl_default_default_domain[] attribute_hidden;
+
+/* Default text domain in which entries for gettext(3) are to be found. */
+extern const char *_nl_current_default_domain attribute_hidden;
+
+
+/* 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 libintl_textdomain
+#endif
+
+/* Lock variable to protect the global data in the gettext implementation. */
+gl_rwlock_define (extern, _nl_state_lock attribute_hidden)
+
+/* 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 (const char *domainname)
+{
+ char *new_domain;
+ char *old_domain;
+
+ /* A NULL pointer requests the current setting. */
+ if (domainname == NULL)
+ return (char *) _nl_current_default_domain;
+
+ gl_rwlock_wrlock (_nl_state_lock);
+
+ old_domain = (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;
+ new_domain = (char *) _nl_current_default_domain;
+ }
+ else if (strcmp (domainname, old_domain) == 0)
+ /* This can happen and people will use it to signal that some
+ environment variable changed. */
+ new_domain = old_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
+ new_domain = strdup (domainname);
+#else
+ size_t len = strlen (domainname) + 1;
+ new_domain = (char *) malloc (len);
+ if (new_domain != NULL)
+ memcpy (new_domain, domainname, len);
+#endif
+
+ if (new_domain != NULL)
+ _nl_current_default_domain = new_domain;
+ }
+
+ /* We use this possibility to signal a change of the loaded catalogs
+ since this is most likely the case and there is no other easy we
+ to do it. Do it only when the call was successful. */
+ if (new_domain != NULL)
+ {
+ ++_nl_msg_cat_cntr;
+
+ if (old_domain != new_domain && old_domain != _nl_default_default_domain)
+ free (old_domain);
+ }
+
+ gl_rwlock_unlock (_nl_state_lock);
+
+ return new_domain;
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library. */
+weak_alias (__textdomain, textdomain);
+#endif
diff --git a/intl/vasnprintf.c b/intl/vasnprintf.c
new file mode 100644
index 000000000..8b073103b
--- /dev/null
+++ b/intl/vasnprintf.c
@@ -0,0 +1,890 @@
+/* vsprintf with automatic memory allocation.
+ Copyright (C) 1999, 2002-2006 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+/* Tell glibc's <stdio.h> to provide a prototype for snprintf().
+ This must come before <config.h> because <config.h> may include
+ <features.h>, and once <features.h> has been included, it's too late. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#include <config.h>
+#ifndef IN_LIBINTL
+# include <alloca.h>
+#endif
+
+/* Specification. */
+#if WIDE_CHAR_VERSION
+# include "vasnwprintf.h"
+#else
+# include "vasnprintf.h"
+#endif
+
+#include <stdio.h> /* snprintf(), sprintf() */
+#include <stdlib.h> /* abort(), malloc(), realloc(), free() */
+#include <string.h> /* memcpy(), strlen() */
+#include <errno.h> /* errno */
+#include <limits.h> /* CHAR_BIT */
+#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */
+#if WIDE_CHAR_VERSION
+# include "wprintf-parse.h"
+#else
+# include "printf-parse.h"
+#endif
+
+/* Checked size_t computations. */
+#include "xsize.h"
+
+#ifdef HAVE_WCHAR_T
+# ifdef HAVE_WCSLEN
+# define local_wcslen wcslen
+# else
+ /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
+ a dependency towards this library, here is a local substitute.
+ Define this substitute only once, even if this file is included
+ twice in the same compilation unit. */
+# ifndef local_wcslen_defined
+# define local_wcslen_defined 1
+static size_t
+local_wcslen (const wchar_t *s)
+{
+ const wchar_t *ptr;
+
+ for (ptr = s; *ptr != (wchar_t) 0; ptr++)
+ ;
+ return ptr - s;
+}
+# endif
+# endif
+#endif
+
+#if WIDE_CHAR_VERSION
+# define VASNPRINTF vasnwprintf
+# define CHAR_T wchar_t
+# define DIRECTIVE wchar_t_directive
+# define DIRECTIVES wchar_t_directives
+# define PRINTF_PARSE wprintf_parse
+# define USE_SNPRINTF 1
+# if HAVE_DECL__SNWPRINTF
+ /* On Windows, the function swprintf() has a different signature than
+ on Unix; we use the _snwprintf() function instead. */
+# define SNPRINTF _snwprintf
+# else
+ /* Unix. */
+# define SNPRINTF swprintf
+# endif
+#else
+# define VASNPRINTF vasnprintf
+# define CHAR_T char
+# define DIRECTIVE char_directive
+# define DIRECTIVES char_directives
+# define PRINTF_PARSE printf_parse
+# define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF)
+# if HAVE_DECL__SNPRINTF
+ /* Windows. */
+# define SNPRINTF _snprintf
+# else
+ /* Unix. */
+# define SNPRINTF snprintf
+# endif
+#endif
+
+CHAR_T *
+VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)
+{
+ DIRECTIVES d;
+ arguments a;
+
+ if (PRINTF_PARSE (format, &d, &a) < 0)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+#define CLEANUP() \
+ free (d.dir); \
+ if (a.arg) \
+ free (a.arg);
+
+ if (printf_fetchargs (args, &a) < 0)
+ {
+ CLEANUP ();
+ errno = EINVAL;
+ return NULL;
+ }
+
+ {
+ size_t buf_neededlength;
+ CHAR_T *buf;
+ CHAR_T *buf_malloced;
+ const CHAR_T *cp;
+ size_t i;
+ DIRECTIVE *dp;
+ /* Output string accumulator. */
+ CHAR_T *result;
+ size_t allocated;
+ size_t length;
+
+ /* Allocate a small buffer that will hold a directive passed to
+ sprintf or snprintf. */
+ buf_neededlength =
+ xsum4 (7, d.max_width_length, d.max_precision_length, 6);
+#if HAVE_ALLOCA
+ if (buf_neededlength < 4000 / sizeof (CHAR_T))
+ {
+ buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
+ buf_malloced = NULL;
+ }
+ else
+#endif
+ {
+ size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T));
+ if (size_overflow_p (buf_memsize))
+ goto out_of_memory_1;
+ buf = (CHAR_T *) malloc (buf_memsize);
+ if (buf == NULL)
+ goto out_of_memory_1;
+ buf_malloced = buf;
+ }
+
+ if (resultbuf != NULL)
+ {
+ result = resultbuf;
+ allocated = *lengthp;
+ }
+ else
+ {
+ result = NULL;
+ allocated = 0;
+ }
+ length = 0;
+ /* Invariants:
+ result is either == resultbuf or == NULL or malloc-allocated.
+ If length > 0, then result != NULL. */
+
+ /* Ensures that allocated >= needed. Aborts through a jump to
+ out_of_memory if needed is SIZE_MAX or otherwise too big. */
+#define ENSURE_ALLOCATION(needed) \
+ if ((needed) > allocated) \
+ { \
+ size_t memory_size; \
+ CHAR_T *memory; \
+ \
+ allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \
+ if ((needed) > allocated) \
+ allocated = (needed); \
+ memory_size = xtimes (allocated, sizeof (CHAR_T)); \
+ if (size_overflow_p (memory_size)) \
+ goto out_of_memory; \
+ if (result == resultbuf || result == NULL) \
+ memory = (CHAR_T *) malloc (memory_size); \
+ else \
+ memory = (CHAR_T *) realloc (result, memory_size); \
+ if (memory == NULL) \
+ goto out_of_memory; \
+ if (result == resultbuf && length > 0) \
+ memcpy (memory, result, length * sizeof (CHAR_T)); \
+ result = memory; \
+ }
+
+ for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
+ {
+ if (cp != dp->dir_start)
+ {
+ size_t n = dp->dir_start - cp;
+ size_t augmented_length = xsum (length, n);
+
+ ENSURE_ALLOCATION (augmented_length);
+ memcpy (result + length, cp, n * sizeof (CHAR_T));
+ length = augmented_length;
+ }
+ if (i == d.count)
+ break;
+
+ /* Execute a single directive. */
+ if (dp->conversion == '%')
+ {
+ size_t augmented_length;
+
+ if (!(dp->arg_index == ARG_NONE))
+ abort ();
+ augmented_length = xsum (length, 1);
+ ENSURE_ALLOCATION (augmented_length);
+ result[length] = '%';
+ length = augmented_length;
+ }
+ else
+ {
+ if (!(dp->arg_index != ARG_NONE))
+ abort ();
+
+ if (dp->conversion == 'n')
+ {
+ switch (a.arg[dp->arg_index].type)
+ {
+ case TYPE_COUNT_SCHAR_POINTER:
+ *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
+ break;
+ case TYPE_COUNT_SHORT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_short_pointer = length;
+ break;
+ case TYPE_COUNT_INT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_int_pointer = length;
+ break;
+ case TYPE_COUNT_LONGINT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
+ break;
+#ifdef HAVE_LONG_LONG_INT
+ case TYPE_COUNT_LONGLONGINT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
+ break;
+#endif
+ default:
+ abort ();
+ }
+ }
+ else
+ {
+ arg_type type = a.arg[dp->arg_index].type;
+ CHAR_T *p;
+ unsigned int prefix_count;
+ int prefixes[2];
+#if !USE_SNPRINTF
+ size_t tmp_length;
+ CHAR_T tmpbuf[700];
+ CHAR_T *tmp;
+
+ /* Allocate a temporary buffer of sufficient size for calling
+ sprintf. */
+ {
+ size_t width;
+ size_t precision;
+
+ width = 0;
+ if (dp->width_start != dp->width_end)
+ {
+ if (dp->width_arg_index != ARG_NONE)
+ {
+ int arg;
+
+ if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+ abort ();
+ arg = a.arg[dp->width_arg_index].a.a_int;
+ width = (arg < 0 ? (unsigned int) (-arg) : arg);
+ }
+ else
+ {
+ const CHAR_T *digitp = dp->width_start;
+
+ do
+ width = xsum (xtimes (width, 10), *digitp++ - '0');
+ while (digitp != dp->width_end);
+ }
+ }
+
+ precision = 6;
+ if (dp->precision_start != dp->precision_end)
+ {
+ if (dp->precision_arg_index != ARG_NONE)
+ {
+ int arg;
+
+ if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+ abort ();
+ arg = a.arg[dp->precision_arg_index].a.a_int;
+ precision = (arg < 0 ? 0 : arg);
+ }
+ else
+ {
+ const CHAR_T *digitp = dp->precision_start + 1;
+
+ precision = 0;
+ while (digitp != dp->precision_end)
+ precision = xsum (xtimes (precision, 10), *digitp++ - '0');
+ }
+ }
+
+ switch (dp->conversion)
+ {
+
+ case 'd': case 'i': case 'u':
+# ifdef HAVE_LONG_LONG_INT
+ if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ else
+# endif
+ if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ else
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ if (tmp_length < precision)
+ tmp_length = precision;
+ /* Multiply by 2, as an estimate for FLAG_GROUP. */
+ tmp_length = xsum (tmp_length, tmp_length);
+ /* Add 1, to account for a leading sign. */
+ tmp_length = xsum (tmp_length, 1);
+ break;
+
+ case 'o':
+# ifdef HAVE_LONG_LONG_INT
+ if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ else
+# endif
+ if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ else
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ if (tmp_length < precision)
+ tmp_length = precision;
+ /* Add 1, to account for a leading sign. */
+ tmp_length = xsum (tmp_length, 1);
+ break;
+
+ case 'x': case 'X':
+# ifdef HAVE_LONG_LONG_INT
+ if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ else
+# endif
+ if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ else
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ if (tmp_length < precision)
+ tmp_length = precision;
+ /* Add 2, to account for a leading sign or alternate form. */
+ tmp_length = xsum (tmp_length, 2);
+ break;
+
+ case 'f': case 'F':
+# ifdef HAVE_LONG_DOUBLE
+ if (type == TYPE_LONGDOUBLE)
+ tmp_length =
+ (unsigned int) (LDBL_MAX_EXP
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 10; /* sign, decimal point etc. */
+ else
+# endif
+ tmp_length =
+ (unsigned int) (DBL_MAX_EXP
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 10; /* sign, decimal point etc. */
+ tmp_length = xsum (tmp_length, precision);
+ break;
+
+ case 'e': case 'E': case 'g': case 'G':
+ case 'a': case 'A':
+ tmp_length =
+ 12; /* sign, decimal point, exponent etc. */
+ tmp_length = xsum (tmp_length, precision);
+ break;
+
+ case 'c':
+# if defined HAVE_WINT_T && !WIDE_CHAR_VERSION
+ if (type == TYPE_WIDE_CHAR)
+ tmp_length = MB_CUR_MAX;
+ else
+# endif
+ tmp_length = 1;
+ break;
+
+ case 's':
+# ifdef HAVE_WCHAR_T
+ if (type == TYPE_WIDE_STRING)
+ {
+ tmp_length =
+ local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
+
+# if !WIDE_CHAR_VERSION
+ tmp_length = xtimes (tmp_length, MB_CUR_MAX);
+# endif
+ }
+ else
+# endif
+ tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
+ break;
+
+ case 'p':
+ tmp_length =
+ (unsigned int) (sizeof (void *) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1 /* turn floor into ceil */
+ + 2; /* account for leading 0x */
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (tmp_length < width)
+ tmp_length = width;
+
+ tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
+ }
+
+ if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
+ tmp = tmpbuf;
+ else
+ {
+ size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T));
+
+ if (size_overflow_p (tmp_memsize))
+ /* Overflow, would lead to out of memory. */
+ goto out_of_memory;
+ tmp = (CHAR_T *) malloc (tmp_memsize);
+ if (tmp == NULL)
+ /* Out of memory. */
+ goto out_of_memory;
+ }
+#endif
+
+ /* Construct the format string for calling snprintf or
+ sprintf. */
+ p = buf;
+ *p++ = '%';
+ if (dp->flags & FLAG_GROUP)
+ *p++ = '\'';
+ if (dp->flags & FLAG_LEFT)
+ *p++ = '-';
+ if (dp->flags & FLAG_SHOWSIGN)
+ *p++ = '+';
+ if (dp->flags & FLAG_SPACE)
+ *p++ = ' ';
+ if (dp->flags & FLAG_ALT)
+ *p++ = '#';
+ if (dp->flags & FLAG_ZERO)
+ *p++ = '0';
+ if (dp->width_start != dp->width_end)
+ {
+ size_t n = dp->width_end - dp->width_start;
+ memcpy (p, dp->width_start, n * sizeof (CHAR_T));
+ p += n;
+ }
+ if (dp->precision_start != dp->precision_end)
+ {
+ size_t n = dp->precision_end - dp->precision_start;
+ memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
+ p += n;
+ }
+
+ switch (type)
+ {
+#ifdef HAVE_LONG_LONG_INT
+ case TYPE_LONGLONGINT:
+ case TYPE_ULONGLONGINT:
+ *p++ = 'l';
+ /*FALLTHROUGH*/
+#endif
+ case TYPE_LONGINT:
+ case TYPE_ULONGINT:
+#ifdef HAVE_WINT_T
+ case TYPE_WIDE_CHAR:
+#endif
+#ifdef HAVE_WCHAR_T
+ case TYPE_WIDE_STRING:
+#endif
+ *p++ = 'l';
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case TYPE_LONGDOUBLE:
+ *p++ = 'L';
+ break;
+#endif
+ default:
+ break;
+ }
+ *p = dp->conversion;
+#if USE_SNPRINTF
+ p[1] = '%';
+ p[2] = 'n';
+ p[3] = '\0';
+#else
+ p[1] = '\0';
+#endif
+
+ /* Construct the arguments for calling snprintf or sprintf. */
+ prefix_count = 0;
+ if (dp->width_arg_index != ARG_NONE)
+ {
+ if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+ abort ();
+ prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
+ }
+ if (dp->precision_arg_index != ARG_NONE)
+ {
+ if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+ abort ();
+ prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
+ }
+
+#if USE_SNPRINTF
+ /* Prepare checking whether snprintf returns the count
+ via %n. */
+ ENSURE_ALLOCATION (xsum (length, 1));
+ result[length] = '\0';
+#endif
+
+ for (;;)
+ {
+ size_t maxlen;
+ int count;
+ int retcount;
+
+ maxlen = allocated - length;
+ count = -1;
+ retcount = 0;
+
+#if USE_SNPRINTF
+# define SNPRINTF_BUF(arg) \
+ switch (prefix_count) \
+ { \
+ case 0: \
+ retcount = SNPRINTF (result + length, maxlen, buf, \
+ arg, &count); \
+ break; \
+ case 1: \
+ retcount = SNPRINTF (result + length, maxlen, buf, \
+ prefixes[0], arg, &count); \
+ break; \
+ case 2: \
+ retcount = SNPRINTF (result + length, maxlen, buf, \
+ prefixes[0], prefixes[1], arg, \
+ &count); \
+ break; \
+ default: \
+ abort (); \
+ }
+#else
+# define SNPRINTF_BUF(arg) \
+ switch (prefix_count) \
+ { \
+ case 0: \
+ count = sprintf (tmp, buf, arg); \
+ break; \
+ case 1: \
+ count = sprintf (tmp, buf, prefixes[0], arg); \
+ break; \
+ case 2: \
+ count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
+ arg); \
+ break; \
+ default: \
+ abort (); \
+ }
+#endif
+
+ switch (type)
+ {
+ case TYPE_SCHAR:
+ {
+ int arg = a.arg[dp->arg_index].a.a_schar;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UCHAR:
+ {
+ unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_SHORT:
+ {
+ int arg = a.arg[dp->arg_index].a.a_short;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_USHORT:
+ {
+ unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_INT:
+ {
+ int arg = a.arg[dp->arg_index].a.a_int;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UINT:
+ {
+ unsigned int arg = a.arg[dp->arg_index].a.a_uint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_LONGINT:
+ {
+ long int arg = a.arg[dp->arg_index].a.a_longint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_ULONGINT:
+ {
+ unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_LONG_LONG_INT
+ case TYPE_LONGLONGINT:
+ {
+ long long int arg = a.arg[dp->arg_index].a.a_longlongint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_ULONGLONGINT:
+ {
+ unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_DOUBLE:
+ {
+ double arg = a.arg[dp->arg_index].a.a_double;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case TYPE_LONGDOUBLE:
+ {
+ long double arg = a.arg[dp->arg_index].a.a_longdouble;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_CHAR:
+ {
+ int arg = a.arg[dp->arg_index].a.a_char;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_WINT_T
+ case TYPE_WIDE_CHAR:
+ {
+ wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_STRING:
+ {
+ const char *arg = a.arg[dp->arg_index].a.a_string;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_WCHAR_T
+ case TYPE_WIDE_STRING:
+ {
+ const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_POINTER:
+ {
+ void *arg = a.arg[dp->arg_index].a.a_pointer;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ default:
+ abort ();
+ }
+
+#if USE_SNPRINTF
+ /* Portability: Not all implementations of snprintf()
+ are ISO C 99 compliant. Determine the number of
+ bytes that snprintf() has produced or would have
+ produced. */
+ if (count >= 0)
+ {
+ /* Verify that snprintf() has NUL-terminated its
+ result. */
+ if (count < maxlen && result[length + count] != '\0')
+ abort ();
+ /* Portability hack. */
+ if (retcount > count)
+ count = retcount;
+ }
+ else
+ {
+ /* snprintf() doesn't understand the '%n'
+ directive. */
+ if (p[1] != '\0')
+ {
+ /* Don't use the '%n' directive; instead, look
+ at the snprintf() return value. */
+ p[1] = '\0';
+ continue;
+ }
+ else
+ {
+ /* Look at the snprintf() return value. */
+ if (retcount < 0)
+ {
+ /* HP-UX 10.20 snprintf() is doubly deficient:
+ It doesn't understand the '%n' directive,
+ *and* it returns -1 (rather than the length
+ that would have been required) when the
+ buffer is too small. */
+ size_t bigger_need =
+ xsum (xtimes (allocated, 2), 12);
+ ENSURE_ALLOCATION (bigger_need);
+ continue;
+ }
+ else
+ count = retcount;
+ }
+ }
+#endif
+
+ /* Attempt to handle failure. */
+ if (count < 0)
+ {
+ if (!(result == resultbuf || result == NULL))
+ free (result);
+ if (buf_malloced != NULL)
+ free (buf_malloced);
+ CLEANUP ();
+ errno = EINVAL;
+ return NULL;
+ }
+
+#if !USE_SNPRINTF
+ if (count >= tmp_length)
+ /* tmp_length was incorrectly calculated - fix the
+ code above! */
+ abort ();
+#endif
+
+ /* Make room for the result. */
+ if (count >= maxlen)
+ {
+ /* Need at least count bytes. But allocate
+ proportionally, to avoid looping eternally if
+ snprintf() reports a too small count. */
+ size_t n =
+ xmax (xsum (length, count), xtimes (allocated, 2));
+
+ ENSURE_ALLOCATION (n);
+#if USE_SNPRINTF
+ continue;
+#endif
+ }
+
+#if USE_SNPRINTF
+ /* The snprintf() result did fit. */
+#else
+ /* Append the sprintf() result. */
+ memcpy (result + length, tmp, count * sizeof (CHAR_T));
+ if (tmp != tmpbuf)
+ free (tmp);
+#endif
+
+ length += count;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Add the final NUL. */
+ ENSURE_ALLOCATION (xsum (length, 1));
+ result[length] = '\0';
+
+ if (result != resultbuf && length + 1 < allocated)
+ {
+ /* Shrink the allocated memory if possible. */
+ CHAR_T *memory;
+
+ memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T));
+ if (memory != NULL)
+ result = memory;
+ }
+
+ if (buf_malloced != NULL)
+ free (buf_malloced);
+ CLEANUP ();
+ *lengthp = length;
+ /* Note that we can produce a big string of a length > INT_MAX. POSIX
+ says that snprintf() fails with errno = EOVERFLOW in this case, but
+ that's only because snprintf() returns an 'int'. This function does
+ not have this limitation. */
+ return result;
+
+ out_of_memory:
+ if (!(result == resultbuf || result == NULL))
+ free (result);
+ if (buf_malloced != NULL)
+ free (buf_malloced);
+ out_of_memory_1:
+ CLEANUP ();
+ errno = ENOMEM;
+ return NULL;
+ }
+}
+
+#undef SNPRINTF
+#undef USE_SNPRINTF
+#undef PRINTF_PARSE
+#undef DIRECTIVES
+#undef DIRECTIVE
+#undef CHAR_T
+#undef VASNPRINTF
diff --git a/intl/vasnprintf.h b/intl/vasnprintf.h
new file mode 100644
index 000000000..e67b88da3
--- /dev/null
+++ b/intl/vasnprintf.h
@@ -0,0 +1,78 @@
+/* vsprintf with automatic memory allocation.
+ Copyright (C) 2002-2004 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _VASNPRINTF_H
+#define _VASNPRINTF_H
+
+/* Get va_list. */
+#include <stdarg.h>
+
+/* Get size_t. */
+#include <stddef.h>
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+# define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __format__ format
+# define __printf__ printf
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Write formatted output to a string dynamically allocated with malloc().
+ You can pass a preallocated buffer for the result in RESULTBUF and its
+ size in *LENGTHP; otherwise you pass RESULTBUF = NULL.
+ If successful, return the address of the string (this may be = RESULTBUF
+ if no dynamic memory allocation was necessary) and set *LENGTHP to the
+ number of resulting bytes, excluding the trailing NUL. Upon error, set
+ errno and return NULL.
+
+ When dynamic memory allocation occurs, the preallocated buffer is left
+ alone (with possibly modified contents). This makes it possible to use
+ a statically allocated or stack-allocated buffer, like this:
+
+ char buf[100];
+ size_t len = sizeof (buf);
+ char *output = vasnprintf (buf, &len, format, args);
+ if (output == NULL)
+ ... error handling ...;
+ else
+ {
+ ... use the output string ...;
+ if (output != buf)
+ free (output);
+ }
+ */
+extern char * asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+extern char * vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args)
+ __attribute__ ((__format__ (__printf__, 3, 0)));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VASNPRINTF_H */
diff --git a/intl/vasnwprintf.h b/intl/vasnwprintf.h
new file mode 100644
index 000000000..6ff03ce16
--- /dev/null
+++ b/intl/vasnwprintf.h
@@ -0,0 +1,46 @@
+/* vswprintf with automatic memory allocation.
+ Copyright (C) 2002-2003 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _VASNWPRINTF_H
+#define _VASNWPRINTF_H
+
+/* Get va_list. */
+#include <stdarg.h>
+
+/* Get wchar_t, size_t. */
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Write formatted output to a string dynamically allocated with malloc().
+ You can pass a preallocated buffer for the result in RESULTBUF and its
+ size in *LENGTHP; otherwise you pass RESULTBUF = NULL.
+ If successful, return the address of the string (this may be = RESULTBUF
+ if no dynamic memory allocation was necessary) and set *LENGTHP to the
+ number of resulting bytes, excluding the trailing NUL. Upon error, set
+ errno and return NULL. */
+extern wchar_t * asnwprintf (wchar_t *resultbuf, size_t *lengthp, const wchar_t *format, ...);
+extern wchar_t * vasnwprintf (wchar_t *resultbuf, size_t *lengthp, const wchar_t *format, va_list args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VASNWPRINTF_H */
diff --git a/intl/version.c b/intl/version.c
new file mode 100644
index 000000000..a968cf746
--- /dev/null
+++ b/intl/version.c
@@ -0,0 +1,26 @@
+/* libintl library version.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libgnuintl.h"
+
+/* Version number: (major<<16) + (minor<<8) + subminor */
+int libintl_version = LIBINTL_VERSION;
diff --git a/intl/wprintf-parse.h b/intl/wprintf-parse.h
new file mode 100644
index 000000000..600b89adc
--- /dev/null
+++ b/intl/wprintf-parse.h
@@ -0,0 +1,75 @@
+/* Parse printf format string.
+ Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _WPRINTF_PARSE_H
+#define _WPRINTF_PARSE_H
+
+#include "printf-args.h"
+
+
+/* Flags */
+#define FLAG_GROUP 1 /* ' flag */
+#define FLAG_LEFT 2 /* - flag */
+#define FLAG_SHOWSIGN 4 /* + flag */
+#define FLAG_SPACE 8 /* space flag */
+#define FLAG_ALT 16 /* # flag */
+#define FLAG_ZERO 32
+
+/* arg_index value indicating that no argument is consumed. */
+#define ARG_NONE (~(size_t)0)
+
+/* A parsed directive. */
+typedef struct
+{
+ const wchar_t* dir_start;
+ const wchar_t* dir_end;
+ int flags;
+ const wchar_t* width_start;
+ const wchar_t* width_end;
+ size_t width_arg_index;
+ const wchar_t* precision_start;
+ const wchar_t* precision_end;
+ size_t precision_arg_index;
+ wchar_t conversion; /* d i o u x X f e E g G c s p n U % but not C S */
+ size_t arg_index;
+}
+wchar_t_directive;
+
+/* A parsed format string. */
+typedef struct
+{
+ size_t count;
+ wchar_t_directive *dir;
+ size_t max_width_length;
+ size_t max_precision_length;
+}
+wchar_t_directives;
+
+
+/* Parses the format string. Fills in the number N of directives, and fills
+ in directives[0], ..., directives[N-1], and sets directives[N].dir_start
+ to the end of the format string. Also fills in the arg_type fields of the
+ arguments and the needed count of arguments. */
+#ifdef STATIC
+STATIC
+#else
+extern
+#endif
+int wprintf_parse (const wchar_t *format, wchar_t_directives *d, arguments *a);
+
+#endif /* _WPRINTF_PARSE_H */
diff --git a/intl/xsize.h b/intl/xsize.h
new file mode 100644
index 000000000..b3023a7d4
--- /dev/null
+++ b/intl/xsize.h
@@ -0,0 +1,109 @@
+/* xsize.h -- Checked size_t computations.
+
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _XSIZE_H
+#define _XSIZE_H
+
+/* Get size_t. */
+#include <stddef.h>
+
+/* Get SIZE_MAX. */
+#include <limits.h>
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+/* The size of memory objects is often computed through expressions of
+ type size_t. Example:
+ void* p = malloc (header_size + n * element_size).
+ These computations can lead to overflow. When this happens, malloc()
+ returns a piece of memory that is way too small, and the program then
+ crashes while attempting to fill the memory.
+ To avoid this, the functions and macros in this file check for overflow.
+ The convention is that SIZE_MAX represents overflow.
+ malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc
+ implementation that uses mmap --, it's recommended to use size_overflow_p()
+ or size_in_bounds_p() before invoking malloc().
+ The example thus becomes:
+ size_t size = xsum (header_size, xtimes (n, element_size));
+ void *p = (size_in_bounds_p (size) ? malloc (size) : NULL);
+*/
+
+/* Convert an arbitrary value >= 0 to type size_t. */
+#define xcast_size_t(N) \
+ ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX)
+
+/* Sum of two sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xsum (size_t size1, size_t size2)
+{
+ size_t sum = size1 + size2;
+ return (sum >= size1 ? sum : SIZE_MAX);
+}
+
+/* Sum of three sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xsum3 (size_t size1, size_t size2, size_t size3)
+{
+ return xsum (xsum (size1, size2), size3);
+}
+
+/* Sum of four sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xsum4 (size_t size1, size_t size2, size_t size3, size_t size4)
+{
+ return xsum (xsum (xsum (size1, size2), size3), size4);
+}
+
+/* Maximum of two sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xmax (size_t size1, size_t size2)
+{
+ /* No explicit check is needed here, because for any n:
+ max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX. */
+ return (size1 >= size2 ? size1 : size2);
+}
+
+/* Multiplication of a count with an element size, with overflow check.
+ The count must be >= 0 and the element size must be > 0.
+ This is a macro, not an inline function, so that it works correctly even
+ when N is of a wider tupe and N > SIZE_MAX. */
+#define xtimes(N, ELSIZE) \
+ ((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX)
+
+/* Check for overflow. */
+#define size_overflow_p(SIZE) \
+ ((SIZE) == SIZE_MAX)
+/* Check against overflow. */
+#define size_in_bounds_p(SIZE) \
+ ((SIZE) != SIZE_MAX)
+
+#endif /* _XSIZE_H */