aboutsummaryrefslogtreecommitdiff
path: root/intl/dcigettext.c
diff options
context:
space:
mode:
Diffstat (limited to 'intl/dcigettext.c')
-rw-r--r--intl/dcigettext.c301
1 files changed, 160 insertions, 141 deletions
diff --git a/intl/dcigettext.c b/intl/dcigettext.c
index 8712e4b..c6540b9 100644
--- a/intl/dcigettext.c
+++ b/intl/dcigettext.c
@@ -210,10 +210,7 @@ static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
struct known_translation_t
{
/* Domain in which to search. */
- char *domain;
-
- /* Plural index. */
- unsigned long int plindex;
+ char *domainname;
/* The category. */
int category;
@@ -221,8 +218,12 @@ struct known_translation_t
/* 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];
@@ -253,16 +254,12 @@ transcmp (const void *p1, const void *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;
@@ -284,8 +281,14 @@ const char _nl_default_dirname[] = GNULOCALEDIR;
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 char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
+ unsigned long int n,
+ const char *translation,
+ size_t translation_len))
+ internal_function;
+static unsigned long int plural_eval PARAMS ((struct expression *pexp,
+ unsigned long int n))
+ internal_function;
static const char *category_to_name PARAMS ((int category)) internal_function;
static const char *guess_category_value PARAMS ((int category,
const char *categoryname))
@@ -328,12 +331,17 @@ struct block_list
#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;
+} transmem_block_t;
+static struct transmem_list *transmem_list;
+#else
+typedef char transmem_block_t;
+#endif
/* Names for the libintl functions are a problem. They must not clash
@@ -389,6 +397,7 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
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;
@@ -412,23 +421,26 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
#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 (sizeof (*search) + msgid_len);
+ memcpy (search->msgid, msgid1, msgid_len);
+ search->domainname = (char *) domainname;
+ search->category = category;
+
+ foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
+ 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
@@ -563,39 +575,7 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
if (domain != NULL)
{
- unsigned long int index = 0;
-
- if (plural != 0)
- {
- const struct loaded_domain *domaindata =
- (const 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, msgid1, &retlen);
if (retval == NULL)
{
@@ -604,15 +584,20 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
{
retval = _nl_find_msg (domain->successor[cnt], msgid1,
- index);
+ &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
@@ -626,12 +611,14 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+ domainname_len + 1 - ZERO);
if (newp != NULL)
{
- newp->domain = mempcpy (newp->msgid, msgid1, msgid_len);
- memcpy (newp->domain, domainname, domainname_len + 1);
- newp->plindex = index;
+ newp->domainname =
+ mempcpy (newp->msgid, msgid1, msgid_len);
+ memcpy (newp->domainname, domainname, domainname_len + 1);
newp->category = category;
newp->counter = _nl_msg_cat_cntr;
+ newp->domain = domain;
newp->translation = retval;
+ newp->translation_length = retlen;
/* Insert the entry in the search tree. */
foundp = (struct known_translation_t **)
@@ -646,9 +633,15 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
{
/* We can update the existing entry. */
(*foundp)->counter = _nl_msg_cat_cntr;
+ (*foundp)->domain = domain;
(*foundp)->translation = retval;
+ (*foundp)->translation_length = retlen;
}
#endif
+ /* Now deal with plural. */
+ if (plural)
+ retval = plural_lookup (domain, n, retval, retlen);
+
__libc_rwlock_unlock (_nl_state_lock);
return retval;
}
@@ -660,14 +653,15 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
char *
internal_function
-_nl_find_msg (domain_file, msgid, index)
+_nl_find_msg (domain_file, msgid, lengthp)
struct loaded_l10nfile *domain_file;
const char *msgid;
- unsigned long int index;
+ size_t *lengthp;
{
const struct loaded_domain *domain;
size_t act;
char *result;
+ size_t resultlen;
if (domain_file->decided == 0)
_nl_load_domain (domain_file);
@@ -691,17 +685,21 @@ _nl_find_msg (domain_file, msgid, index)
/* 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)
{
+ /* Compare msgid with the original string at index nstr-1.
+ We compare the lengths with >=, not ==, because plural entries
+ are represented by strings with an embedded NUL. */
+ 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;
+ }
+
if (idx >= domain->hash_size - incr)
idx -= domain->hash_size - incr;
else
@@ -711,16 +709,6 @@ _nl_find_msg (domain_file, msgid, index)
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;
- }
}
/* NOTREACHED */
}
@@ -756,6 +744,7 @@ _nl_find_msg (domain_file, msgid, index)
string to use a different character set, this is the time. */
result = ((char *) domain->data
+ W (domain->must_swap, domain->trans_tab[act].offset));
+ resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
#if defined _LIBC || HAVE_ICONV
if (
@@ -772,9 +761,10 @@ _nl_find_msg (domain_file, msgid, index)
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,
@@ -787,8 +777,7 @@ _nl_find_msg (domain_file, msgid, index)
/* 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. */
@@ -796,46 +785,37 @@ _nl_find_msg (domain_file, msgid, index)
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);
+ 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)
@@ -850,16 +830,15 @@ _nl_find_msg (domain_file, msgid, index)
inbuf = 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;
+ outleft = freemem_size - sizeof (size_t);
if (iconv (domain->conv, &inptr, &inleft, &outptr, &outleft)
!= (size_t) (-1))
{
@@ -871,30 +850,34 @@ _nl_find_msg (domain_file, msgid, index)
__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))
{
@@ -912,27 +895,31 @@ _nl_find_msg (domain_file, msgid, index)
freemem = 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;
+ *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
domain->conv_tab[act] = 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:
@@ -940,26 +927,58 @@ _nl_find_msg (domain_file, msgid, index)
#endif /* _LIBC || HAVE_ICONV */
- /* Now skip some strings. How much depends on the index passed in. */
+ *lengthp = resultlen;
+ return result;
+}
+
+
+/* Look up a plural variant. */
+static char *
+internal_function
+plural_lookup (domain, n, translation, translation_len)
+ 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
- result = __rawmemchr (result, '\0');
+ p = __rawmemchr (p, '\0');
#else
- result = strchr (result, '\0');
+ p = strchr (p, '\0');
#endif
/* And skip over the NUL byte. */
- ++result;
- }
+ p++;
- return result;
+ 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;
}
/* Function to evaluate the plural expression and return an index value. */
static unsigned long int
internal_function
-plural_eval (struct expression *pexp, unsigned long int n)
+plural_eval (pexp, n)
+ struct expression *pexp;
+ unsigned long int n;
{
switch (pexp->operation)
{