/* Implementation of the internal dcigettext function.
- Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1995-2002,2003,2004,2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
+ 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
- Library General Public License for more details.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
/* Tell glibc's <string.h> to provide a prototype for mempcpy().
This must come before <config.h> because <config.h> may include
#include <sys/types.h>
-#if defined __GNUC__ && !defined C_ALLOCA
+#ifdef __GNUC__
# define alloca __builtin_alloca
# define HAVE_ALLOCA 1
#else
-# if (defined HAVE_ALLOCA_H || defined _LIBC) && !defined C_ALLOCA
+# if defined HAVE_ALLOCA_H || defined _LIBC
# include <alloca.h>
# else
# ifdef _AIX
# define __set_errno(val) errno = (val)
#endif
-#if defined STDC_HEADERS || defined _LIBC
-# include <stddef.h>
-# include <stdlib.h>
-#else
-char *getenv ();
-# ifdef HAVE_MALLOC_H
-# include <malloc.h>
-# else
-void free ();
-# endif
-#endif
-
-#if defined HAVE_STRING_H || defined _LIBC
-# include <string.h>
-#else
-# include <strings.h>
-#endif
-#if !HAVE_STRCHR && !defined _LIBC
-# ifndef strchr
-# define strchr index
-# endif
-#endif
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
#if defined HAVE_UNISTD_H || defined _LIBC
# include <unistd.h>
#endif
-#if defined HAVE_LOCALE_H || defined _LIBC
-# include <locale.h>
-#endif
+#include <locale.h>
#if defined HAVE_SYS_PARAM_H || defined _LIBC
# include <sys/param.h>
#endif
-#include "gettext.h"
#include "gettextP.h"
+#include "plural-exp.h"
#ifdef _LIBC
# include <libintl.h>
#else
-# include "libgettext.h"
+# include "libgnuintl.h"
#endif
#include "hash-string.h"
((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
# ifndef stpcpy
# define stpcpy __stpcpy
# endif
+# define tfind __tfind
#else
# if !defined HAVE_GETCWD
char *getwd ();
# define PATH_MAX _POSIX_PATH_MAX
#endif
-/* XPG3 defines the result of `setlocale (category, NULL)' as:
- ``Directs `setlocale()' to query `category' and return the current
- setting of `local'.''
- However it does not specify the exact format. And even worse: POSIX
- defines this not at all. So we can use this feature only on selected
- system (e.g. those using GNU C Library). */
-#ifdef _LIBC
-# define HAVE_LOCALE_NULL
-#endif
-
-/* We want to allocate a string at the end of the struct. gcc makes
- this easy. */
-#ifdef __GNUC__
-# define ZERO 0
-#else
-# define ZERO 1
-#endif
-
/* This is the type used for the search tree where known translations
are stored. */
struct known_translation_t
{
/* Domain in which to search. */
- char *domain;
-
- /* Plural index. */
- unsigned long int plindex;
+ const char *domainname;
/* The category. */
int category;
/* 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];
# endif
/* Function to compare two entries in the table of known translations. */
+static int transcmp PARAMS ((const void *p1, const void *p2));
static int
-transcmp (const void *p1, const void *p2)
+transcmp (p1, p2)
+ const void *p1;
+ const void *p2;
{
- struct known_translation_t *s1 = (struct known_translation_t *) p1;
- struct known_translation_t *s2 = (struct known_translation_t *) 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->domain, s2->domain);
+ result = strcmp (s1->domainname, s2->domainname);
if (result == 0)
- {
- result = s1->plindex - s2->plindex;
- if (result == 0)
- /* 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;
- }
+ /* 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;
/* Name of the default domain used for gettext(3) prior any call to
textdomain(3). The default value for this is "messages". */
-const char _nl_default_default_domain[] = "messages";
+const char _nl_default_default_domain[] attribute_hidden = "messages";
/* Value used as the default domain for gettext(3). */
-const char *_nl_current_default_domain = _nl_default_default_domain;
+const char *_nl_current_default_domain attribute_hidden
+ = _nl_default_default_domain;
/* Contains the default location of the message catalogs. */
-const char _nl_default_dirname[] = GNULOCALEDIR;
+
+#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
/* List with bindings of specific domains created by bindtextdomain()
calls. */
struct binding *_nl_domain_bindings;
/* Prototypes for local functions. */
-static unsigned long int plural_eval (struct expression *pexp,
- unsigned long int n) internal_function;
-static const char *category_to_name PARAMS ((int category)) internal_function;
+static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
+ unsigned long int n,
+ const char *translation,
+ size_t translation_len))
+ internal_function;
static const char *guess_category_value PARAMS ((int category,
const char *categoryname))
internal_function;
+#ifdef _LIBC
+# include "../locale/localeinfo.h"
+# define category_to_name(category) _nl_category_names[category]
+#else
+static const char *category_to_name PARAMS ((int category)) 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
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. */
-static struct transmem_list
+typedef struct transmem_list
{
struct transmem_list *next;
- char data[0];
-} *transmem_list;
+ 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
#ifdef _LIBC
# define DCIGETTEXT __dcigettext
#else
-# define DCIGETTEXT dcigettext__
+# define DCIGETTEXT libintl_dcigettext
#endif
/* Lock variable to protect the global data in the gettext implementation. */
-__libc_rwlock_define_initialized (, _nl_state_lock)
+#ifdef _LIBC
+__libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
+#endif
/* Checking whether the binaries runs SUID must be done and glibc provides
easier methods therefore we make a difference here. */
# 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 \
}
#endif
+/* Get the function to evaluate the plural expression. */
+#include "plural-eval.c"
+
/* 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. */
char *dirname, *xdomainname;
char *single_locale;
char *retval;
+ size_t retlen;
int saved_errno;
#if defined HAVE_TSEARCH || defined _LIBC
struct known_translation_t *search;
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
+
__libc_rwlock_rdlock (_nl_state_lock);
/* If DOMAINNAME is NULL, we are interested in the default domain. If
#if defined HAVE_TSEARCH || defined _LIBC
msgid_len = strlen (msgid1) + 1;
- if (plural == 0)
+ /* 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;
+
+ /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
+ tsearch calls can be fatal. */
+ __libc_rwlock_define_initialized (static, tree_lock);
+ __libc_rwlock_rdlock (tree_lock);
+
+ foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
+
+ __libc_rwlock_unlock (tree_lock);
+
+ freea (search);
+ if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
{
- /* Try to find the translation among those which we found at
- some time. */
- search = (struct known_translation_t *) alloca (sizeof (*search)
- + msgid_len);
- memcpy (search->msgid, msgid1, msgid_len);
- search->domain = (char *) domainname;
- search->plindex = 0;
- search->category = category;
-
- foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
- if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
- {
- __libc_rwlock_unlock (_nl_state_lock);
- return (char *) (*foundp)->translation;
- }
+ /* Now deal with plural. */
+ if (plural)
+ retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
+ (*foundp)->translation_length);
+ else
+ retval = (char *) (*foundp)->translation;
+
+ __libc_rwlock_unlock (_nl_state_lock);
+ return retval;
}
#endif
path_max = (unsigned int) PATH_MAX;
path_max += 2; /* The getcwd docs say to do this. */
- dirname = (char *) alloca (path_max + dirname_len);
- ADD_BLOCK (block_list, dirname);
-
- __set_errno (0);
- while ((ret = getcwd (dirname, path_max)) == NULL && errno == ERANGE)
+ for (;;)
{
- path_max += PATH_INCR;
dirname = (char *) alloca (path_max + dirname_len);
ADD_BLOCK (block_list, dirname);
+
__set_errno (0);
+ ret = getcwd (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. */
FREE_BLOCKS (block_list);
+ __libc_rwlock_unlock (_nl_state_lock);
__set_errno (saved_errno);
return (plural == 0
? (char *) msgid1
/* When this is a SUID binary we must not allow accessing files
outside the dedicated directories. */
- if (ENABLE_SECURE
- && (memchr (single_locale, '/',
- _nl_find_language (single_locale) - single_locale)
- != NULL))
+ if (ENABLE_SECURE && strchr (single_locale, '/') != NULL)
/* Ingore this entry. */
continue;
}
if (domain != NULL)
{
- unsigned long int index = 0;
-
- if (plural != 0)
- {
- struct loaded_domain *domaindata =
- (struct loaded_domain *) domain->data;
- 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;
-
-#if defined HAVE_TSEARCH || defined _LIBC
- /* Try to find the translation among those which we
- found at some time. */
- search = (struct known_translation_t *) alloca (sizeof (*search)
- + msgid_len);
- memcpy (search->msgid, msgid1, msgid_len);
- search->domain = (char *) domainname;
- search->plindex = index;
- search->category = category;
-
- foundp = (struct known_translation_t **) tfind (search, &root,
- transcmp);
- if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
- {
- __libc_rwlock_unlock (_nl_state_lock);
- return (char *) (*foundp)->translation;
- }
-#endif
- }
-
- retval = _nl_find_msg (domain, msgid1, index);
+ retval = _nl_find_msg (domain, binding, msgid1, &retlen);
if (retval == NULL)
{
for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
{
- retval = _nl_find_msg (domain->successor[cnt], msgid1,
- index);
+ retval = _nl_find_msg (domain->successor[cnt], binding,
+ msgid1, &retlen);
if (retval != NULL)
- break;
+ {
+ domain = domain->successor[cnt];
+ break;
+ }
}
}
if (retval != NULL)
{
+ /* Found the translation of MSGID1 in domain DOMAIN:
+ starting at RETVAL, RETLEN bytes. */
FREE_BLOCKS (block_list);
- __set_errno (saved_errno);
#if defined HAVE_TSEARCH || defined _LIBC
if (foundp == NULL)
{
struct known_translation_t *newp;
newp = (struct known_translation_t *)
- malloc (sizeof (*newp) + msgid_len
- + domainname_len + 1 - ZERO);
+ malloc (offsetof (struct known_translation_t, msgid)
+ + msgid_len + domainname_len + 1);
if (newp != NULL)
{
- newp->domain = mempcpy (newp->msgid, msgid1, msgid_len);
- memcpy (newp->domain, domainname, domainname_len + 1);
- newp->plindex = index;
+ char *new_domainname;
+
+ new_domainname = mempcpy (newp->msgid, msgid1, msgid_len);
+ memcpy (new_domainname, domainname, domainname_len + 1);
+ newp->domainname = new_domainname;
newp->category = category;
newp->counter = _nl_msg_cat_cntr;
+ newp->domain = domain;
newp->translation = retval;
+ newp->translation_length = retlen;
+
+ __libc_rwlock_wrlock (tree_lock);
/* Insert the entry in the search tree. */
foundp = (struct known_translation_t **)
tsearch (newp, &root, transcmp);
+
+ __libc_rwlock_unlock (tree_lock);
+
if (foundp == NULL
|| __builtin_expect (*foundp != newp, 0))
/* The insert failed. */
{
/* 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);
+
__libc_rwlock_unlock (_nl_state_lock);
return retval;
}
char *
internal_function
-_nl_find_msg (domain_file, msgid, index)
+_nl_find_msg (domain_file, domainbinding, msgid, lengthp)
struct loaded_l10nfile *domain_file;
+ struct binding *domainbinding;
const char *msgid;
- unsigned long int index;
+ size_t *lengthp;
{
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);
+ 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_size > 2 && domain->hash_tab != NULL)
+ if (domain->hash_tab != NULL)
{
/* Use the hashing table. */
nls_uint32 len = strlen (msgid);
- nls_uint32 hash_val = hash_string (msgid);
+ nls_uint32 hash_val = __hash_string (msgid);
nls_uint32 idx = hash_val % domain->hash_size;
nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
- nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
-
- if (nstr == 0)
- /* Hash table entry is empty. */
- return NULL;
-
- if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
- && strcmp (msgid,
- domain->data + W (domain->must_swap,
- domain->orig_tab[nstr - 1].offset)) == 0)
- {
- act = nstr - 1;
- goto found;
- }
while (1)
{
- if (idx >= domain->hash_size - incr)
- idx -= domain->hash_size - incr;
- else
- idx += incr;
+ nls_uint32 nstr =
+ W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
- nstr = W (domain->must_swap, domain->hash_tab[idx]);
if (nstr == 0)
/* Hash table entry is empty. */
return NULL;
- if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
- && (strcmp (msgid,
- domain->data + W (domain->must_swap,
- domain->orig_tab[nstr - 1].offset))
- == 0))
+ 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 - 1;
+ act = nstr;
goto found;
}
+
+ if (idx >= domain->hash_size - incr)
+ idx -= domain->hash_size - incr;
+ else
+ idx += incr;
}
/* NOTREACHED */
}
size_t top, bottom;
bottom = 0;
- top = domain->nstrings;
+ top = nstrings;
while (bottom < top)
{
int cmp_val;
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. */
- result = ((char *) domain->data
- + W (domain->must_swap, domain->trans_tab[act].offset));
+ 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
+ if (domain->codeset_cntr
+ != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
+ {
+ /* The domain's codeset has changed through bind_textdomain_codeset()
+ since the message catalog was initialized or last accessed. We
+ have to reinitialize the converter. */
+ _nl_free_domain_conv (domain);
+ _nl_init_domain_conv (domain_file, domain, domainbinding);
+ }
+
if (
# ifdef _LIBC
domain->conv != (__gconv_t) -1
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 the INDEX: We don't know
- a priori which entries are plural entries. Therefore at any
- moment we can only translate the variants 0 .. INDEX. */
+ 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 (domain->conv_tab == NULL
- && ((domain->conv_tab = (char **) calloc (domain->nstrings,
- sizeof (char *)))
+ && ((domain->conv_tab =
+ (char **) calloc (nstrings + domain->n_sysdep_strings,
+ sizeof (char *)))
== NULL))
/* Mark that we didn't succeed allocating a table. */
domain->conv_tab = (char **) -1;
/* Nothing we can do, no more memory. */
goto converted;
- if (domain->conv_tab[act] == NULL
- || *(nls_uint32 *) domain->conv_tab[act] < index)
+ if (domain->conv_tab[act] == NULL)
{
/* We haven't used this string so far, so it is not
translated yet. Do this now. */
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
+# define INITIAL_BLOCK_SIZE 4080
static unsigned char *freemem;
static size_t freemem_size;
- size_t resultlen;
const unsigned char *inbuf;
unsigned char *outbuf;
int malloc_count;
-
- /* Note that we translate (index + 1) consecutive strings at
- once, including the final NUL byte. */
- {
- unsigned long int i = index;
- char *p = result;
- do
- p += strlen (p) + 1;
- while (i-- > 0);
- resultlen = p - result;
- }
+# ifndef _LIBC
+ transmem_block_t *transmem_list = NULL;
+# endif
__libc_lock_lock (lock);
- inbuf = result;
- outbuf = freemem + sizeof (nls_uint32);
+ inbuf = (const unsigned char *) result;
+ outbuf = freemem + sizeof (size_t);
malloc_count = 0;
while (1)
{
+ transmem_block_t *newmem;
# ifdef _LIBC
- struct transmem_list *newmem;
size_t non_reversible;
int res;
- if (freemem_size < 4)
+ if (freemem_size < sizeof (size_t))
goto resize_freemem;
res = __gconv (domain->conv,
&inbuf, inbuf + resultlen,
&outbuf,
- outbuf + freemem_size - sizeof (nls_uint32),
+ outbuf + freemem_size - sizeof (size_t),
&non_reversible);
if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
goto converted;
}
- inbuf = result;
+ inbuf = (const unsigned char *) result;
# else
# if HAVE_ICONV
-# define transmem freemem
const char *inptr = (const char *) inbuf;
size_t inleft = resultlen;
char *outptr = (char *) outbuf;
size_t outleft;
- if (freemem_size < 4)
+ if (freemem_size < sizeof (size_t))
goto resize_freemem;
- outleft = freemem_size - 4;
- if (iconv (domain->conv, &inptr, &inleft, &outptr, &outleft)
+ outleft = freemem_size - sizeof (size_t);
+ if (iconv (domain->conv,
+ (ICONV_CONST char **) &inptr, &inleft,
+ &outptr, &outleft)
!= (size_t) (-1))
{
outbuf = (unsigned char *) outptr;
__libc_lock_unlock (lock);
goto converted;
}
-# else
-# define transmem freemem
# endif
# endif
resize_freemem:
- /* We must allocate a new buffer of resize the old one. */
+ /* We must allocate a new buffer or resize the old one. */
if (malloc_count > 0)
{
- struct transmem_list *next = transmem_list->next;
-
++malloc_count;
freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
- newmem = (struct transmem_list *) realloc (transmem_list,
- freemem_size);
-
+ newmem = (transmem_block_t *) realloc (transmem_list,
+ freemem_size);
+# ifdef _LIBC
if (newmem != NULL)
- transmem_list = next;
+ 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 = (struct transmem_list *) malloc (freemem_size);
+ newmem = (transmem_block_t *) malloc (freemem_size);
}
if (__builtin_expect (newmem == NULL, 0))
{
newmem->next = transmem_list;
transmem_list = newmem;
- freemem = newmem->data;
+ freemem = (unsigned char *) newmem->data;
freemem_size -= offsetof (struct transmem_list, data);
+# else
+ transmem_list = newmem;
+ freemem = newmem;
# endif
- outbuf = freemem + sizeof (nls_uint32);
+ outbuf = freemem + sizeof (size_t);
}
/* We have now in our buffer a converted string. Put this
into the table of conversions. */
- *(nls_uint32 *) freemem = index;
- domain->conv_tab[act] = freemem;
+ *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
+ domain->conv_tab[act] = (char *) freemem;
/* Shrink freemem, but keep it aligned. */
freemem_size -= outbuf - freemem;
freemem = outbuf;
- freemem += freemem_size & (alignof (nls_uint32) - 1);
- freemem_size = freemem_size & ~ (alignof (nls_uint32) - 1);
+ freemem += freemem_size & (alignof (size_t) - 1);
+ freemem_size = freemem_size & ~ (alignof (size_t) - 1);
__libc_lock_unlock (lock);
}
- /* Now domain->conv_tab[act] contains the translation of at least
- the variants 0 .. INDEX. */
- result = domain->conv_tab[act] + sizeof (nls_uint32);
+ /* Now domain->conv_tab[act] contains the translation of all
+ the plural variants. */
+ result = domain->conv_tab[act] + sizeof (size_t);
+ resultlen = *(size_t *) domain->conv_tab[act];
}
converted:
#endif /* _LIBC || HAVE_ICONV */
- /* Now skip some strings. How much depends on the index passed in. */
- while (index-- > 0)
- {
-#ifdef _LIBC
- result = __rawmemchr (result, '\0');
-#else
- result = strchr (result, '\0');
-#endif
- /* And skip over the NUL byte. */
- ++result;
- }
-
+ *lengthp = resultlen;
return result;
}
-/* Function to evaluate the plural expression and return an index value. */
-static unsigned long int
+/* Look up a plural variant. */
+static char *
internal_function
-plural_eval (struct expression *pexp, unsigned long int n)
+plural_lookup (domain, n, translation, translation_len)
+ struct loaded_l10nfile *domain;
+ unsigned long int n;
+ const char *translation;
+ size_t translation_len;
{
- switch (pexp->operation)
+ 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)
{
- case var:
- return n;
- case num:
- return pexp->val.num;
- case mult:
- return (plural_eval (pexp->val.args2.left, n)
- * plural_eval (pexp->val.args2.right, n));
- case divide:
- return (plural_eval (pexp->val.args2.left, n)
- / plural_eval (pexp->val.args2.right, n));
- case module:
- return (plural_eval (pexp->val.args2.left, n)
- % plural_eval (pexp->val.args2.right, n));
- case plus:
- return (plural_eval (pexp->val.args2.left, n)
- + plural_eval (pexp->val.args2.right, n));
- case minus:
- return (plural_eval (pexp->val.args2.left, n)
- - plural_eval (pexp->val.args2.right, n));
- case equal:
- return (plural_eval (pexp->val.args2.left, n)
- == plural_eval (pexp->val.args2.right, n));
- case not_equal:
- return (plural_eval (pexp->val.args2.left, n)
- != plural_eval (pexp->val.args2.right, n));
- case land:
- return (plural_eval (pexp->val.args2.left, n)
- && plural_eval (pexp->val.args2.right, n));
- case lor:
- return (plural_eval (pexp->val.args2.left, n)
- || plural_eval (pexp->val.args2.right, n));
- case qmop:
- return (plural_eval (pexp->val.args3.bexp, n)
- ? plural_eval (pexp->val.args3.tbranch, n)
- : plural_eval (pexp->val.args3.fbranch, n));
+#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;
}
- /* NOTREACHED */
- return 0;
+ return (char *) p;
}
-
+#ifndef _LIBC
/* Return string representation of locale CATEGORY. */
static const char *
internal_function
return retval;
}
+#endif
/* Guess value of current locale from value of the environment variables. */
static const char *
int category;
const char *categoryname;
{
+ const char *language;
const char *retval;
/* The highest priority value is the `LANGUAGE' environment
- variable. This is a GNU extension. */
- retval = getenv ("LANGUAGE");
- if (retval != NULL && retval[0] != '\0')
- return retval;
-
- /* `LANGUAGE' is not set. So we have to proceed with the POSIX
- methods of looking to `LC_ALL', `LC_xxx', and `LANG'. On some
- systems this can be done by the `setlocale' function itself. */
-#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
- return setlocale (category, NULL);
+ variable. But we don't use the value if the currently selected
+ locale is the C locale. This is a GNU extension. */
+ language = getenv ("LANGUAGE");
+ if (language != NULL && language[0] == '\0')
+ language = NULL;
+
+ /* We have to proceed with the POSIX methods of looking to `LC_ALL',
+ `LC_xxx', and `LANG'. On some systems this can be done by the
+ `setlocale' function itself. */
+#ifdef _LIBC
+ retval = __current_locale_name (category);
#else
- /* Setting of LC_ALL overwrites all other. */
- retval = getenv ("LC_ALL");
- if (retval != NULL && retval[0] != '\0')
- return retval;
-
- /* Next comes the name of the desired category. */
- retval = getenv (categoryname);
- if (retval != NULL && retval[0] != '\0')
- return retval;
-
- /* Last possibility is the LANG environment variable. */
- retval = getenv ("LANG");
- if (retval != NULL && retval[0] != '\0')
- return retval;
-
- /* We use C as the default domain. POSIX says this is implementation
- defined. */
- return "C";
+ retval = _nl_locale_name (category, categoryname);
#endif
+
+ return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
}
/* @@ begin of epilog @@ */
#ifdef _LIBC
/* If we want to free all resources we have to do some work at
program's end. */
-static void __attribute__ ((unused))
-free_mem (void)
+libc_freeres_fn (free_mem)
{
- struct binding *runp;
void *old;
- for (runp = _nl_domain_bindings; runp != NULL; runp = runp->next)
+ while (_nl_domain_bindings != NULL)
{
- if (runp->dirname != _nl_default_dirname)
+ 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 (runp->dirname);
- if (runp->codeset != NULL)
- free (runp->codeset);
+ free (oldp->dirname);
+ free (oldp->codeset);
+ free (oldp);
}
if (_nl_current_default_domain != _nl_default_default_domain)
/* Remove the search tree with the known translations. */
__tdestroy (root, free);
+ root = NULL;
while (transmem_list != NULL)
{
free (old);
}
}
-
-text_set_element (__libc_subfreeres, free_mem);
#endif