root/trunk/intl/dcigettext.c

Revision 2, 34.1 kB (checked in by jordi, 2 years ago)

Added the initial source layout with autotools and gettext support. Still no code for the project.

Line 
1/* Implementation of the internal dcigettext function.
2   Copyright (C) 1995-1999, 2000-2005 Free Software Foundation, Inc.
3
4   This program is free software; you can redistribute it and/or modify it
5   under the terms of the GNU Library General Public License as published
6   by the Free Software Foundation; either version 2, or (at your option)
7   any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Library General Public License for more details.
13
14   You should have received a copy of the GNU Library General Public
15   License along with this program; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17   USA.  */
18
19/* Tell glibc's <string.h> to provide a prototype for mempcpy().
20   This must come before <config.h> because <config.h> may include
21   <features.h>, and once <features.h> has been included, it's too late.  */
22#ifndef _GNU_SOURCE
23# define _GNU_SOURCE    1
24#endif
25
26#ifdef HAVE_CONFIG_H
27# include <config.h>
28#endif
29
30#include <sys/types.h>
31
32#ifdef __GNUC__
33# define alloca __builtin_alloca
34# define HAVE_ALLOCA 1
35#else
36# ifdef _MSC_VER
37#  include <malloc.h>
38#  define alloca _alloca
39# else
40#  if defined HAVE_ALLOCA_H || defined _LIBC
41#   include <alloca.h>
42#  else
43#   ifdef _AIX
44 #pragma alloca
45#   else
46#    ifndef alloca
47char *alloca ();
48#    endif
49#   endif
50#  endif
51# endif
52#endif
53
54#include <errno.h>
55#ifndef errno
56extern int errno;
57#endif
58#ifndef __set_errno
59# define __set_errno(val) errno = (val)
60#endif
61
62#include <stddef.h>
63#include <stdlib.h>
64#include <string.h>
65
66#if defined HAVE_UNISTD_H || defined _LIBC
67# include <unistd.h>
68#endif
69
70#include <locale.h>
71
72#ifdef _LIBC
73  /* Guess whether integer division by zero raises signal SIGFPE.
74     Set to 1 only if you know for sure.  In case of doubt, set to 0.  */
75# if defined __alpha__ || defined __arm__ || defined __i386__ \
76     || defined __m68k__ || defined __s390__
77#  define INTDIV0_RAISES_SIGFPE 1
78# else
79#  define INTDIV0_RAISES_SIGFPE 0
80# endif
81#endif
82#if !INTDIV0_RAISES_SIGFPE
83# include <signal.h>
84#endif
85
86#if defined HAVE_SYS_PARAM_H || defined _LIBC
87# include <sys/param.h>
88#endif
89
90#include "gettextP.h"
91#include "plural-exp.h"
92#ifdef _LIBC
93# include <libintl.h>
94#else
95# include "libgnuintl.h"
96#endif
97#include "hash-string.h"
98
99/* Thread safetyness.  */
100#ifdef _LIBC
101# include <bits/libc-lock.h>
102#else
103/* Provide dummy implementation if this is outside glibc.  */
104# define __libc_lock_define_initialized(CLASS, NAME)
105# define __libc_lock_lock(NAME)
106# define __libc_lock_unlock(NAME)
107# define __libc_rwlock_define_initialized(CLASS, NAME)
108# define __libc_rwlock_rdlock(NAME)
109# define __libc_rwlock_unlock(NAME)
110#endif
111
112/* Alignment of types.  */
113#if defined __GNUC__ && __GNUC__ >= 2
114# define alignof(TYPE) __alignof__ (TYPE)
115#else
116# define alignof(TYPE) \
117    ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
118#endif
119
120/* The internal variables in the standalone libintl.a must have different
121   names than the internal variables in GNU libc, otherwise programs
122   using libintl.a cannot be linked statically.  */
123#if !defined _LIBC
124# define _nl_default_default_domain libintl_nl_default_default_domain
125# define _nl_current_default_domain libintl_nl_current_default_domain
126# define _nl_default_dirname libintl_nl_default_dirname
127# define _nl_domain_bindings libintl_nl_domain_bindings
128#endif
129
130/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
131#ifndef offsetof
132# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
133#endif
134
135/* @@ end of prolog @@ */
136
137#ifdef _LIBC
138/* Rename the non ANSI C functions.  This is required by the standard
139   because some ANSI C functions will require linking with this object
140   file and the name space must not be polluted.  */
141# define getcwd __getcwd
142# ifndef stpcpy
143#  define stpcpy __stpcpy
144# endif
145# define tfind __tfind
146#else
147# if !defined HAVE_GETCWD
148char *getwd ();
149#  define getcwd(buf, max) getwd (buf)
150# else
151#  if VMS
152#   define getcwd(buf, max) (getcwd) (buf, max, 0)
153#  else
154char *getcwd ();
155#  endif
156# endif
157# ifndef HAVE_STPCPY
158static char *stpcpy (char *dest, const char *src);
159# endif
160# ifndef HAVE_MEMPCPY
161static void *mempcpy (void *dest, const void *src, size_t n);
162# endif
163#endif
164
165/* Amount to increase buffer size by in each try.  */
166#define PATH_INCR 32
167
168/* The following is from pathmax.h.  */
169/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
170   PATH_MAX but might cause redefinition warnings when sys/param.h is
171   later included (as on MORE/BSD 4.3).  */
172#if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
173# include <limits.h>
174#endif
175
176#ifndef _POSIX_PATH_MAX
177# define _POSIX_PATH_MAX 255
178#endif
179
180#if !defined PATH_MAX && defined _PC_PATH_MAX
181# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
182#endif
183
184/* Don't include sys/param.h if it already has been.  */
185#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
186# include <sys/param.h>
187#endif
188
189#if !defined PATH_MAX && defined MAXPATHLEN
190# define PATH_MAX MAXPATHLEN
191#endif
192
193#ifndef PATH_MAX
194# define PATH_MAX _POSIX_PATH_MAX
195#endif
196
197/* Pathname support.
198   ISSLASH(C)           tests whether C is a directory separator character.
199   IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
200                        it may be concatenated to a directory pathname.
201   IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
202 */
203#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
204  /* Win32, Cygwin, OS/2, DOS */
205# define ISSLASH(C) ((C) == '/' || (C) == '\\')
206# define HAS_DEVICE(P) \
207    ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
208     && (P)[1] == ':')
209# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
210# define IS_PATH_WITH_DIR(P) \
211    (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
212#else
213  /* Unix */
214# define ISSLASH(C) ((C) == '/')
215# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
216# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
217#endif
218
219/* This is the type used for the search tree where known translations
220   are stored.  */
221struct known_translation_t
222{
223  /* Domain in which to search.  */
224  char *domainname;
225
226  /* The category.  */
227  int category;
228
229  /* State of the catalog counter at the point the string was found.  */
230  int counter;
231
232  /* Catalog where the string was found.  */
233  struct loaded_l10nfile *domain;
234
235  /* And finally the translation.  */
236  const char *translation;
237  size_t translation_length;
238
239  /* Pointer to the string in question.  */
240  char msgid[ZERO];
241};
242
243/* Root of the search tree with known translations.  We can use this
244   only if the system provides the `tsearch' function family.  */
245#if defined HAVE_TSEARCH || defined _LIBC
246# include <search.h>
247
248static void *root;
249
250# ifdef _LIBC
251#  define tsearch __tsearch
252# endif
253
254/* Function to compare two entries in the table of known translations.  */
255static int
256transcmp (const void *p1, const void *p2)
257{
258  const struct known_translation_t *s1;
259  const struct known_translation_t *s2;
260  int result;
261
262  s1 = (const struct known_translation_t *) p1;
263  s2 = (const struct known_translation_t *) p2;
264
265  result = strcmp (s1->msgid, s2->msgid);
266  if (result == 0)
267    {
268      result = strcmp (s1->domainname, s2->domainname);
269      if (result == 0)
270    /* We compare the category last (though this is the cheapest
271       operation) since it is hopefully always the same (namely
272       LC_MESSAGES).  */
273    result = s1->category - s2->category;
274    }
275
276  return result;
277}
278#endif
279
280#ifndef INTVARDEF
281# define INTVARDEF(name)
282#endif
283#ifndef INTUSE
284# define INTUSE(name) name
285#endif
286
287/* Name of the default domain used for gettext(3) prior any call to
288   textdomain(3).  The default value for this is "messages".  */
289const char _nl_default_default_domain[] attribute_hidden = "messages";
290
291/* Value used as the default domain for gettext(3).  */
292const char *_nl_current_default_domain attribute_hidden
293     = _nl_default_default_domain;
294
295/* Contains the default location of the message catalogs.  */
296#if defined __EMX__
297extern const char _nl_default_dirname[];
298#else
299const char _nl_default_dirname[] = LOCALEDIR;
300INTVARDEF (_nl_default_dirname)
301#endif
302
303/* List with bindings of specific domains created by bindtextdomain()
304   calls.  */
305struct binding *_nl_domain_bindings;
306
307/* Prototypes for local functions.  */
308static char *plural_lookup (struct loaded_l10nfile *domain,
309                unsigned long int n,
310                const char *translation, size_t translation_len)
311     internal_function;
312static const char *guess_category_value (int category,
313                     const char *categoryname)
314     internal_function;
315#ifdef _LIBC
316# include "../locale/localeinfo.h"
317# define category_to_name(category) _nl_category_names[category]
318#else
319static const char *category_to_name (int category) internal_function;
320#endif
321
322
323/* For those loosing systems which don't have `alloca' we have to add
324   some additional code emulating it.  */
325#ifdef HAVE_ALLOCA
326/* Nothing has to be done.  */
327# define freea(p) /* nothing */
328# define ADD_BLOCK(list, address) /* nothing */
329# define FREE_BLOCKS(list) /* nothing */
330#else
331struct block_list
332{
333  void *address;
334  struct block_list *next;
335};
336# define ADD_BLOCK(list, addr)                            \
337  do {                                        \
338    struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
339    /* If we cannot get a free block we cannot add the new element to         \
340       the list.  */                                  \
341    if (newp != NULL) {                               \
342      newp->address = (addr);                             \
343      newp->next = (list);                            \
344      (list) = newp;                                  \
345    }                                         \
346  } while (0)
347# define FREE_BLOCKS(list)                            \
348  do {                                        \
349    while (list != NULL) {                            \
350      struct block_list *old = list;                          \
351      list = list->next;                              \
352      free (old->address);                            \
353      free (old);                                 \
354    }                                         \
355  } while (0)
356# undef alloca
357# define alloca(size) (malloc (size))
358# define freea(p) free (p)
359#endif  /* have alloca */
360
361
362#ifdef _LIBC
363/* List of blocks allocated for translations.  */
364typedef struct transmem_list
365{
366  struct transmem_list *next;
367  char data[ZERO];
368} transmem_block_t;
369static struct transmem_list *transmem_list;
370#else
371typedef unsigned char transmem_block_t;
372#endif
373
374
375/* Names for the libintl functions are a problem.  They must not clash
376   with existing names and they should follow ANSI C.  But this source
377   code is also used in GNU C Library where the names have a __
378   prefix.  So we have to make a difference here.  */
379#ifdef _LIBC
380# define DCIGETTEXT __dcigettext
381#else
382# define DCIGETTEXT libintl_dcigettext
383#endif
384
385/* Lock variable to protect the global data in the gettext implementation.  */
386#ifdef _LIBC
387__libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
388#endif
389
390/* Checking whether the binaries runs SUID must be done and glibc provides
391   easier methods therefore we make a difference here.  */
392#ifdef _LIBC
393# define ENABLE_SECURE __libc_enable_secure
394# define DETERMINE_SECURE
395#else
396# ifndef HAVE_GETUID
397#  define getuid() 0
398# endif
399# ifndef HAVE_GETGID
400#  define getgid() 0
401# endif
402# ifndef HAVE_GETEUID
403#  define geteuid() getuid()
404# endif
405# ifndef HAVE_GETEGID
406#  define getegid() getgid()
407# endif
408static int enable_secure;
409# define ENABLE_SECURE (enable_secure == 1)
410# define DETERMINE_SECURE \
411  if (enable_secure == 0)                             \
412    {                                         \
413      if (getuid () != geteuid () || getgid () != getegid ())             \
414    enable_secure = 1;                            \
415      else                                    \
416    enable_secure = -1;                           \
417    }
418#endif
419
420/* Get the function to evaluate the plural expression.  */
421#include "eval-plural.h"
422
423/* Look up MSGID in the DOMAINNAME message catalog for the current
424   CATEGORY locale and, if PLURAL is nonzero, search over string
425   depending on the plural form determined by N.  */
426char *
427DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
428        int plural, unsigned long int n, int category)
429{
430#ifndef HAVE_ALLOCA
431  struct block_list *block_list = NULL;
432#endif
433  struct loaded_l10nfile *domain;
434  struct binding *binding;
435  const char *categoryname;
436  const char *categoryvalue;
437  char *dirname, *xdomainname;
438  char *single_locale;
439  char *retval;
440  size_t retlen;
441  int saved_errno;
442#if defined HAVE_TSEARCH || defined _LIBC
443  struct known_translation_t *search;
444  struct known_translation_t **foundp = NULL;
445  size_t msgid_len;
446#endif
447  size_t domainname_len;
448
449  /* If no real MSGID is given return NULL.  */
450  if (msgid1 == NULL)
451    return NULL;
452
453#ifdef _LIBC
454  if (category < 0 || category >= __LC_LAST || category == LC_ALL)
455    /* Bogus.  */
456    return (plural == 0
457        ? (char *) msgid1
458        /* Use the Germanic plural rule.  */
459        : n == 1 ? (char *) msgid1 : (char *) msgid2);
460#endif
461
462  __libc_rwlock_rdlock (_nl_state_lock);
463
464  /* If DOMAINNAME is NULL, we are interested in the default domain.  If
465     CATEGORY is not LC_MESSAGES this might not make much sense but the
466     definition left this undefined.  */
467  if (domainname == NULL)
468    domainname = _nl_current_default_domain;
469
470  /* OS/2 specific: backward compatibility with older libintl versions  */
471#ifdef LC_MESSAGES_COMPAT
472  if (category == LC_MESSAGES_COMPAT)
473    category = LC_MESSAGES;
474#endif
475
476#if defined HAVE_TSEARCH || defined _LIBC
477  msgid_len = strlen (msgid1) + 1;
478
479  /* Try to find the translation among those which we found at
480     some time.  */
481  search = (struct known_translation_t *)
482       alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
483  memcpy (search->msgid, msgid1, msgid_len);
484  search->domainname = (char *) domainname;
485  search->category = category;
486
487  foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
488  freea (search);
489  if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
490    {
491      /* Now deal with plural.  */
492      if (plural)
493    retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
494                (*foundp)->translation_length);
495      else
496    retval = (char *) (*foundp)->translation;
497
498      __libc_rwlock_unlock (_nl_state_lock);
499      return retval;
500    }
501#endif
502
503  /* Preserve the `errno' value.  */
504  saved_errno = errno;
505
506  /* See whether this is a SUID binary or not.  */
507  DETERMINE_SECURE;
508
509  /* First find matching binding.  */
510  for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
511    {
512      int compare = strcmp (domainname, binding->domainname);
513      if (compare == 0)
514    /* We found it!  */
515    break;
516      if (compare < 0)
517    {
518      /* It is not in the list.  */
519      binding = NULL;
520      break;
521    }
522    }
523
524  if (binding == NULL)
525    dirname = (char *) INTUSE(_nl_default_dirname);
526  else if (IS_ABSOLUTE_PATH (binding->dirname))
527    dirname = binding->dirname;
528  else
529    {
530      /* We have a relative path.  Make it absolute now.  */
531      size_t dirname_len = strlen (binding->dirname) + 1;
532      size_t path_max;
533      char *ret;
534
535      path_max = (unsigned int) PATH_MAX;
536      path_max += 2;        /* The getcwd docs say to do this.  */
537
538      for (;;)
539    {
540      dirname = (char *) alloca (path_max + dirname_len);
541      ADD_BLOCK (block_list, dirname);
542
543      __set_errno (0);
544      ret = getcwd (dirname, path_max);
545      if (ret != NULL || errno != ERANGE)
546        break;
547
548      path_max += path_max / 2;
549      path_max += PATH_INCR;
550    }
551
552      if (ret == NULL)
553    /* We cannot get the current working directory.  Don't signal an
554       error but simply return the default string.  */
555    goto return_untranslated;
556
557      stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
558    }
559
560  /* Now determine the symbolic name of CATEGORY and its value.  */
561  categoryname = category_to_name (category);
562  categoryvalue = guess_category_value (category, categoryname);
563
564  domainname_len = strlen (domainname);
565  xdomainname = (char *) alloca (strlen (categoryname)
566                 + domainname_len + 5);
567  ADD_BLOCK (block_list, xdomainname);
568
569  stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
570          domainname, domainname_len),
571      ".mo");
572
573  /* Creating working area.  */
574  single_locale = (char *) alloca (strlen (categoryvalue) + 1);
575  ADD_BLOCK (block_list, single_locale);
576
577
578  /* Search for the given string.  This is a loop because we perhaps
579     got an ordered list of languages to consider for the translation.  */
580  while (1)
581    {
582      /* Make CATEGORYVALUE point to the next element of the list.  */
583      while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
584    ++categoryvalue;
585      if (categoryvalue[0] == '\0')
586    {
587      /* The whole contents of CATEGORYVALUE has been searched but
588         no valid entry has been found.  We solve this situation
589         by implicitly appending a "C" entry, i.e. no translation
590         will take place.  */
591      single_locale[0] = 'C';
592      single_locale[1] = '\0';
593    }
594      else
595    {
596      char *cp = single_locale;
597      while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
598        *cp++ = *categoryvalue++;
599      *cp = '\0';
600
601      /* When this is a SUID binary we must not allow accessing files
602         outside the dedicated directories.  */
603      if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
604        /* Ingore this entry.  */
605        continue;
606    }
607
608      /* If the current locale value is C (or POSIX) we don't load a
609     domain.  Return the MSGID.  */
610      if (strcmp (single_locale, "C") == 0
611      || strcmp (single_locale, "POSIX") == 0)
612    break;
613
614      /* Find structure describing the message catalog matching the
615     DOMAINNAME and CATEGORY.  */
616      domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
617
618      if (domain != NULL)
619    {
620      retval = _nl_find_msg (domain, binding, msgid1, &retlen);
621
622      if (retval == NULL)
623        {
624          int cnt;
625
626          for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
627        {
628          retval = _nl_find_msg (domain->successor[cnt], binding,
629                     msgid1, &retlen);
630
631          if (retval != NULL)
632            {
633              domain = domain->successor[cnt];
634              break;
635            }
636        }
637        }
638
639      if (retval != NULL)
640        {
641          /* Found the translation of MSGID1 in domain DOMAIN:
642         starting at RETVAL, RETLEN bytes.  */
643          FREE_BLOCKS (block_list);
644#if defined HAVE_TSEARCH || defined _LIBC
645          if (foundp == NULL)
646        {
647          /* Create a new entry and add it to the search tree.  */
648          struct known_translation_t *newp;
649
650          newp = (struct known_translation_t *)
651            malloc (offsetof (struct known_translation_t, msgid)
652                + msgid_len + domainname_len + 1);
653          if (newp != NULL)
654            {
655              newp->domainname =
656            mempcpy (newp->msgid, msgid1, msgid_len);
657              memcpy (newp->domainname, domainname, domainname_len + 1);
658              newp->category = category;
659              newp->counter = _nl_msg_cat_cntr;
660              newp->domain = domain;
661              newp->translation = retval;
662              newp->translation_length = retlen;
663
664              /* Insert the entry in the search tree.  */
665              foundp = (struct known_translation_t **)
666            tsearch (newp, &root, transcmp);
667              if (foundp == NULL
668              || __builtin_expect (*foundp != newp, 0))
669            /* The insert failed.  */
670            free (newp);
671            }
672        }
673          else
674        {
675          /* We can update the existing entry.  */
676          (*foundp)->counter = _nl_msg_cat_cntr;
677          (*foundp)->domain = domain;
678          (*foundp)->translation = retval;
679          (*foundp)->translation_length = retlen;
680        }
681#endif
682          __set_errno (saved_errno);
683
684          /* Now deal with plural.  */
685          if (plural)
686        retval = plural_lookup (domain, n, retval, retlen);
687
688          __libc_rwlock_unlock (_nl_state_lock);
689          return retval;
690        }
691    }
692    }
693
694 return_untranslated:
695  /* Return the untranslated MSGID.  */
696  FREE_BLOCKS (block_list);
697  __libc_rwlock_unlock (_nl_state_lock);
698#ifndef _LIBC
699  if (!ENABLE_SECURE)
700    {
701      extern void _nl_log_untranslated (const char *logfilename,
702                    const char *domainname,
703                    const char *msgid1, const char *msgid2,
704                    int plural);
705      const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
706
707      if (logfilename != NULL && logfilename[0] != '\0')
708    _nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
709    }
710#endif
711  __set_errno (saved_errno);
712  return (plural == 0
713      ? (char *) msgid1
714      /* Use the Germanic plural rule.  */
715      : n == 1 ? (char *) msgid1 : (char *) msgid2);
716}
717
718
719char *
720internal_function
721_nl_find_msg (struct loaded_l10nfile *domain_file,
722          struct binding *domainbinding, const char *msgid,
723          size_t *lengthp)
724{
725  struct loaded_domain *domain;
726  nls_uint32 nstrings;
727  size_t act;
728  char *result;
729  size_t resultlen;
730
731  if (domain_file->decided == 0)
732    _nl_load_domain (domain_file, domainbinding);
733
734  if (domain_file->data == NULL)
735    return NULL;
736
737  domain = (struct loaded_domain *) domain_file->data;
738
739  nstrings = domain->nstrings;
740
741  /* Locate the MSGID and its translation.  */
742  if (domain->hash_tab != NULL)
743    {
744      /* Use the hashing table.  */
745      nls_uint32 len = strlen (msgid);
746      nls_uint32 hash_val = hash_string (msgid);
747      nls_uint32 idx = hash_val % domain->hash_size;
748      nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
749
750      while (1)
751    {
752      nls_uint32 nstr =
753        W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
754
755      if (nstr == 0)
756        /* Hash table entry is empty.  */
757        return NULL;
758
759      nstr--;
760
761      /* Compare msgid with the original string at index nstr.
762         We compare the lengths with >=, not ==, because plural entries
763         are represented by strings with an embedded NUL.  */
764      if (nstr < nstrings
765          ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
766        && (strcmp (msgid,
767                domain->data + W (domain->must_swap,
768                          domain->orig_tab[nstr].offset))
769            == 0)
770          : domain->orig_sysdep_tab[nstr - nstrings].length > len
771        && (strcmp (msgid,
772                domain->orig_sysdep_tab[nstr - nstrings].pointer)
773            == 0))
774        {
775          act = nstr;
776          goto found;
777        }
778
779      if (idx >= domain->hash_size - incr)
780        idx -= domain->hash_size - incr;
781      else
782        idx += incr;
783    }
784      /* NOTREACHED */
785    }
786  else
787    {
788      /* Try the default method:  binary search in the sorted array of
789     messages.  */
790      size_t top, bottom;
791
792      bottom = 0;
793      top = nstrings;
794      while (bottom < top)
795    {
796      int cmp_val;
797
798      act = (bottom + top) / 2;
799      cmp_val = strcmp (msgid, (domain->data
800                    + W (domain->must_swap,
801                     domain->orig_tab[act].offset)));
802      if (cmp_val < 0)
803        top = act;
804      else if (cmp_val > 0)
805        bottom = act + 1;
806      else
807        goto found;
808    }
809      /* No translation was found.  */
810      return NULL;
811    }
812
813 found:
814  /* The translation was found at index ACT.  If we have to convert the
815     string to use a different character set, this is the time.  */
816  if (act < nstrings)
817    {
818      result = (char *)
819    (domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
820      resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
821    }
822  else
823    {
824      result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
825      resultlen = domain->trans_sysdep_tab[act - nstrings].length;
826    }
827
828#if defined _LIBC || HAVE_ICONV
829  if (domain->codeset_cntr
830      != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
831    {
832      /* The domain's codeset has changed through bind_textdomain_codeset()
833     since the message catalog was initialized or last accessed.  We
834     have to reinitialize the converter.  */
835      _nl_free_domain_conv (domain);
836      _nl_init_domain_conv (domain_file, domain, domainbinding);
837    }
838
839  if (
840# ifdef _LIBC
841      domain->conv != (__gconv_t) -1
842# else
843#  if HAVE_ICONV
844      domain->conv != (iconv_t) -1
845#  endif
846# endif
847      )
848    {
849      /* We are supposed to do a conversion.  First allocate an
850     appropriate table with the same structure as the table
851     of translations in the file, where we can put the pointers
852     to the converted strings in.
853     There is a slight complication with plural entries.  They
854     are represented by consecutive NUL terminated strings.  We
855     handle this case by converting RESULTLEN bytes, including
856     NULs.  */
857
858      if (domain->conv_tab == NULL
859      && ((domain->conv_tab =
860         (char **) calloc (nstrings + domain->n_sysdep_strings,
861                   sizeof (char *)))
862          == NULL))
863    /* Mark that we didn't succeed allocating a table.  */
864    domain->conv_tab = (char **) -1;
865
866      if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
867    /* Nothing we can do, no more memory.  */
868    goto converted;
869
870      if (domain->conv_tab[act] == NULL)
871    {
872      /* We haven't used this string so far, so it is not
873         translated yet.  Do this now.  */
874      /* We use a bit more efficient memory handling.
875         We allocate always larger blocks which get used over
876         time.  This is faster than many small allocations.   */
877      __libc_lock_define_initialized (static, lock)
878# define INITIAL_BLOCK_SIZE 4080
879      static unsigned char *freemem;
880      static size_t freemem_size;
881
882      const unsigned char *inbuf;
883      unsigned char *outbuf;
884      int malloc_count;
885# ifndef _LIBC
886      transmem_block_t *transmem_list = NULL;
887# endif
888
889      __libc_lock_lock (lock);
890
891      inbuf = (const unsigned char *) result;
892      outbuf = freemem + sizeof (size_t);
893
894      malloc_count = 0;
895      while (1)
896        {
897          transmem_block_t *newmem;
898# ifdef _LIBC
899          size_t non_reversible;
900          int res;
901
902          if (freemem_size < sizeof (size_t))
903        goto resize_freemem;
904
905          res = __gconv (domain->conv,
906                 &inbuf, inbuf + resultlen,
907                 &outbuf,
908                 outbuf + freemem_size - sizeof (size_t),
909                 &non_reversible);
910
911          if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
912        break;
913
914          if (res != __GCONV_FULL_OUTPUT)
915        {
916          __libc_lock_unlock (lock);
917          goto converted;
918        }
919
920          inbuf = result;
921# else
922#  if HAVE_ICONV
923          const char *inptr = (const char *) inbuf;
924          size_t inleft = resultlen;
925          char *outptr = (char *) outbuf;
926          size_t outleft;
927
928          if (freemem_size < sizeof (size_t))
929        goto resize_freemem;
930
931          outleft = freemem_size - sizeof (size_t);
932          if (iconv (domain->conv,
933             (ICONV_CONST char **) &inptr, &inleft,
934             &outptr, &outleft)
935          != (size_t) (-1))
936        {
937          outbuf = (unsigned char *) outptr;
938          break;
939        }
940          if (errno != E2BIG)
941        {
942          __libc_lock_unlock (lock);
943          goto converted;
944        }
945#  endif
946# endif
947
948        resize_freemem:
949          /* We must allocate a new buffer or resize the old one.  */
950          if (malloc_count > 0)
951        {
952          ++malloc_count;
953          freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
954          newmem = (transmem_block_t *) realloc (transmem_list,
955                             freemem_size);
956# ifdef _LIBC
957          if (newmem != NULL)
958          Â