Home | History | Annotate | Line # | Download | only in intl
      1  1.1  christos /* Implementation of the internal dcigettext function.
      2  1.1  christos    Copyright (C) 1995-1999, 2000-2006 Free Software Foundation, Inc.
      3  1.1  christos 
      4  1.1  christos    This program is free software; you can redistribute it and/or modify it
      5  1.1  christos    under the terms of the GNU Library General Public License as published
      6  1.1  christos    by the Free Software Foundation; either version 2, or (at your option)
      7  1.1  christos    any later version.
      8  1.1  christos 
      9  1.1  christos    This program is distributed in the hope that it will be useful,
     10  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  1.1  christos    Library General Public License for more details.
     13  1.1  christos 
     14  1.1  christos    You should have received a copy of the GNU Library General Public
     15  1.1  christos    License along with this program; if not, write to the Free Software
     16  1.1  christos    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
     17  1.1  christos    USA.  */
     18  1.1  christos 
     19  1.1  christos /* Tell glibc's <string.h> to provide a prototype for mempcpy().
     20  1.1  christos    This must come before <config.h> because <config.h> may include
     21  1.1  christos    <features.h>, and once <features.h> has been included, it's too late.  */
     22  1.1  christos #ifndef _GNU_SOURCE
     23  1.1  christos # define _GNU_SOURCE	1
     24  1.1  christos #endif
     25  1.1  christos 
     26  1.1  christos #ifdef HAVE_CONFIG_H
     27  1.1  christos # include <config.h>
     28  1.1  christos #endif
     29  1.1  christos 
     30  1.1  christos /* NL_LOCALE_NAME does not work in glibc-2.4.  Ignore it.  */
     31  1.1  christos #undef HAVE_NL_LOCALE_NAME
     32  1.1  christos 
     33  1.1  christos #include <sys/types.h>
     34  1.1  christos 
     35  1.1  christos #ifdef __GNUC__
     36  1.1  christos # define alloca __builtin_alloca
     37  1.1  christos # define HAVE_ALLOCA 1
     38  1.1  christos #else
     39  1.1  christos # ifdef _MSC_VER
     40  1.1  christos #  include <malloc.h>
     41  1.1  christos #  define alloca _alloca
     42  1.1  christos # else
     43  1.1  christos #  if defined HAVE_ALLOCA_H || defined _LIBC
     44  1.1  christos #   include <alloca.h>
     45  1.1  christos #  else
     46  1.1  christos #   ifdef _AIX
     47  1.1  christos  #pragma alloca
     48  1.1  christos #   else
     49  1.1  christos #    ifndef alloca
     50  1.1  christos char *alloca ();
     51  1.1  christos #    endif
     52  1.1  christos #   endif
     53  1.1  christos #  endif
     54  1.1  christos # endif
     55  1.1  christos #endif
     56  1.1  christos 
     57  1.1  christos #include <errno.h>
     58  1.1  christos #ifndef errno
     59  1.1  christos extern int errno;
     60  1.1  christos #endif
     61  1.1  christos #ifndef __set_errno
     62  1.1  christos # define __set_errno(val) errno = (val)
     63  1.1  christos #endif
     64  1.1  christos 
     65  1.1  christos #include <stddef.h>
     66  1.1  christos #include <stdlib.h>
     67  1.1  christos #include <string.h>
     68  1.1  christos 
     69  1.1  christos #if defined HAVE_UNISTD_H || defined _LIBC
     70  1.1  christos # include <unistd.h>
     71  1.1  christos #endif
     72  1.1  christos 
     73  1.1  christos #include <locale.h>
     74  1.1  christos 
     75  1.1  christos #ifdef _LIBC
     76  1.1  christos   /* Guess whether integer division by zero raises signal SIGFPE.
     77  1.1  christos      Set to 1 only if you know for sure.  In case of doubt, set to 0.  */
     78  1.1  christos # if defined __alpha__ || defined __arm__ || defined __i386__ \
     79  1.1  christos      || defined __m68k__ || defined __s390__
     80  1.1  christos #  define INTDIV0_RAISES_SIGFPE 1
     81  1.1  christos # else
     82  1.1  christos #  define INTDIV0_RAISES_SIGFPE 0
     83  1.1  christos # endif
     84  1.1  christos #endif
     85  1.1  christos #if !INTDIV0_RAISES_SIGFPE
     86  1.1  christos # include <signal.h>
     87  1.1  christos #endif
     88  1.1  christos 
     89  1.1  christos #if defined HAVE_SYS_PARAM_H || defined _LIBC
     90  1.1  christos # include <sys/param.h>
     91  1.1  christos #endif
     92  1.1  christos 
     93  1.1  christos #if !defined _LIBC && HAVE_NL_LOCALE_NAME
     94  1.1  christos # include <langinfo.h>
     95  1.1  christos #endif
     96  1.1  christos 
     97  1.1  christos #include "gettextP.h"
     98  1.1  christos #include "plural-exp.h"
     99  1.1  christos #ifdef _LIBC
    100  1.1  christos # include <libintl.h>
    101  1.1  christos #else
    102  1.1  christos # ifdef IN_LIBGLOCALE
    103  1.1  christos #  include <libintl.h>
    104  1.1  christos # endif
    105  1.1  christos # include "libgnuintl.h"
    106  1.1  christos #endif
    107  1.1  christos #include "hash-string.h"
    108  1.1  christos 
    109  1.1  christos /* Handle multi-threaded applications.  */
    110  1.1  christos #ifdef _LIBC
    111  1.1  christos # include <bits/libc-lock.h>
    112  1.1  christos # define gl_rwlock_define_initialized __libc_rwlock_define_initialized
    113  1.1  christos # define gl_rwlock_rdlock __libc_rwlock_rdlock
    114  1.1  christos # define gl_rwlock_wrlock __libc_rwlock_wrlock
    115  1.1  christos # define gl_rwlock_unlock __libc_rwlock_unlock
    116  1.1  christos #else
    117  1.1  christos # include "lock.h"
    118  1.1  christos #endif
    119  1.1  christos 
    120  1.1  christos /* Alignment of types.  */
    121  1.1  christos #if defined __GNUC__ && __GNUC__ >= 2
    122  1.1  christos # define alignof(TYPE) __alignof__ (TYPE)
    123  1.1  christos #else
    124  1.1  christos # define alignof(TYPE) \
    125  1.1  christos     ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
    126  1.1  christos #endif
    127  1.1  christos 
    128  1.1  christos /* The internal variables in the standalone libintl.a must have different
    129  1.1  christos    names than the internal variables in GNU libc, otherwise programs
    130  1.1  christos    using libintl.a cannot be linked statically.  */
    131  1.1  christos #if !defined _LIBC
    132  1.1  christos # define _nl_default_default_domain libintl_nl_default_default_domain
    133  1.1  christos # define _nl_current_default_domain libintl_nl_current_default_domain
    134  1.1  christos # define _nl_default_dirname libintl_nl_default_dirname
    135  1.1  christos # define _nl_domain_bindings libintl_nl_domain_bindings
    136  1.1  christos #endif
    137  1.1  christos 
    138  1.1  christos /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
    139  1.1  christos #ifndef offsetof
    140  1.1  christos # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
    141  1.1  christos #endif
    142  1.1  christos 
    143  1.1  christos /* @@ end of prolog @@ */
    144  1.1  christos 
    145  1.1  christos #ifdef _LIBC
    146  1.1  christos /* Rename the non ANSI C functions.  This is required by the standard
    147  1.1  christos    because some ANSI C functions will require linking with this object
    148  1.1  christos    file and the name space must not be polluted.  */
    149  1.1  christos # define getcwd __getcwd
    150  1.1  christos # ifndef stpcpy
    151  1.1  christos #  define stpcpy __stpcpy
    152  1.1  christos # endif
    153  1.1  christos # define tfind __tfind
    154  1.1  christos #else
    155  1.1  christos # if !defined HAVE_GETCWD
    156  1.1  christos char *getwd ();
    157  1.1  christos #  define getcwd(buf, max) getwd (buf)
    158  1.1  christos # else
    159  1.1  christos #  if VMS
    160  1.1  christos #   define getcwd(buf, max) (getcwd) (buf, max, 0)
    161  1.1  christos #  else
    162  1.1  christos char *getcwd ();
    163  1.1  christos #  endif
    164  1.1  christos # endif
    165  1.1  christos # ifndef HAVE_STPCPY
    166  1.1  christos static char *stpcpy (char *dest, const char *src);
    167  1.1  christos # endif
    168  1.1  christos # ifndef HAVE_MEMPCPY
    169  1.1  christos static void *mempcpy (void *dest, const void *src, size_t n);
    170  1.1  christos # endif
    171  1.1  christos #endif
    172  1.1  christos 
    173  1.1  christos /* Amount to increase buffer size by in each try.  */
    174  1.1  christos #define PATH_INCR 32
    175  1.1  christos 
    176  1.1  christos /* The following is from pathmax.h.  */
    177  1.1  christos /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
    178  1.1  christos    PATH_MAX but might cause redefinition warnings when sys/param.h is
    179  1.1  christos    later included (as on MORE/BSD 4.3).  */
    180  1.1  christos #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
    181  1.1  christos # include <limits.h>
    182  1.1  christos #endif
    183  1.1  christos 
    184  1.1  christos #ifndef _POSIX_PATH_MAX
    185  1.1  christos # define _POSIX_PATH_MAX 255
    186  1.1  christos #endif
    187  1.1  christos 
    188  1.1  christos #if !defined PATH_MAX && defined _PC_PATH_MAX
    189  1.1  christos # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
    190  1.1  christos #endif
    191  1.1  christos 
    192  1.1  christos /* Don't include sys/param.h if it already has been.  */
    193  1.1  christos #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
    194  1.1  christos # include <sys/param.h>
    195  1.1  christos #endif
    196  1.1  christos 
    197  1.1  christos #if !defined PATH_MAX && defined MAXPATHLEN
    198  1.1  christos # define PATH_MAX MAXPATHLEN
    199  1.1  christos #endif
    200  1.1  christos 
    201  1.1  christos #ifndef PATH_MAX
    202  1.1  christos # define PATH_MAX _POSIX_PATH_MAX
    203  1.1  christos #endif
    204  1.1  christos 
    205  1.1  christos /* Pathname support.
    206  1.1  christos    ISSLASH(C)           tests whether C is a directory separator character.
    207  1.1  christos    IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
    208  1.1  christos                         it may be concatenated to a directory pathname.
    209  1.1  christos    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
    210  1.1  christos  */
    211  1.1  christos #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
    212  1.1  christos   /* Win32, Cygwin, OS/2, DOS */
    213  1.1  christos # define ISSLASH(C) ((C) == '/' || (C) == '\\')
    214  1.1  christos # define HAS_DEVICE(P) \
    215  1.1  christos     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
    216  1.1  christos      && (P)[1] == ':')
    217  1.1  christos # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
    218  1.1  christos # define IS_PATH_WITH_DIR(P) \
    219  1.1  christos     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
    220  1.1  christos #else
    221  1.1  christos   /* Unix */
    222  1.1  christos # define ISSLASH(C) ((C) == '/')
    223  1.1  christos # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
    224  1.1  christos # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
    225  1.1  christos #endif
    226  1.1  christos 
    227  1.1  christos /* Whether to support different locales in different threads.  */
    228  1.1  christos #if defined _LIBC || HAVE_NL_LOCALE_NAME || (HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS) || defined IN_LIBGLOCALE
    229  1.1  christos # define HAVE_PER_THREAD_LOCALE
    230  1.1  christos #endif
    231  1.1  christos 
    232  1.1  christos /* This is the type used for the search tree where known translations
    233  1.1  christos    are stored.  */
    234  1.1  christos struct known_translation_t
    235  1.1  christos {
    236  1.1  christos   /* Domain in which to search.  */
    237  1.1  christos   const char *domainname;
    238  1.1  christos 
    239  1.1  christos   /* The category.  */
    240  1.1  christos   int category;
    241  1.1  christos 
    242  1.1  christos #ifdef HAVE_PER_THREAD_LOCALE
    243  1.1  christos   /* Name of the relevant locale category, or "" for the global locale.  */
    244  1.1  christos   const char *localename;
    245  1.1  christos #endif
    246  1.1  christos 
    247  1.1  christos #ifdef IN_LIBGLOCALE
    248  1.1  christos   /* The character encoding.  */
    249  1.1  christos   const char *encoding;
    250  1.1  christos #endif
    251  1.1  christos 
    252  1.1  christos   /* State of the catalog counter at the point the string was found.  */
    253  1.1  christos   int counter;
    254  1.1  christos 
    255  1.1  christos   /* Catalog where the string was found.  */
    256  1.1  christos   struct loaded_l10nfile *domain;
    257  1.1  christos 
    258  1.1  christos   /* And finally the translation.  */
    259  1.1  christos   const char *translation;
    260  1.1  christos   size_t translation_length;
    261  1.1  christos 
    262  1.1  christos   /* Pointer to the string in question.  */
    263  1.1  christos   char msgid[ZERO];
    264  1.1  christos };
    265  1.1  christos 
    266  1.1  christos /* Root of the search tree with known translations.  We can use this
    267  1.1  christos    only if the system provides the `tsearch' function family.  */
    268  1.1  christos #if defined HAVE_TSEARCH || defined _LIBC
    269  1.1  christos # include <search.h>
    270  1.1  christos 
    271  1.1  christos gl_rwlock_define_initialized (static, tree_lock)
    272  1.1  christos 
    273  1.1  christos static void *root;
    274  1.1  christos 
    275  1.1  christos # ifdef _LIBC
    276  1.1  christos #  define tsearch __tsearch
    277  1.1  christos # endif
    278  1.1  christos 
    279  1.1  christos /* Function to compare two entries in the table of known translations.  */
    280  1.1  christos static int
    281  1.1  christos transcmp (const void *p1, const void *p2)
    282  1.1  christos {
    283  1.1  christos   const struct known_translation_t *s1;
    284  1.1  christos   const struct known_translation_t *s2;
    285  1.1  christos   int result;
    286  1.1  christos 
    287  1.1  christos   s1 = (const struct known_translation_t *) p1;
    288  1.1  christos   s2 = (const struct known_translation_t *) p2;
    289  1.1  christos 
    290  1.1  christos   result = strcmp (s1->msgid, s2->msgid);
    291  1.1  christos   if (result == 0)
    292  1.1  christos     {
    293  1.1  christos       result = strcmp (s1->domainname, s2->domainname);
    294  1.1  christos       if (result == 0)
    295  1.1  christos 	{
    296  1.1  christos #ifdef HAVE_PER_THREAD_LOCALE
    297  1.1  christos 	  result = strcmp (s1->localename, s2->localename);
    298  1.1  christos 	  if (result == 0)
    299  1.1  christos #endif
    300  1.1  christos 	    {
    301  1.1  christos #ifdef IN_LIBGLOCALE
    302  1.1  christos 	      result = strcmp (s1->encoding, s2->encoding);
    303  1.1  christos 	      if (result == 0)
    304  1.1  christos #endif
    305  1.1  christos 		/* We compare the category last (though this is the cheapest
    306  1.1  christos 		   operation) since it is hopefully always the same (namely
    307  1.1  christos 		   LC_MESSAGES).  */
    308  1.1  christos 		result = s1->category - s2->category;
    309  1.1  christos 	    }
    310  1.1  christos 	}
    311  1.1  christos     }
    312  1.1  christos 
    313  1.1  christos   return result;
    314  1.1  christos }
    315  1.1  christos #endif
    316  1.1  christos 
    317  1.1  christos /* Name of the default domain used for gettext(3) prior any call to
    318  1.1  christos    textdomain(3).  The default value for this is "messages".  */
    319  1.1  christos const char _nl_default_default_domain[] attribute_hidden = "messages";
    320  1.1  christos 
    321  1.1  christos #ifndef IN_LIBGLOCALE
    322  1.1  christos /* Value used as the default domain for gettext(3).  */
    323  1.1  christos const char *_nl_current_default_domain attribute_hidden
    324  1.1  christos      = _nl_default_default_domain;
    325  1.1  christos #endif
    326  1.1  christos 
    327  1.1  christos /* Contains the default location of the message catalogs.  */
    328  1.1  christos #if defined __EMX__
    329  1.1  christos extern const char _nl_default_dirname[];
    330  1.1  christos #else
    331  1.1  christos # ifdef _LIBC
    332  1.1  christos extern const char _nl_default_dirname[];
    333  1.1  christos libc_hidden_proto (_nl_default_dirname)
    334  1.1  christos # endif
    335  1.1  christos const char _nl_default_dirname[] = LOCALEDIR;
    336  1.1  christos # ifdef _LIBC
    337  1.1  christos libc_hidden_data_def (_nl_default_dirname)
    338  1.1  christos # endif
    339  1.1  christos #endif
    340  1.1  christos 
    341  1.1  christos #ifndef IN_LIBGLOCALE
    342  1.1  christos /* List with bindings of specific domains created by bindtextdomain()
    343  1.1  christos    calls.  */
    344  1.1  christos struct binding *_nl_domain_bindings;
    345  1.1  christos #endif
    346  1.1  christos 
    347  1.1  christos /* Prototypes for local functions.  */
    348  1.1  christos static char *plural_lookup (struct loaded_l10nfile *domain,
    349  1.1  christos 			    unsigned long int n,
    350  1.1  christos 			    const char *translation, size_t translation_len)
    351  1.1  christos      internal_function;
    352  1.1  christos 
    353  1.1  christos #ifdef IN_LIBGLOCALE
    354  1.1  christos static const char *guess_category_value (int category,
    355  1.1  christos 					 const char *categoryname,
    356  1.1  christos 					 const char *localename)
    357  1.1  christos      internal_function;
    358  1.1  christos #else
    359  1.1  christos static const char *guess_category_value (int category,
    360  1.1  christos 					 const char *categoryname)
    361  1.1  christos      internal_function;
    362  1.1  christos #endif
    363  1.1  christos 
    364  1.1  christos #ifdef _LIBC
    365  1.1  christos # include "../locale/localeinfo.h"
    366  1.1  christos # define category_to_name(category) \
    367  1.1  christos   _nl_category_names.str + _nl_category_name_idxs[category]
    368  1.1  christos #else
    369  1.1  christos static const char *category_to_name (int category) internal_function;
    370  1.1  christos #endif
    371  1.1  christos #if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
    372  1.1  christos static const char *get_output_charset (struct binding *domainbinding)
    373  1.1  christos      internal_function;
    374  1.1  christos #endif
    375  1.1  christos 
    376  1.1  christos 
    377  1.1  christos /* For those loosing systems which don't have `alloca' we have to add
    378  1.1  christos    some additional code emulating it.  */
    379  1.1  christos #ifdef HAVE_ALLOCA
    380  1.1  christos /* Nothing has to be done.  */
    381  1.1  christos # define freea(p) /* nothing */
    382  1.1  christos # define ADD_BLOCK(list, address) /* nothing */
    383  1.1  christos # define FREE_BLOCKS(list) /* nothing */
    384  1.1  christos #else
    385  1.1  christos struct block_list
    386  1.1  christos {
    387  1.1  christos   void *address;
    388  1.1  christos   struct block_list *next;
    389  1.1  christos };
    390  1.1  christos # define ADD_BLOCK(list, addr)						      \
    391  1.1  christos   do {									      \
    392  1.1  christos     struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
    393  1.1  christos     /* If we cannot get a free block we cannot add the new element to	      \
    394  1.1  christos        the list.  */							      \
    395  1.1  christos     if (newp != NULL) {							      \
    396  1.1  christos       newp->address = (addr);						      \
    397  1.1  christos       newp->next = (list);						      \
    398  1.1  christos       (list) = newp;							      \
    399  1.1  christos     }									      \
    400  1.1  christos   } while (0)
    401  1.1  christos # define FREE_BLOCKS(list)						      \
    402  1.1  christos   do {									      \
    403  1.1  christos     while (list != NULL) {						      \
    404  1.1  christos       struct block_list *old = list;					      \
    405  1.1  christos       list = list->next;						      \
    406  1.1  christos       free (old->address);						      \
    407  1.1  christos       free (old);							      \
    408  1.1  christos     }									      \
    409  1.1  christos   } while (0)
    410  1.1  christos # undef alloca
    411  1.1  christos # define alloca(size) (malloc (size))
    412  1.1  christos # define freea(p) free (p)
    413  1.1  christos #endif	/* have alloca */
    414  1.1  christos 
    415  1.1  christos 
    416  1.1  christos #ifdef _LIBC
    417  1.1  christos /* List of blocks allocated for translations.  */
    418  1.1  christos typedef struct transmem_list
    419  1.1  christos {
    420  1.1  christos   struct transmem_list *next;
    421  1.1  christos   char data[ZERO];
    422  1.1  christos } transmem_block_t;
    423  1.1  christos static struct transmem_list *transmem_list;
    424  1.1  christos #else
    425  1.1  christos typedef unsigned char transmem_block_t;
    426  1.1  christos #endif
    427  1.1  christos 
    428  1.1  christos 
    429  1.1  christos /* Names for the libintl functions are a problem.  They must not clash
    430  1.1  christos    with existing names and they should follow ANSI C.  But this source
    431  1.1  christos    code is also used in GNU C Library where the names have a __
    432  1.1  christos    prefix.  So we have to make a difference here.  */
    433  1.1  christos #ifdef _LIBC
    434  1.1  christos # define DCIGETTEXT __dcigettext
    435  1.1  christos #else
    436  1.1  christos # define DCIGETTEXT libintl_dcigettext
    437  1.1  christos #endif
    438  1.1  christos 
    439  1.1  christos /* Lock variable to protect the global data in the gettext implementation.  */
    440  1.1  christos gl_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
    441  1.1  christos 
    442  1.1  christos /* Checking whether the binaries runs SUID must be done and glibc provides
    443  1.1  christos    easier methods therefore we make a difference here.  */
    444  1.1  christos #ifdef _LIBC
    445  1.1  christos # define ENABLE_SECURE __libc_enable_secure
    446  1.1  christos # define DETERMINE_SECURE
    447  1.1  christos #else
    448  1.1  christos # ifndef HAVE_GETUID
    449  1.1  christos #  define getuid() 0
    450  1.1  christos # endif
    451  1.1  christos # ifndef HAVE_GETGID
    452  1.1  christos #  define getgid() 0
    453  1.1  christos # endif
    454  1.1  christos # ifndef HAVE_GETEUID
    455  1.1  christos #  define geteuid() getuid()
    456  1.1  christos # endif
    457  1.1  christos # ifndef HAVE_GETEGID
    458  1.1  christos #  define getegid() getgid()
    459  1.1  christos # endif
    460  1.1  christos static int enable_secure;
    461  1.1  christos # define ENABLE_SECURE (enable_secure == 1)
    462  1.1  christos # define DETERMINE_SECURE \
    463  1.1  christos   if (enable_secure == 0)						      \
    464  1.1  christos     {									      \
    465  1.1  christos       if (getuid () != geteuid () || getgid () != getegid ())		      \
    466  1.1  christos 	enable_secure = 1;						      \
    467  1.1  christos       else								      \
    468  1.1  christos 	enable_secure = -1;						      \
    469  1.1  christos     }
    470  1.1  christos #endif
    471  1.1  christos 
    472  1.1  christos /* Get the function to evaluate the plural expression.  */
    473  1.1  christos #include "eval-plural.h"
    474  1.1  christos 
    475  1.1  christos /* Look up MSGID in the DOMAINNAME message catalog for the current
    476  1.1  christos    CATEGORY locale and, if PLURAL is nonzero, search over string
    477  1.1  christos    depending on the plural form determined by N.  */
    478  1.1  christos #ifdef IN_LIBGLOCALE
    479  1.1  christos char *
    480  1.1  christos gl_dcigettext (const char *domainname,
    481  1.1  christos 	       const char *msgid1, const char *msgid2,
    482  1.1  christos 	       int plural, unsigned long int n,
    483  1.1  christos 	       int category,
    484  1.1  christos 	       const char *localename, const char *encoding)
    485  1.1  christos #else
    486  1.1  christos char *
    487  1.1  christos DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
    488  1.1  christos 	    int plural, unsigned long int n, int category)
    489  1.1  christos #endif
    490  1.1  christos {
    491  1.1  christos #ifndef HAVE_ALLOCA
    492  1.1  christos   struct block_list *block_list = NULL;
    493  1.1  christos #endif
    494  1.1  christos   struct loaded_l10nfile *domain;
    495  1.1  christos   struct binding *binding;
    496  1.1  christos   const char *categoryname;
    497  1.1  christos   const char *categoryvalue;
    498  1.1  christos   const char *dirname;
    499  1.1  christos   char *xdomainname;
    500  1.1  christos   char *single_locale;
    501  1.1  christos   char *retval;
    502  1.1  christos   size_t retlen;
    503  1.1  christos   int saved_errno;
    504  1.1  christos #if defined HAVE_TSEARCH || defined _LIBC
    505  1.1  christos   struct known_translation_t *search;
    506  1.1  christos   struct known_translation_t **foundp = NULL;
    507  1.1  christos   size_t msgid_len;
    508  1.1  christos # if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE
    509  1.1  christos   const char *localename;
    510  1.1  christos # endif
    511  1.1  christos #endif
    512  1.1  christos   size_t domainname_len;
    513  1.1  christos 
    514  1.1  christos   /* If no real MSGID is given return NULL.  */
    515  1.1  christos   if (msgid1 == NULL)
    516  1.1  christos     return NULL;
    517  1.1  christos 
    518  1.1  christos #ifdef _LIBC
    519  1.1  christos   if (category < 0 || category >= __LC_LAST || category == LC_ALL)
    520  1.1  christos     /* Bogus.  */
    521  1.1  christos     return (plural == 0
    522  1.1  christos 	    ? (char *) msgid1
    523  1.1  christos 	    /* Use the Germanic plural rule.  */
    524  1.1  christos 	    : n == 1 ? (char *) msgid1 : (char *) msgid2);
    525  1.1  christos #endif
    526  1.1  christos 
    527  1.1  christos   gl_rwlock_rdlock (_nl_state_lock);
    528  1.1  christos 
    529  1.1  christos   /* If DOMAINNAME is NULL, we are interested in the default domain.  If
    530  1.1  christos      CATEGORY is not LC_MESSAGES this might not make much sense but the
    531  1.1  christos      definition left this undefined.  */
    532  1.1  christos   if (domainname == NULL)
    533  1.1  christos     domainname = _nl_current_default_domain;
    534  1.1  christos 
    535  1.1  christos   /* OS/2 specific: backward compatibility with older libintl versions  */
    536  1.1  christos #ifdef LC_MESSAGES_COMPAT
    537  1.1  christos   if (category == LC_MESSAGES_COMPAT)
    538  1.1  christos     category = LC_MESSAGES;
    539  1.1  christos #endif
    540  1.1  christos 
    541  1.1  christos #if defined HAVE_TSEARCH || defined _LIBC
    542  1.1  christos   msgid_len = strlen (msgid1) + 1;
    543  1.1  christos 
    544  1.1  christos   /* Try to find the translation among those which we found at
    545  1.1  christos      some time.  */
    546  1.1  christos   search = (struct known_translation_t *)
    547  1.1  christos 	   alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
    548  1.1  christos   memcpy (search->msgid, msgid1, msgid_len);
    549  1.1  christos   search->domainname = domainname;
    550  1.1  christos   search->category = category;
    551  1.1  christos # ifdef HAVE_PER_THREAD_LOCALE
    552  1.1  christos #  ifndef IN_LIBGLOCALE
    553  1.1  christos #   ifdef _LIBC
    554  1.1  christos   localename = __current_locale_name (category);
    555  1.1  christos #   else
    556  1.1  christos #    if HAVE_NL_LOCALE_NAME
    557  1.1  christos   /* NL_LOCALE_NAME is public glibc API introduced in glibc-2.4.  */
    558  1.1  christos   localename = nl_langinfo (NL_LOCALE_NAME (category));
    559  1.1  christos #    else
    560  1.1  christos #     if HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS
    561  1.1  christos   /* The __names field is not public glibc API and must therefore not be used
    562  1.1  christos      in code that is installed in public locations.  */
    563  1.1  christos   {
    564  1.1  christos     locale_t thread_locale = uselocale (NULL);
    565  1.1  christos     if (thread_locale != LC_GLOBAL_LOCALE)
    566  1.1  christos       localename = thread_locale->__names[category];
    567  1.1  christos     else
    568  1.1  christos       localename = "";
    569  1.1  christos   }
    570  1.1  christos #     endif
    571  1.1  christos #    endif
    572  1.1  christos #   endif
    573  1.1  christos #  endif
    574  1.1  christos   search->localename = localename;
    575  1.1  christos #  ifdef IN_LIBGLOCALE
    576  1.1  christos   search->encoding = encoding;
    577  1.1  christos #  endif
    578  1.1  christos # endif
    579  1.1  christos 
    580  1.1  christos   /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
    581  1.1  christos      tsearch calls can be fatal.  */
    582  1.1  christos   gl_rwlock_rdlock (tree_lock);
    583  1.1  christos 
    584  1.1  christos   foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
    585  1.1  christos 
    586  1.1  christos   gl_rwlock_unlock (tree_lock);
    587  1.1  christos 
    588  1.1  christos   freea (search);
    589  1.1  christos   if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
    590  1.1  christos     {
    591  1.1  christos       /* Now deal with plural.  */
    592  1.1  christos       if (plural)
    593  1.1  christos 	retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
    594  1.1  christos 				(*foundp)->translation_length);
    595  1.1  christos       else
    596  1.1  christos 	retval = (char *) (*foundp)->translation;
    597  1.1  christos 
    598  1.1  christos       gl_rwlock_unlock (_nl_state_lock);
    599  1.1  christos       return retval;
    600  1.1  christos     }
    601  1.1  christos #endif
    602  1.1  christos 
    603  1.1  christos   /* Preserve the `errno' value.  */
    604  1.1  christos   saved_errno = errno;
    605  1.1  christos 
    606  1.1  christos   /* See whether this is a SUID binary or not.  */
    607  1.1  christos   DETERMINE_SECURE;
    608  1.1  christos 
    609  1.1  christos   /* First find matching binding.  */
    610  1.1  christos #ifdef IN_LIBGLOCALE
    611  1.1  christos   /* We can use a trivial binding, since _nl_find_msg will ignore it anyway,
    612  1.1  christos      and _nl_load_domain and _nl_find_domain just pass it through.  */
    613  1.1  christos   binding = NULL;
    614  1.1  christos   dirname = bindtextdomain (domainname, NULL);
    615  1.1  christos #else
    616  1.1  christos   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
    617  1.1  christos     {
    618  1.1  christos       int compare = strcmp (domainname, binding->domainname);
    619  1.1  christos       if (compare == 0)
    620  1.1  christos 	/* We found it!  */
    621  1.1  christos 	break;
    622  1.1  christos       if (compare < 0)
    623  1.1  christos 	{
    624  1.1  christos 	  /* It is not in the list.  */
    625  1.1  christos 	  binding = NULL;
    626  1.1  christos 	  break;
    627  1.1  christos 	}
    628  1.1  christos     }
    629  1.1  christos 
    630  1.1  christos   if (binding == NULL)
    631  1.1  christos     dirname = _nl_default_dirname;
    632  1.1  christos   else
    633  1.1  christos     {
    634  1.1  christos       dirname = binding->dirname;
    635  1.1  christos #endif
    636  1.1  christos       if (!IS_ABSOLUTE_PATH (dirname))
    637  1.1  christos 	{
    638  1.1  christos 	  /* We have a relative path.  Make it absolute now.  */
    639  1.1  christos 	  size_t dirname_len = strlen (dirname) + 1;
    640  1.1  christos 	  size_t path_max;
    641  1.1  christos 	  char *resolved_dirname;
    642  1.1  christos 	  char *ret;
    643  1.1  christos 
    644  1.1  christos 	  path_max = (unsigned int) PATH_MAX;
    645  1.1  christos 	  path_max += 2;		/* The getcwd docs say to do this.  */
    646  1.1  christos 
    647  1.1  christos 	  for (;;)
    648  1.1  christos 	    {
    649  1.1  christos 	      resolved_dirname = (char *) alloca (path_max + dirname_len);
    650  1.1  christos 	      ADD_BLOCK (block_list, tmp_dirname);
    651  1.1  christos 
    652  1.1  christos 	      __set_errno (0);
    653  1.1  christos 	      ret = getcwd (resolved_dirname, path_max);
    654  1.1  christos 	      if (ret != NULL || errno != ERANGE)
    655  1.1  christos 		break;
    656  1.1  christos 
    657  1.1  christos 	      path_max += path_max / 2;
    658  1.1  christos 	      path_max += PATH_INCR;
    659  1.1  christos 	    }
    660  1.1  christos 
    661  1.1  christos 	  if (ret == NULL)
    662  1.1  christos 	    /* We cannot get the current working directory.  Don't signal an
    663  1.1  christos 	       error but simply return the default string.  */
    664  1.1  christos 	    goto return_untranslated;
    665  1.1  christos 
    666  1.1  christos 	  stpcpy (stpcpy (strchr (resolved_dirname, '\0'), "/"), dirname);
    667  1.1  christos 	  dirname = resolved_dirname;
    668  1.1  christos 	}
    669  1.1  christos #ifndef IN_LIBGLOCALE
    670  1.1  christos     }
    671  1.1  christos #endif
    672  1.1  christos 
    673  1.1  christos   /* Now determine the symbolic name of CATEGORY and its value.  */
    674  1.1  christos   categoryname = category_to_name (category);
    675  1.1  christos #ifdef IN_LIBGLOCALE
    676  1.1  christos   categoryvalue = guess_category_value (category, categoryname, localename);
    677  1.1  christos #else
    678  1.1  christos   categoryvalue = guess_category_value (category, categoryname);
    679  1.1  christos #endif
    680  1.1  christos 
    681  1.1  christos   domainname_len = strlen (domainname);
    682  1.1  christos   xdomainname = (char *) alloca (strlen (categoryname)
    683  1.1  christos 				 + domainname_len + 5);
    684  1.1  christos   ADD_BLOCK (block_list, xdomainname);
    685  1.1  christos 
    686  1.1  christos   stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
    687  1.1  christos 		  domainname, domainname_len),
    688  1.1  christos 	  ".mo");
    689  1.1  christos 
    690  1.1  christos   /* Creating working area.  */
    691  1.1  christos   single_locale = (char *) alloca (strlen (categoryvalue) + 1);
    692  1.1  christos   ADD_BLOCK (block_list, single_locale);
    693  1.1  christos 
    694  1.1  christos 
    695  1.1  christos   /* Search for the given string.  This is a loop because we perhaps
    696  1.1  christos      got an ordered list of languages to consider for the translation.  */
    697  1.1  christos   while (1)
    698  1.1  christos     {
    699  1.1  christos       /* Make CATEGORYVALUE point to the next element of the list.  */
    700  1.1  christos       while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
    701  1.1  christos 	++categoryvalue;
    702  1.1  christos       if (categoryvalue[0] == '\0')
    703  1.1  christos 	{
    704  1.1  christos 	  /* The whole contents of CATEGORYVALUE has been searched but
    705  1.1  christos 	     no valid entry has been found.  We solve this situation
    706  1.1  christos 	     by implicitly appending a "C" entry, i.e. no translation
    707  1.1  christos 	     will take place.  */
    708  1.1  christos 	  single_locale[0] = 'C';
    709  1.1  christos 	  single_locale[1] = '\0';
    710  1.1  christos 	}
    711  1.1  christos       else
    712  1.1  christos 	{
    713  1.1  christos 	  char *cp = single_locale;
    714  1.1  christos 	  while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
    715  1.1  christos 	    *cp++ = *categoryvalue++;
    716  1.1  christos 	  *cp = '\0';
    717  1.1  christos 
    718  1.1  christos 	  /* When this is a SUID binary we must not allow accessing files
    719  1.1  christos 	     outside the dedicated directories.  */
    720  1.1  christos 	  if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
    721  1.1  christos 	    /* Ingore this entry.  */
    722  1.1  christos 	    continue;
    723  1.1  christos 	}
    724  1.1  christos 
    725  1.1  christos       /* If the current locale value is C (or POSIX) we don't load a
    726  1.1  christos 	 domain.  Return the MSGID.  */
    727  1.1  christos       if (strcmp (single_locale, "C") == 0
    728  1.1  christos 	  || strcmp (single_locale, "POSIX") == 0)
    729  1.1  christos 	break;
    730  1.1  christos 
    731  1.1  christos       /* Find structure describing the message catalog matching the
    732  1.1  christos 	 DOMAINNAME and CATEGORY.  */
    733  1.1  christos       domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
    734  1.1  christos 
    735  1.1  christos       if (domain != NULL)
    736  1.1  christos 	{
    737  1.1  christos #if defined IN_LIBGLOCALE
    738  1.1  christos 	  retval = _nl_find_msg (domain, binding, encoding, msgid1, &retlen);
    739  1.1  christos #else
    740  1.1  christos 	  retval = _nl_find_msg (domain, binding, msgid1, 1, &retlen);
    741  1.1  christos #endif
    742  1.1  christos 
    743  1.1  christos 	  if (retval == NULL)
    744  1.1  christos 	    {
    745  1.1  christos 	      int cnt;
    746  1.1  christos 
    747  1.1  christos 	      for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
    748  1.1  christos 		{
    749  1.1  christos #if defined IN_LIBGLOCALE
    750  1.1  christos 		  retval = _nl_find_msg (domain->successor[cnt], binding,
    751  1.1  christos 					 encoding, msgid1, &retlen);
    752  1.1  christos #else
    753  1.1  christos 		  retval = _nl_find_msg (domain->successor[cnt], binding,
    754  1.1  christos 					 msgid1, 1, &retlen);
    755  1.1  christos #endif
    756  1.1  christos 
    757  1.1  christos 		  if (retval != NULL)
    758  1.1  christos 		    {
    759  1.1  christos 		      domain = domain->successor[cnt];
    760  1.1  christos 		      break;
    761  1.1  christos 		    }
    762  1.1  christos 		}
    763  1.1  christos 	    }
    764  1.1  christos 
    765  1.1  christos 	  /* Returning -1 means that some resource problem exists
    766  1.1  christos 	     (likely memory) and that the strings could not be
    767  1.1  christos 	     converted.  Return the original strings.  */
    768  1.1  christos 	  if (__builtin_expect (retval == (char *) -1, 0))
    769  1.1  christos 	    break;
    770  1.1  christos 
    771  1.1  christos 	  if (retval != NULL)
    772  1.1  christos 	    {
    773  1.1  christos 	      /* Found the translation of MSGID1 in domain DOMAIN:
    774  1.1  christos 		 starting at RETVAL, RETLEN bytes.  */
    775  1.1  christos 	      FREE_BLOCKS (block_list);
    776  1.1  christos #if defined HAVE_TSEARCH || defined _LIBC
    777  1.1  christos 	      if (foundp == NULL)
    778  1.1  christos 		{
    779  1.1  christos 		  /* Create a new entry and add it to the search tree.  */
    780  1.1  christos 		  size_t size;
    781  1.1  christos 		  struct known_translation_t *newp;
    782  1.1  christos 
    783  1.1  christos 		  size = offsetof (struct known_translation_t, msgid)
    784  1.1  christos 			 + msgid_len + domainname_len + 1;
    785  1.1  christos # ifdef HAVE_PER_THREAD_LOCALE
    786  1.1  christos 		  size += strlen (localename) + 1;
    787  1.1  christos # endif
    788  1.1  christos 		  newp = (struct known_translation_t *) malloc (size);
    789  1.1  christos 		  if (newp != NULL)
    790  1.1  christos 		    {
    791  1.1  christos 		      char *new_domainname;
    792  1.1  christos # ifdef HAVE_PER_THREAD_LOCALE
    793  1.1  christos 		      char *new_localename;
    794  1.1  christos # endif
    795  1.1  christos 
    796  1.1  christos 		      new_domainname = mempcpy (newp->msgid, msgid1, msgid_len);
    797  1.1  christos 		      memcpy (new_domainname, domainname, domainname_len + 1);
    798  1.1  christos # ifdef HAVE_PER_THREAD_LOCALE
    799  1.1  christos 		      new_localename = new_domainname + domainname_len + 1;
    800  1.1  christos 		      strcpy (new_localename, localename);
    801  1.1  christos # endif
    802  1.1  christos 		      newp->domainname = new_domainname;
    803  1.1  christos 		      newp->category = category;
    804  1.1  christos # ifdef HAVE_PER_THREAD_LOCALE
    805  1.1  christos 		      newp->localename = new_localename;
    806  1.1  christos # endif
    807  1.1  christos # ifdef IN_LIBGLOCALE
    808  1.1  christos 		      newp->encoding = encoding;
    809  1.1  christos # endif
    810  1.1  christos 		      newp->counter = _nl_msg_cat_cntr;
    811  1.1  christos 		      newp->domain = domain;
    812  1.1  christos 		      newp->translation = retval;
    813  1.1  christos 		      newp->translation_length = retlen;
    814  1.1  christos 
    815  1.1  christos 		      gl_rwlock_wrlock (tree_lock);
    816  1.1  christos 
    817  1.1  christos 		      /* Insert the entry in the search tree.  */
    818  1.1  christos 		      foundp = (struct known_translation_t **)
    819  1.1  christos 			tsearch (newp, &root, transcmp);
    820  1.1  christos 
    821  1.1  christos 		      gl_rwlock_unlock (tree_lock);
    822  1.1  christos 
    823  1.1  christos 		      if (foundp == NULL
    824  1.1  christos 			  || __builtin_expect (*foundp != newp, 0))
    825  1.1  christos 			/* The insert failed.  */
    826  1.1  christos 			free (newp);
    827  1.1  christos 		    }
    828  1.1  christos 		}
    829  1.1  christos 	      else
    830  1.1  christos 		{
    831  1.1  christos 		  /* We can update the existing entry.  */
    832  1.1  christos 		  (*foundp)->counter = _nl_msg_cat_cntr;
    833  1.1  christos 		  (*foundp)->domain = domain;
    834  1.1  christos 		  (*foundp)->translation = retval;
    835  1.1  christos 		  (*foundp)->translation_length = retlen;
    836  1.1  christos 		}
    837  1.1  christos #endif
    838  1.1  christos 	      __set_errno (saved_errno);
    839  1.1  christos 
    840  1.1  christos 	      /* Now deal with plural.  */
    841  1.1  christos 	      if (plural)
    842  1.1  christos 		retval = plural_lookup (domain, n, retval, retlen);
    843  1.1  christos 
    844  1.1  christos 	      gl_rwlock_unlock (_nl_state_lock);
    845  1.1  christos 	      return retval;
    846  1.1  christos 	    }
    847  1.1  christos 	}
    848  1.1  christos     }
    849  1.1  christos 
    850  1.1  christos  return_untranslated:
    851  1.1  christos   /* Return the untranslated MSGID.  */
    852  1.1  christos   FREE_BLOCKS (block_list);
    853  1.1  christos   gl_rwlock_unlock (_nl_state_lock);
    854  1.1  christos #ifndef _LIBC
    855  1.1  christos   if (!ENABLE_SECURE)
    856  1.1  christos     {
    857  1.1  christos       extern void _nl_log_untranslated (const char *logfilename,
    858  1.1  christos 					const char *domainname,
    859  1.1  christos 					const char *msgid1, const char *msgid2,
    860  1.1  christos 					int plural);
    861  1.1  christos       const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
    862  1.1  christos 
    863  1.1  christos       if (logfilename != NULL && logfilename[0] != '\0')
    864  1.1  christos 	_nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
    865  1.1  christos     }
    866  1.1  christos #endif
    867  1.1  christos   __set_errno (saved_errno);
    868  1.1  christos   return (plural == 0
    869  1.1  christos 	  ? (char *) msgid1
    870  1.1  christos 	  /* Use the Germanic plural rule.  */
    871  1.1  christos 	  : n == 1 ? (char *) msgid1 : (char *) msgid2);
    872  1.1  christos }
    873  1.1  christos 
    874  1.1  christos 
    875  1.1  christos /* Look up the translation of msgid within DOMAIN_FILE and DOMAINBINDING.
    876  1.1  christos    Return it if found.  Return NULL if not found or in case of a conversion
    877  1.1  christos    failure (problem in the particular message catalog).  Return (char *) -1
    878  1.1  christos    in case of a memory allocation failure during conversion (only if
    879  1.1  christos    ENCODING != NULL resp. CONVERT == true).  */
    880  1.1  christos char *
    881  1.1  christos internal_function
    882  1.1  christos #ifdef IN_LIBGLOCALE
    883  1.1  christos _nl_find_msg (struct loaded_l10nfile *domain_file,
    884  1.1  christos 	      struct binding *domainbinding, const char *encoding,
    885  1.1  christos 	      const char *msgid,
    886  1.1  christos 	      size_t *lengthp)
    887  1.1  christos #else
    888  1.1  christos _nl_find_msg (struct loaded_l10nfile *domain_file,
    889  1.1  christos 	      struct binding *domainbinding,
    890  1.1  christos 	      const char *msgid, int convert,
    891  1.1  christos 	      size_t *lengthp)
    892  1.1  christos #endif
    893  1.1  christos {
    894  1.1  christos   struct loaded_domain *domain;
    895  1.1  christos   nls_uint32 nstrings;
    896  1.1  christos   size_t act;
    897  1.1  christos   char *result;
    898  1.1  christos   size_t resultlen;
    899  1.1  christos 
    900  1.1  christos   if (domain_file->decided <= 0)
    901  1.1  christos     _nl_load_domain (domain_file, domainbinding);
    902  1.1  christos 
    903  1.1  christos   if (domain_file->data == NULL)
    904  1.1  christos     return NULL;
    905  1.1  christos 
    906  1.1  christos   domain = (struct loaded_domain *) domain_file->data;
    907  1.1  christos 
    908  1.1  christos   nstrings = domain->nstrings;
    909  1.1  christos 
    910  1.1  christos   /* Locate the MSGID and its translation.  */
    911  1.1  christos   if (domain->hash_tab != NULL)
    912  1.1  christos     {
    913  1.1  christos       /* Use the hashing table.  */
    914  1.1  christos       nls_uint32 len = strlen (msgid);
    915  1.1  christos       nls_uint32 hash_val = __hash_string (msgid);
    916  1.1  christos       nls_uint32 idx = hash_val % domain->hash_size;
    917  1.1  christos       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
    918  1.1  christos 
    919  1.1  christos       while (1)
    920  1.1  christos 	{
    921  1.1  christos 	  nls_uint32 nstr =
    922  1.1  christos 	    W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
    923  1.1  christos 
    924  1.1  christos 	  if (nstr == 0)
    925  1.1  christos 	    /* Hash table entry is empty.  */
    926  1.1  christos 	    return NULL;
    927  1.1  christos 
    928  1.1  christos 	  nstr--;
    929  1.1  christos 
    930  1.1  christos 	  /* Compare msgid with the original string at index nstr.
    931  1.1  christos 	     We compare the lengths with >=, not ==, because plural entries
    932  1.1  christos 	     are represented by strings with an embedded NUL.  */
    933  1.1  christos 	  if (nstr < nstrings
    934  1.1  christos 	      ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
    935  1.1  christos 		&& (strcmp (msgid,
    936  1.1  christos 			    domain->data + W (domain->must_swap,
    937  1.1  christos 					      domain->orig_tab[nstr].offset))
    938  1.1  christos 		    == 0)
    939  1.1  christos 	      : domain->orig_sysdep_tab[nstr - nstrings].length > len
    940  1.1  christos 		&& (strcmp (msgid,
    941  1.1  christos 			    domain->orig_sysdep_tab[nstr - nstrings].pointer)
    942  1.1  christos 		    == 0))
    943  1.1  christos 	    {
    944  1.1  christos 	      act = nstr;
    945  1.1  christos 	      goto found;
    946  1.1  christos 	    }
    947  1.1  christos 
    948  1.1  christos 	  if (idx >= domain->hash_size - incr)
    949  1.1  christos 	    idx -= domain->hash_size - incr;
    950  1.1  christos 	  else
    951  1.1  christos 	    idx += incr;
    952  1.1  christos 	}
    953  1.1  christos       /* NOTREACHED */
    954  1.1  christos     }
    955  1.1  christos   else
    956  1.1  christos     {
    957  1.1  christos       /* Try the default method:  binary search in the sorted array of
    958  1.1  christos 	 messages.  */
    959  1.1  christos       size_t top, bottom;
    960  1.1  christos 
    961  1.1  christos       bottom = 0;
    962  1.1  christos       top = nstrings;
    963  1.1  christos       while (bottom < top)
    964  1.1  christos 	{
    965  1.1  christos 	  int cmp_val;
    966  1.1  christos 
    967  1.1  christos 	  act = (bottom + top) / 2;
    968  1.1  christos 	  cmp_val = strcmp (msgid, (domain->data
    969  1.1  christos 				    + W (domain->must_swap,
    970  1.1  christos 					 domain->orig_tab[act].offset)));
    971  1.1  christos 	  if (cmp_val < 0)
    972  1.1  christos 	    top = act;
    973  1.1  christos 	  else if (cmp_val > 0)
    974  1.1  christos 	    bottom = act + 1;
    975  1.1  christos 	  else
    976  1.1  christos 	    goto found;
    977  1.1  christos 	}
    978  1.1  christos       /* No translation was found.  */
    979  1.1  christos       return NULL;
    980  1.1  christos     }
    981  1.1  christos 
    982  1.1  christos  found:
    983  1.1  christos   /* The translation was found at index ACT.  If we have to convert the
    984  1.1  christos      string to use a different character set, this is the time.  */
    985  1.1  christos   if (act < nstrings)
    986  1.1  christos     {
    987  1.1  christos       result = (char *)
    988  1.1  christos 	(domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
    989  1.1  christos       resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
    990  1.1  christos     }
    991  1.1  christos   else
    992  1.1  christos     {
    993  1.1  christos       result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
    994  1.1  christos       resultlen = domain->trans_sysdep_tab[act - nstrings].length;
    995  1.1  christos     }
    996  1.1  christos 
    997  1.1  christos #if defined _LIBC || HAVE_ICONV
    998  1.1  christos # ifdef IN_LIBGLOCALE
    999  1.1  christos   if (encoding != NULL)
   1000  1.1  christos # else
   1001  1.1  christos   if (convert)
   1002  1.1  christos # endif
   1003  1.1  christos     {
   1004  1.1  christos       /* We are supposed to do a conversion.  */
   1005  1.1  christos # ifndef IN_LIBGLOCALE
   1006  1.1  christos       const char *encoding = get_output_charset (domainbinding);
   1007  1.1  christos # endif
   1008  1.1  christos 
   1009  1.1  christos       /* Search whether a table with converted translations for this
   1010  1.1  christos 	 encoding has already been allocated.  */
   1011  1.1  christos       size_t nconversions = domain->nconversions;
   1012  1.1  christos       struct converted_domain *convd = NULL;
   1013  1.1  christos       size_t i;
   1014  1.1  christos 
   1015  1.1  christos       for (i = nconversions; i > 0; )
   1016  1.1  christos 	{
   1017  1.1  christos 	  i--;
   1018  1.1  christos 	  if (strcmp (domain->conversions[i].encoding, encoding) == 0)
   1019  1.1  christos 	    {
   1020  1.1  christos 	      convd = &domain->conversions[i];
   1021  1.1  christos 	      break;
   1022  1.1  christos 	    }
   1023  1.1  christos 	}
   1024  1.1  christos 
   1025  1.1  christos       if (convd == NULL)
   1026  1.1  christos 	{
   1027  1.1  christos 	  /* Allocate a table for the converted translations for this
   1028  1.1  christos 	     encoding.  */
   1029  1.1  christos 	  struct converted_domain *new_conversions =
   1030  1.1  christos 	    (struct converted_domain *)
   1031  1.1  christos 	    (domain->conversions != NULL
   1032  1.1  christos 	     ? realloc (domain->conversions,
   1033  1.1  christos 			(nconversions + 1) * sizeof (struct converted_domain))
   1034  1.1  christos 	     : malloc ((nconversions + 1) * sizeof (struct converted_domain)));
   1035  1.1  christos 
   1036  1.1  christos 	  if (__builtin_expect (new_conversions == NULL, 0))
   1037  1.1  christos 	    /* Nothing we can do, no more memory.  We cannot use the
   1038  1.1  christos 	       translation because it might be encoded incorrectly.  */
   1039  1.1  christos 	    return (char *) -1;
   1040  1.1  christos 
   1041  1.1  christos 	  domain->conversions = new_conversions;
   1042  1.1  christos 
   1043  1.1  christos 	  /* Copy the 'encoding' string to permanent storage.  */
   1044  1.1  christos 	  encoding = strdup (encoding);
   1045  1.1  christos 	  if (__builtin_expect (encoding == NULL, 0))
   1046  1.1  christos 	    /* Nothing we can do, no more memory.  We cannot use the
   1047  1.1  christos 	       translation because it might be encoded incorrectly.  */
   1048  1.1  christos 	    return (char *) -1;
   1049  1.1  christos 
   1050  1.1  christos 	  convd = &new_conversions[nconversions];
   1051  1.1  christos 	  convd->encoding = encoding;
   1052  1.1  christos 
   1053  1.1  christos 	  /* Find out about the character set the file is encoded with.
   1054  1.1  christos 	     This can be found (in textual form) in the entry "".  If this
   1055  1.1  christos 	     entry does not exist or if this does not contain the 'charset='
   1056  1.1  christos 	     information, we will assume the charset matches the one the
   1057  1.1  christos 	     current locale and we don't have to perform any conversion.  */
   1058  1.1  christos # ifdef _LIBC
   1059  1.1  christos 	  convd->conv = (__gconv_t) -1;
   1060  1.1  christos # else
   1061  1.1  christos #  if HAVE_ICONV
   1062  1.1  christos 	  convd->conv = (iconv_t) -1;
   1063  1.1  christos #  endif
   1064  1.1  christos # endif
   1065  1.1  christos 	  {
   1066  1.1  christos 	    char *nullentry;
   1067  1.1  christos 	    size_t nullentrylen;
   1068  1.1  christos 
   1069  1.1  christos 	    /* Get the header entry.  This is a recursion, but it doesn't
   1070  1.1  christos 	       reallocate domain->conversions because we pass
   1071  1.1  christos 	       encoding = NULL or convert = 0, respectively.  */
   1072  1.1  christos 	    nullentry =
   1073  1.1  christos # ifdef IN_LIBGLOCALE
   1074  1.1  christos 	      _nl_find_msg (domain_file, domainbinding, NULL, "",
   1075  1.1  christos 			    &nullentrylen);
   1076  1.1  christos # else
   1077  1.1  christos 	      _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
   1078  1.1  christos # endif
   1079  1.1  christos 
   1080  1.1  christos 	    if (nullentry != NULL)
   1081  1.1  christos 	      {
   1082  1.1  christos 		const char *charsetstr;
   1083  1.1  christos 
   1084  1.1  christos 		charsetstr = strstr (nullentry, "charset=");
   1085  1.1  christos 		if (charsetstr != NULL)
   1086  1.1  christos 		  {
   1087  1.1  christos 		    size_t len;
   1088  1.1  christos 		    char *charset;
   1089  1.1  christos 		    const char *outcharset;
   1090  1.1  christos 
   1091  1.1  christos 		    charsetstr += strlen ("charset=");
   1092  1.1  christos 		    len = strcspn (charsetstr, " \t\n");
   1093  1.1  christos 
   1094  1.1  christos 		    charset = (char *) alloca (len + 1);
   1095  1.1  christos # if defined _LIBC || HAVE_MEMPCPY
   1096  1.1  christos 		    *((char *) mempcpy (charset, charsetstr, len)) = '\0';
   1097  1.1  christos # else
   1098  1.1  christos 		    memcpy (charset, charsetstr, len);
   1099  1.1  christos 		    charset[len] = '\0';
   1100  1.1  christos # endif
   1101  1.1  christos 
   1102  1.1  christos 		    outcharset = encoding;
   1103  1.1  christos 
   1104  1.1  christos # ifdef _LIBC
   1105  1.1  christos 		    /* We always want to use transliteration.  */
   1106  1.1  christos 		    outcharset = norm_add_slashes (outcharset, "TRANSLIT");
   1107  1.1  christos 		    charset = norm_add_slashes (charset, "");
   1108  1.1  christos 		    int r = __gconv_open (outcharset, charset, &convd->conv,
   1109  1.1  christos 					  GCONV_AVOID_NOCONV);
   1110  1.1  christos 		    if (__builtin_expect (r != __GCONV_OK, 0))
   1111  1.1  christos 		      {
   1112  1.1  christos 			/* If the output encoding is the same there is
   1113  1.1  christos 			   nothing to do.  Otherwise do not use the
   1114  1.1  christos 			   translation at all.  */
   1115  1.1  christos 			if (__builtin_expect (r != __GCONV_NOCONV, 1))
   1116  1.1  christos 			  return NULL;
   1117  1.1  christos 
   1118  1.1  christos 			convd->conv = (__gconv_t) -1;
   1119  1.1  christos 		      }
   1120  1.1  christos # else
   1121  1.1  christos #  if HAVE_ICONV
   1122  1.1  christos 		    /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
   1123  1.1  christos 		       we want to use transliteration.  */
   1124  1.1  christos #   if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
   1125  1.1  christos        || _LIBICONV_VERSION >= 0x0105
   1126  1.1  christos 		    if (strchr (outcharset, '/') == NULL)
   1127  1.1  christos 		      {
   1128  1.1  christos 			char *tmp;
   1129  1.1  christos 
   1130  1.1  christos 			len = strlen (outcharset);
   1131  1.1  christos 			tmp = (char *) alloca (len + 10 + 1);
   1132  1.1  christos 			memcpy (tmp, outcharset, len);
   1133  1.1  christos 			memcpy (tmp + len, "//TRANSLIT", 10 + 1);
   1134  1.1  christos 			outcharset = tmp;
   1135  1.1  christos 
   1136  1.1  christos 			convd->conv = iconv_open (outcharset, charset);
   1137  1.1  christos 
   1138  1.1  christos 			freea (outcharset);
   1139  1.1  christos 		      }
   1140  1.1  christos 		    else
   1141  1.1  christos #   endif
   1142  1.1  christos 		      convd->conv = iconv_open (outcharset, charset);
   1143  1.1  christos #  endif
   1144  1.1  christos # endif
   1145  1.1  christos 
   1146  1.1  christos 		    freea (charset);
   1147  1.1  christos 		  }
   1148  1.1  christos 	      }
   1149  1.1  christos 	  }
   1150  1.1  christos 	  convd->conv_tab = NULL;
   1151  1.1  christos 	  /* Here domain->conversions is still == new_conversions.  */
   1152  1.1  christos 	  domain->nconversions++;
   1153  1.1  christos 	}
   1154  1.1  christos 
   1155  1.1  christos       if (
   1156  1.1  christos # ifdef _LIBC
   1157  1.1  christos 	  convd->conv != (__gconv_t) -1
   1158  1.1  christos # else
   1159  1.1  christos #  if HAVE_ICONV
   1160  1.1  christos 	  convd->conv != (iconv_t) -1
   1161  1.1  christos #  endif
   1162  1.1  christos # endif
   1163  1.1  christos 	  )
   1164  1.1  christos 	{
   1165  1.1  christos 	  /* We are supposed to do a conversion.  First allocate an
   1166  1.1  christos 	     appropriate table with the same structure as the table
   1167  1.1  christos 	     of translations in the file, where we can put the pointers
   1168  1.1  christos 	     to the converted strings in.
   1169  1.1  christos 	     There is a slight complication with plural entries.  They
   1170  1.1  christos 	     are represented by consecutive NUL terminated strings.  We
   1171  1.1  christos 	     handle this case by converting RESULTLEN bytes, including
   1172  1.1  christos 	     NULs.  */
   1173  1.1  christos 
   1174  1.1  christos 	  if (convd->conv_tab == NULL
   1175  1.1  christos 	      && ((convd->conv_tab =
   1176  1.1  christos 		    (char **) calloc (nstrings + domain->n_sysdep_strings,
   1177  1.1  christos 				      sizeof (char *)))
   1178  1.1  christos 		  == NULL))
   1179  1.1  christos 	    /* Mark that we didn't succeed allocating a table.  */
   1180  1.1  christos 	    convd->conv_tab = (char **) -1;
   1181  1.1  christos 
   1182  1.1  christos 	  if (__builtin_expect (convd->conv_tab == (char **) -1, 0))
   1183  1.1  christos 	    /* Nothing we can do, no more memory.  We cannot use the
   1184  1.1  christos 	       translation because it might be encoded incorrectly.  */
   1185  1.1  christos 	    return (char *) -1;
   1186  1.1  christos 
   1187  1.1  christos 	  if (convd->conv_tab[act] == NULL)
   1188  1.1  christos 	    {
   1189  1.1  christos 	      /* We haven't used this string so far, so it is not
   1190  1.1  christos 		 translated yet.  Do this now.  */
   1191  1.1  christos 	      /* We use a bit more efficient memory handling.
   1192  1.1  christos 		 We allocate always larger blocks which get used over
   1193  1.1  christos 		 time.  This is faster than many small allocations.   */
   1194  1.1  christos 	      __libc_lock_define_initialized (static, lock)
   1195  1.1  christos # define INITIAL_BLOCK_SIZE	4080
   1196  1.1  christos 	      static unsigned char *freemem;
   1197  1.1  christos 	      static size_t freemem_size;
   1198  1.1  christos 
   1199  1.1  christos 	      const unsigned char *inbuf;
   1200  1.1  christos 	      unsigned char *outbuf;
   1201  1.1  christos 	      int malloc_count;
   1202  1.1  christos # ifndef _LIBC
   1203  1.1  christos 	      transmem_block_t *transmem_list = NULL;
   1204  1.1  christos # endif
   1205  1.1  christos 
   1206  1.1  christos 	      __libc_lock_lock (lock);
   1207  1.1  christos 
   1208  1.1  christos 	      inbuf = (const unsigned char *) result;
   1209  1.1  christos 	      outbuf = freemem + sizeof (size_t);
   1210  1.1  christos 
   1211  1.1  christos 	      malloc_count = 0;
   1212  1.1  christos 	      while (1)
   1213  1.1  christos 		{
   1214  1.1  christos 		  transmem_block_t *newmem;
   1215  1.1  christos # ifdef _LIBC
   1216  1.1  christos 		  size_t non_reversible;
   1217  1.1  christos 		  int res;
   1218  1.1  christos 
   1219  1.1  christos 		  if (freemem_size < sizeof (size_t))
   1220  1.1  christos 		    goto resize_freemem;
   1221  1.1  christos 
   1222  1.1  christos 		  res = __gconv (convd->conv,
   1223  1.1  christos 				 &inbuf, inbuf + resultlen,
   1224  1.1  christos 				 &outbuf,
   1225  1.1  christos 				 outbuf + freemem_size - sizeof (size_t),
   1226  1.1  christos 				 &non_reversible);
   1227  1.1  christos 
   1228  1.1  christos 		  if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
   1229  1.1  christos 		    break;
   1230  1.1  christos 
   1231  1.1  christos 		  if (res != __GCONV_FULL_OUTPUT)
   1232  1.1  christos 		    {
   1233  1.1  christos 		      /* We should not use the translation at all, it
   1234  1.1  christos 			 is incorrectly encoded.  */
   1235  1.1  christos 		      __libc_lock_unlock (lock);
   1236  1.1  christos 		      return NULL;
   1237  1.1  christos 		    }
   1238  1.1  christos 
   1239  1.1  christos 		  inbuf = (const unsigned char *) result;
   1240  1.1  christos # else
   1241  1.1  christos #  if HAVE_ICONV
   1242  1.1  christos 		  const char *inptr = (const char *) inbuf;
   1243  1.1  christos 		  size_t inleft = resultlen;
   1244  1.1  christos 		  char *outptr = (char *) outbuf;
   1245  1.1  christos 		  size_t outleft;
   1246  1.1  christos 
   1247  1.1  christos 		  if (freemem_size < sizeof (size_t))
   1248  1.1  christos 		    goto resize_freemem;
   1249  1.1  christos 
   1250  1.1  christos 		  outleft = freemem_size - sizeof (size_t);
   1251  1.1  christos 		  if (iconv (convd->conv,
   1252  1.1  christos 			     (ICONV_CONST char **) &inptr, &inleft,
   1253  1.1  christos 			     &outptr, &outleft)
   1254  1.1  christos 		      != (size_t) (-1))
   1255  1.1  christos 		    {
   1256  1.1  christos 		      outbuf = (unsigned char *) outptr;
   1257  1.1  christos 		      break;
   1258  1.1  christos 		    }
   1259  1.1  christos 		  if (errno != E2BIG)
   1260  1.1  christos 		    {
   1261  1.1  christos 		      __libc_lock_unlock (lock);
   1262  1.1  christos 		      return NULL;
   1263  1.1  christos 		    }
   1264  1.1  christos #  endif
   1265  1.1  christos # endif
   1266  1.1  christos 
   1267  1.1  christos 		resize_freemem:
   1268  1.1  christos 		  /* We must allocate a new buffer or resize the old one.  */
   1269  1.1  christos 		  if (malloc_count > 0)
   1270  1.1  christos 		    {
   1271  1.1  christos 		      ++malloc_count;
   1272  1.1  christos 		      freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
   1273  1.1  christos 		      newmem = (transmem_block_t *) realloc (transmem_list,
   1274  1.1  christos 							     freemem_size);
   1275  1.1  christos # ifdef _LIBC
   1276  1.1  christos 		      if (newmem != NULL)
   1277  1.1  christos 			transmem_list = transmem_list->next;
   1278  1.1  christos 		      else
   1279  1.1  christos 			{
   1280  1.1  christos 			  struct transmem_list *old = transmem_list;
   1281  1.1  christos 
   1282  1.1  christos 			  transmem_list = transmem_list->next;
   1283  1.1  christos 			  free (old);
   1284  1.1  christos 			}
   1285  1.1  christos # endif
   1286  1.1  christos 		    }
   1287  1.1  christos 		  else
   1288  1.1  christos 		    {
   1289  1.1  christos 		      malloc_count = 1;
   1290  1.1  christos 		      freemem_size = INITIAL_BLOCK_SIZE;
   1291  1.1  christos 		      newmem = (transmem_block_t *) malloc (freemem_size);
   1292  1.1  christos 		    }
   1293  1.1  christos 		  if (__builtin_expect (newmem == NULL, 0))
   1294  1.1  christos 		    {
   1295  1.1  christos 		      freemem = NULL;
   1296  1.1  christos 		      freemem_size = 0;
   1297  1.1  christos 		      __libc_lock_unlock (lock);
   1298  1.1  christos 		      return (char *) -1;
   1299  1.1  christos 		    }
   1300  1.1  christos 
   1301  1.1  christos # ifdef _LIBC
   1302  1.1  christos 		  /* Add the block to the list of blocks we have to free
   1303  1.1  christos 		     at some point.  */
   1304  1.1  christos 		  newmem->next = transmem_list;
   1305  1.1  christos 		  transmem_list = newmem;
   1306  1.1  christos 
   1307  1.1  christos 		  freemem = (unsigned char *) newmem->data;
   1308  1.1  christos 		  freemem_size -= offsetof (struct transmem_list, data);
   1309  1.1  christos # else
   1310  1.1  christos 		  transmem_list = newmem;
   1311  1.1  christos 		  freemem = newmem;
   1312  1.1  christos # endif
   1313  1.1  christos 
   1314  1.1  christos 		  outbuf = freemem + sizeof (size_t);
   1315  1.1  christos 		}
   1316  1.1  christos 
   1317  1.1  christos 	      /* We have now in our buffer a converted string.  Put this
   1318  1.1  christos 		 into the table of conversions.  */
   1319  1.1  christos 	      *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
   1320  1.1  christos 	      convd->conv_tab[act] = (char *) freemem;
   1321  1.1  christos 	      /* Shrink freemem, but keep it aligned.  */
   1322  1.1  christos 	      freemem_size -= outbuf - freemem;
   1323  1.1  christos 	      freemem = outbuf;
   1324  1.1  christos 	      freemem += freemem_size & (alignof (size_t) - 1);
   1325  1.1  christos 	      freemem_size = freemem_size & ~ (alignof (size_t) - 1);
   1326  1.1  christos 
   1327  1.1  christos 	      __libc_lock_unlock (lock);
   1328  1.1  christos 	    }
   1329  1.1  christos 
   1330  1.1  christos 	  /* Now convd->conv_tab[act] contains the translation of all
   1331  1.1  christos 	     the plural variants.  */
   1332  1.1  christos 	  result = convd->conv_tab[act] + sizeof (size_t);
   1333  1.1  christos 	  resultlen = *(size_t *) convd->conv_tab[act];
   1334  1.1  christos 	}
   1335  1.1  christos     }
   1336  1.1  christos 
   1337  1.1  christos   /* The result string is converted.  */
   1338  1.1  christos 
   1339  1.1  christos #endif /* _LIBC || HAVE_ICONV */
   1340  1.1  christos 
   1341  1.1  christos   *lengthp = resultlen;
   1342  1.1  christos   return result;
   1343  1.1  christos }
   1344  1.1  christos 
   1345  1.1  christos 
   1346  1.1  christos /* Look up a plural variant.  */
   1347  1.1  christos static char *
   1348  1.1  christos internal_function
   1349  1.1  christos plural_lookup (struct loaded_l10nfile *domain, unsigned long int n,
   1350  1.1  christos 	       const char *translation, size_t translation_len)
   1351  1.1  christos {
   1352  1.1  christos   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
   1353  1.1  christos   unsigned long int index;
   1354  1.1  christos   const char *p;
   1355  1.1  christos 
   1356  1.1  christos   index = plural_eval (domaindata->plural, n);
   1357  1.1  christos   if (index >= domaindata->nplurals)
   1358  1.1  christos     /* This should never happen.  It means the plural expression and the
   1359  1.1  christos        given maximum value do not match.  */
   1360  1.1  christos     index = 0;
   1361  1.1  christos 
   1362  1.1  christos   /* Skip INDEX strings at TRANSLATION.  */
   1363  1.1  christos   p = translation;
   1364  1.1  christos   while (index-- > 0)
   1365  1.1  christos     {
   1366  1.1  christos #ifdef _LIBC
   1367  1.1  christos       p = __rawmemchr (p, '\0');
   1368  1.1  christos #else
   1369  1.1  christos       p = strchr (p, '\0');
   1370  1.1  christos #endif
   1371  1.1  christos       /* And skip over the NUL byte.  */
   1372  1.1  christos       p++;
   1373  1.1  christos 
   1374  1.1  christos       if (p >= translation + translation_len)
   1375  1.1  christos 	/* This should never happen.  It means the plural expression
   1376  1.1  christos 	   evaluated to a value larger than the number of variants
   1377  1.1  christos 	   available for MSGID1.  */
   1378  1.1  christos 	return (char *) translation;
   1379  1.1  christos     }
   1380  1.1  christos   return (char *) p;
   1381  1.1  christos }
   1382  1.1  christos 
   1383  1.1  christos #ifndef _LIBC
   1384  1.1  christos /* Return string representation of locale CATEGORY.  */
   1385  1.1  christos static const char *
   1386  1.1  christos internal_function
   1387  1.1  christos category_to_name (int category)
   1388  1.1  christos {
   1389  1.1  christos   const char *retval;
   1390  1.1  christos 
   1391  1.1  christos   switch (category)
   1392  1.1  christos   {
   1393  1.1  christos #ifdef LC_COLLATE
   1394  1.1  christos   case LC_COLLATE:
   1395  1.1  christos     retval = "LC_COLLATE";
   1396  1.1  christos     break;
   1397  1.1  christos #endif
   1398  1.1  christos #ifdef LC_CTYPE
   1399  1.1  christos   case LC_CTYPE:
   1400  1.1  christos     retval = "LC_CTYPE";
   1401  1.1  christos     break;
   1402  1.1  christos #endif
   1403  1.1  christos #ifdef LC_MONETARY
   1404  1.1  christos   case LC_MONETARY:
   1405  1.1  christos     retval = "LC_MONETARY";
   1406  1.1  christos     break;
   1407  1.1  christos #endif
   1408  1.1  christos #ifdef LC_NUMERIC
   1409  1.1  christos   case LC_NUMERIC:
   1410  1.1  christos     retval = "LC_NUMERIC";
   1411  1.1  christos     break;
   1412  1.1  christos #endif
   1413  1.1  christos #ifdef LC_TIME
   1414  1.1  christos   case LC_TIME:
   1415  1.1  christos     retval = "LC_TIME";
   1416  1.1  christos     break;
   1417  1.1  christos #endif
   1418  1.1  christos #ifdef LC_MESSAGES
   1419  1.1  christos   case LC_MESSAGES:
   1420  1.1  christos     retval = "LC_MESSAGES";
   1421  1.1  christos     break;
   1422  1.1  christos #endif
   1423  1.1  christos #ifdef LC_RESPONSE
   1424  1.1  christos   case LC_RESPONSE:
   1425  1.1  christos     retval = "LC_RESPONSE";
   1426  1.1  christos     break;
   1427  1.1  christos #endif
   1428  1.1  christos #ifdef LC_ALL
   1429  1.1  christos   case LC_ALL:
   1430  1.1  christos     /* This might not make sense but is perhaps better than any other
   1431  1.1  christos        value.  */
   1432  1.1  christos     retval = "LC_ALL";
   1433  1.1  christos     break;
   1434  1.1  christos #endif
   1435  1.1  christos   default:
   1436  1.1  christos     /* If you have a better idea for a default value let me know.  */
   1437  1.1  christos     retval = "LC_XXX";
   1438  1.1  christos   }
   1439  1.1  christos 
   1440  1.1  christos   return retval;
   1441  1.1  christos }
   1442  1.1  christos #endif
   1443  1.1  christos 
   1444  1.1  christos /* Guess value of current locale from value of the environment variables
   1445  1.1  christos    or system-dependent defaults.  */
   1446  1.1  christos static const char *
   1447  1.1  christos internal_function
   1448  1.1  christos #ifdef IN_LIBGLOCALE
   1449  1.1  christos guess_category_value (int category, const char *categoryname,
   1450  1.1  christos 		      const char *locale)
   1451  1.1  christos 
   1452  1.1  christos #else
   1453  1.1  christos guess_category_value (int category, const char *categoryname)
   1454  1.1  christos #endif
   1455  1.1  christos {
   1456  1.1  christos   const char *language;
   1457  1.1  christos #ifndef IN_LIBGLOCALE
   1458  1.1  christos   const char *locale;
   1459  1.1  christos # ifndef _LIBC
   1460  1.1  christos   const char *language_default;
   1461  1.1  christos   int locale_defaulted;
   1462  1.1  christos # endif
   1463  1.1  christos #endif
   1464  1.1  christos 
   1465  1.1  christos   /* We use the settings in the following order:
   1466  1.1  christos      1. The value of the environment variable 'LANGUAGE'.  This is a GNU
   1467  1.1  christos         extension.  Its value can be a colon-separated list of locale names.
   1468  1.1  christos      2. The value of the environment variable 'LC_ALL', 'LC_xxx', or 'LANG'.
   1469  1.1  christos         More precisely, the first among these that is set to a non-empty value.
   1470  1.1  christos         This is how POSIX specifies it.  The value is a single locale name.
   1471  1.1  christos      3. A system-dependent preference list of languages.  Its value can be a
   1472  1.1  christos         colon-separated list of locale names.
   1473  1.1  christos      4. A system-dependent default locale name.
   1474  1.1  christos      This way:
   1475  1.1  christos        - System-dependent settings can be overridden by environment variables.
   1476  1.1  christos        - If the system provides both a list of languages and a default locale,
   1477  1.1  christos          the former is used.  */
   1478  1.1  christos 
   1479  1.1  christos #ifndef IN_LIBGLOCALE
   1480  1.1  christos   /* Fetch the locale name, through the POSIX method of looking to `LC_ALL',
   1481  1.1  christos      `LC_xxx', and `LANG'.  On some systems this can be done by the
   1482  1.1  christos      `setlocale' function itself.  */
   1483  1.1  christos # ifdef _LIBC
   1484  1.1  christos   locale = __current_locale_name (category);
   1485  1.1  christos # else
   1486  1.1  christos #  if HAVE_STRUCT___LOCALE_STRUCT___NAMES && defined USE_IN_GETTEXT_TESTS
   1487  1.1  christos   /* The __names field is not public glibc API and must therefore not be used
   1488  1.1  christos      in code that is installed in public locations.  */
   1489  1.1  christos   locale_t thread_locale = uselocale (NULL);
   1490  1.1  christos   if (thread_locale != LC_GLOBAL_LOCALE)
   1491  1.1  christos     {
   1492  1.1  christos       locale = thread_locale->__names[category];
   1493  1.1  christos       locale_defaulted = 0;
   1494  1.1  christos     }
   1495  1.1  christos   else
   1496  1.1  christos #  endif
   1497  1.1  christos     {
   1498  1.1  christos       locale = _nl_locale_name_posix (category, categoryname);
   1499  1.1  christos       locale_defaulted = 0;
   1500  1.1  christos       if (locale == NULL)
   1501  1.1  christos 	{
   1502  1.1  christos 	  locale = _nl_locale_name_default ();
   1503  1.1  christos 	  locale_defaulted = 1;
   1504  1.1  christos 	}
   1505  1.1  christos     }
   1506  1.1  christos # endif
   1507  1.1  christos #endif
   1508  1.1  christos 
   1509  1.1  christos   /* Ignore LANGUAGE and its system-dependent analogon if the locale is set
   1510  1.1  christos      to "C" because
   1511  1.1  christos      1. "C" locale usually uses the ASCII encoding, and most international
   1512  1.1  christos 	messages use non-ASCII characters. These characters get displayed
   1513  1.1  christos 	as question marks (if using glibc's iconv()) or as invalid 8-bit
   1514  1.1  christos 	characters (because other iconv()s refuse to convert most non-ASCII
   1515  1.1  christos 	characters to ASCII). In any case, the output is ugly.
   1516  1.1  christos      2. The precise output of some programs in the "C" locale is specified
   1517  1.1  christos 	by POSIX and should not depend on environment variables like
   1518  1.1  christos 	"LANGUAGE" or system-dependent information.  We allow such programs
   1519  1.1  christos         to use gettext().  */
   1520  1.1  christos   if (strcmp (locale, "C") == 0)
   1521  1.1  christos     return locale;
   1522  1.1  christos 
   1523  1.1  christos   /* The highest priority value is the value of the 'LANGUAGE' environment
   1524  1.1  christos      variable.  */
   1525  1.1  christos   language = getenv ("LANGUAGE");
   1526  1.1  christos   if (language != NULL && language[0] != '\0')
   1527  1.1  christos     return language;
   1528  1.1  christos #if !defined IN_LIBGLOCALE && !defined _LIBC
   1529  1.1  christos   /* The next priority value is the locale name, if not defaulted.  */
   1530  1.1  christos   if (locale_defaulted)
   1531  1.1  christos     {
   1532  1.1  christos       /* The next priority value is the default language preferences list. */
   1533  1.1  christos       language_default = _nl_language_preferences_default ();
   1534  1.1  christos       if (language_default != NULL)
   1535  1.1  christos         return language_default;
   1536  1.1  christos     }
   1537  1.1  christos   /* The least priority value is the locale name, if defaulted.  */
   1538  1.1  christos #endif
   1539  1.1  christos   return locale;
   1540  1.1  christos }
   1541  1.1  christos 
   1542  1.1  christos #if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
   1543  1.1  christos /* Returns the output charset.  */
   1544  1.1  christos static const char *
   1545  1.1  christos internal_function
   1546  1.1  christos get_output_charset (struct binding *domainbinding)
   1547  1.1  christos {
   1548  1.1  christos   /* The output charset should normally be determined by the locale.  But
   1549  1.1  christos      sometimes the locale is not used or not correctly set up, so we provide
   1550  1.1  christos      a possibility for the user to override this: the OUTPUT_CHARSET
   1551  1.1  christos      environment variable.  Moreover, the value specified through
   1552  1.1  christos      bind_textdomain_codeset overrides both.  */
   1553  1.1  christos   if (domainbinding != NULL && domainbinding->codeset != NULL)
   1554  1.1  christos     return domainbinding->codeset;
   1555  1.1  christos   else
   1556  1.1  christos     {
   1557  1.1  christos       /* For speed reasons, we look at the value of OUTPUT_CHARSET only
   1558  1.1  christos 	 once.  This is a user variable that is not supposed to change
   1559  1.1  christos 	 during a program run.  */
   1560  1.1  christos       static char *output_charset_cache;
   1561  1.1  christos       static int output_charset_cached;
   1562  1.1  christos 
   1563  1.1  christos       if (!output_charset_cached)
   1564  1.1  christos 	{
   1565  1.1  christos 	  const char *value = getenv ("OUTPUT_CHARSET");
   1566  1.1  christos 
   1567  1.1  christos 	  if (value != NULL && value[0] != '\0')
   1568  1.1  christos 	    {
   1569  1.1  christos 	      size_t len = strlen (value) + 1;
   1570  1.1  christos 	      char *value_copy = (char *) malloc (len);
   1571  1.1  christos 
   1572  1.1  christos 	      if (value_copy != NULL)
   1573  1.1  christos 		memcpy (value_copy, value, len);
   1574  1.1  christos 	      output_charset_cache = value_copy;
   1575  1.1  christos 	    }
   1576  1.1  christos 	  output_charset_cached = 1;
   1577  1.1  christos 	}
   1578  1.1  christos 
   1579  1.1  christos       if (output_charset_cache != NULL)
   1580  1.1  christos 	return output_charset_cache;
   1581  1.1  christos       else
   1582  1.1  christos 	{
   1583  1.1  christos # ifdef _LIBC
   1584  1.1  christos 	  return _NL_CURRENT (LC_CTYPE, CODESET);
   1585  1.1  christos # else
   1586  1.1  christos #  if HAVE_ICONV
   1587  1.1  christos 	  extern const char *locale_charset (void);
   1588  1.1  christos 	  return locale_charset ();
   1589  1.1  christos #  endif
   1590  1.1  christos # endif
   1591  1.1  christos 	}
   1592  1.1  christos     }
   1593  1.1  christos }
   1594  1.1  christos #endif
   1595  1.1  christos 
   1596  1.1  christos /* @@ begin of epilog @@ */
   1597  1.1  christos 
   1598  1.1  christos /* We don't want libintl.a to depend on any other library.  So we
   1599  1.1  christos    avoid the non-standard function stpcpy.  In GNU C Library this
   1600  1.1  christos    function is available, though.  Also allow the symbol HAVE_STPCPY
   1601  1.1  christos    to be defined.  */
   1602  1.1  christos #if !_LIBC && !HAVE_STPCPY
   1603  1.1  christos static char *
   1604  1.1  christos stpcpy (char *dest, const char *src)
   1605  1.1  christos {
   1606  1.1  christos   while ((*dest++ = *src++) != '\0')
   1607  1.1  christos     /* Do nothing. */ ;
   1608  1.1  christos   return dest - 1;
   1609  1.1  christos }
   1610  1.1  christos #endif
   1611  1.1  christos 
   1612  1.1  christos #if !_LIBC && !HAVE_MEMPCPY
   1613  1.1  christos static void *
   1614  1.1  christos mempcpy (void *dest, const void *src, size_t n)
   1615  1.1  christos {
   1616  1.1  christos   return (void *) ((char *) memcpy (dest, src, n) + n);
   1617  1.1  christos }
   1618  1.1  christos #endif
   1619  1.1  christos 
   1620  1.1  christos 
   1621  1.1  christos #ifdef _LIBC
   1622  1.1  christos /* If we want to free all resources we have to do some work at
   1623  1.1  christos    program's end.  */
   1624  1.1  christos libc_freeres_fn (free_mem)
   1625  1.1  christos {
   1626  1.1  christos   void *old;
   1627  1.1  christos 
   1628  1.1  christos   while (_nl_domain_bindings != NULL)
   1629  1.1  christos     {
   1630  1.1  christos       struct binding *oldp = _nl_domain_bindings;
   1631  1.1  christos       _nl_domain_bindings = _nl_domain_bindings->next;
   1632  1.1  christos       if (oldp->dirname != _nl_default_dirname)
   1633  1.1  christos 	/* Yes, this is a pointer comparison.  */
   1634  1.1  christos 	free (oldp->dirname);
   1635  1.1  christos       free (oldp->codeset);
   1636  1.1  christos       free (oldp);
   1637  1.1  christos     }
   1638  1.1  christos 
   1639  1.1  christos   if (_nl_current_default_domain != _nl_default_default_domain)
   1640  1.1  christos     /* Yes, again a pointer comparison.  */
   1641  1.1  christos     free ((char *) _nl_current_default_domain);
   1642  1.1  christos 
   1643  1.1  christos   /* Remove the search tree with the known translations.  */
   1644  1.1  christos   __tdestroy (root, free);
   1645  1.1  christos   root = NULL;
   1646  1.1  christos 
   1647  1.1  christos   while (transmem_list != NULL)
   1648  1.1  christos     {
   1649  1.1  christos       old = transmem_list;
   1650  1.1  christos       transmem_list = transmem_list->next;
   1651  1.1  christos       free (old);
   1652  1.1  christos     }
   1653  1.1  christos }
   1654  1.1  christos #endif
   1655