"Fossies" - the Fresh Open Source Software Archive

Member "OpenSP-1.5.2/intl/dcigettext.c" (26 Aug 2005, 34926 Bytes) of package /linux/misc/old/OpenSP-1.5.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   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
   47 char *alloca ();
   48 #    endif
   49 #   endif
   50 #  endif
   51 # endif
   52 #endif
   53 
   54 #include <errno.h>
   55 #ifndef errno
   56 extern 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
  148 char *getwd ();
  149 #  define getcwd(buf, max) getwd (buf)
  150 # else
  151 #  if VMS
  152 #   define getcwd(buf, max) (getcwd) (buf, max, 0)
  153 #  else
  154 char *getcwd ();
  155 #  endif
  156 # endif
  157 # ifndef HAVE_STPCPY
  158 static char *stpcpy (char *dest, const char *src);
  159 # endif
  160 # ifndef HAVE_MEMPCPY
  161 static 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.  */
  221 struct 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 
  248 static 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.  */
  255 static int
  256 transcmp (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".  */
  289 const char _nl_default_default_domain[] attribute_hidden = "messages";
  290 
  291 /* Value used as the default domain for gettext(3).  */
  292 const 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__
  297 extern const char _nl_default_dirname[];
  298 #else
  299 const char _nl_default_dirname[] = LOCALEDIR;
  300 INTVARDEF (_nl_default_dirname)
  301 #endif
  302 
  303 /* List with bindings of specific domains created by bindtextdomain()
  304    calls.  */
  305 struct binding *_nl_domain_bindings;
  306 
  307 /* Prototypes for local functions.  */
  308 static char *plural_lookup (struct loaded_l10nfile *domain,
  309                 unsigned long int n,
  310                 const char *translation, size_t translation_len)
  311      internal_function;
  312 static 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
  319 static 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
  331 struct 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.  */
  364 typedef struct transmem_list
  365 {
  366   struct transmem_list *next;
  367   char data[ZERO];
  368 } transmem_block_t;
  369 static struct transmem_list *transmem_list;
  370 #else
  371 typedef 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
  408 static 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.  */
  426 char *
  427 DCIGETTEXT (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 
  719 char *
  720 internal_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             transmem_list = transmem_list->next;
  959           else
  960             {
  961               struct transmem_list *old = transmem_list;
  962 
  963               transmem_list = transmem_list->next;
  964               free (old);
  965             }
  966 # endif
  967         }
  968           else
  969         {
  970           malloc_count = 1;
  971           freemem_size = INITIAL_BLOCK_SIZE;
  972           newmem = (transmem_block_t *) malloc (freemem_size);
  973         }
  974           if (__builtin_expect (newmem == NULL, 0))
  975         {
  976           freemem = NULL;
  977           freemem_size = 0;
  978           __libc_lock_unlock (lock);
  979           goto converted;
  980         }
  981 
  982 # ifdef _LIBC
  983           /* Add the block to the list of blocks we have to free
  984                  at some point.  */
  985           newmem->next = transmem_list;
  986           transmem_list = newmem;
  987 
  988           freemem = newmem->data;
  989           freemem_size -= offsetof (struct transmem_list, data);
  990 # else
  991           transmem_list = newmem;
  992           freemem = newmem;
  993 # endif
  994 
  995           outbuf = freemem + sizeof (size_t);
  996         }
  997 
  998       /* We have now in our buffer a converted string.  Put this
  999          into the table of conversions.  */
 1000       *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
 1001       domain->conv_tab[act] = (char *) freemem;
 1002       /* Shrink freemem, but keep it aligned.  */
 1003       freemem_size -= outbuf - freemem;
 1004       freemem = outbuf;
 1005       freemem += freemem_size & (alignof (size_t) - 1);
 1006       freemem_size = freemem_size & ~ (alignof (size_t) - 1);
 1007 
 1008       __libc_lock_unlock (lock);
 1009     }
 1010 
 1011       /* Now domain->conv_tab[act] contains the translation of all
 1012      the plural variants.  */
 1013       result = domain->conv_tab[act] + sizeof (size_t);
 1014       resultlen = *(size_t *) domain->conv_tab[act];
 1015     }
 1016 
 1017  converted:
 1018   /* The result string is converted.  */
 1019 
 1020 #endif /* _LIBC || HAVE_ICONV */
 1021 
 1022   *lengthp = resultlen;
 1023   return result;
 1024 }
 1025 
 1026 
 1027 /* Look up a plural variant.  */
 1028 static char *
 1029 internal_function
 1030 plural_lookup (struct loaded_l10nfile *domain, unsigned long int n,
 1031            const char *translation, size_t translation_len)
 1032 {
 1033   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
 1034   unsigned long int index;
 1035   const char *p;
 1036 
 1037   index = plural_eval (domaindata->plural, n);
 1038   if (index >= domaindata->nplurals)
 1039     /* This should never happen.  It means the plural expression and the
 1040        given maximum value do not match.  */
 1041     index = 0;
 1042 
 1043   /* Skip INDEX strings at TRANSLATION.  */
 1044   p = translation;
 1045   while (index-- > 0)
 1046     {
 1047 #ifdef _LIBC
 1048       p = __rawmemchr (p, '\0');
 1049 #else
 1050       p = strchr (p, '\0');
 1051 #endif
 1052       /* And skip over the NUL byte.  */
 1053       p++;
 1054 
 1055       if (p >= translation + translation_len)
 1056     /* This should never happen.  It means the plural expression
 1057        evaluated to a value larger than the number of variants
 1058        available for MSGID1.  */
 1059     return (char *) translation;
 1060     }
 1061   return (char *) p;
 1062 }
 1063 
 1064 #ifndef _LIBC
 1065 /* Return string representation of locale CATEGORY.  */
 1066 static const char *
 1067 internal_function
 1068 category_to_name (int category)
 1069 {
 1070   const char *retval;
 1071 
 1072   switch (category)
 1073   {
 1074 #ifdef LC_COLLATE
 1075   case LC_COLLATE:
 1076     retval = "LC_COLLATE";
 1077     break;
 1078 #endif
 1079 #ifdef LC_CTYPE
 1080   case LC_CTYPE:
 1081     retval = "LC_CTYPE";
 1082     break;
 1083 #endif
 1084 #ifdef LC_MONETARY
 1085   case LC_MONETARY:
 1086     retval = "LC_MONETARY";
 1087     break;
 1088 #endif
 1089 #ifdef LC_NUMERIC
 1090   case LC_NUMERIC:
 1091     retval = "LC_NUMERIC";
 1092     break;
 1093 #endif
 1094 #ifdef LC_TIME
 1095   case LC_TIME:
 1096     retval = "LC_TIME";
 1097     break;
 1098 #endif
 1099 #ifdef LC_MESSAGES
 1100   case LC_MESSAGES:
 1101     retval = "LC_MESSAGES";
 1102     break;
 1103 #endif
 1104 #ifdef LC_RESPONSE
 1105   case LC_RESPONSE:
 1106     retval = "LC_RESPONSE";
 1107     break;
 1108 #endif
 1109 #ifdef LC_ALL
 1110   case LC_ALL:
 1111     /* This might not make sense but is perhaps better than any other
 1112        value.  */
 1113     retval = "LC_ALL";
 1114     break;
 1115 #endif
 1116   default:
 1117     /* If you have a better idea for a default value let me know.  */
 1118     retval = "LC_XXX";
 1119   }
 1120 
 1121   return retval;
 1122 }
 1123 #endif
 1124 
 1125 /* Guess value of current locale from value of the environment variables
 1126    or system-dependent defaults.  */
 1127 static const char *
 1128 internal_function
 1129 guess_category_value (int category, const char *categoryname)
 1130 {
 1131   const char *language;
 1132   const char *locale;
 1133 #ifndef _LIBC
 1134   const char *language_default;
 1135   int locale_defaulted;
 1136 #endif
 1137 
 1138   /* We use the settings in the following order:
 1139      1. The value of the environment variable 'LANGUAGE'.  This is a GNU
 1140         extension.  Its value can be a colon-separated list of locale names.
 1141      2. The value of the environment variable 'LC_ALL', 'LC_xxx', or 'LANG'.
 1142         More precisely, the first among these that is set to a non-empty value.
 1143         This is how POSIX specifies it.  The value is a single locale name.
 1144      3. A system-dependent preference list of languages.  Its value can be a
 1145         colon-separated list of locale names.
 1146      4. A system-dependent default locale name.
 1147      This way:
 1148        - System-dependent settings can be overridden by environment variables.
 1149        - If the system provides both a list of languages and a default locale,
 1150          the former is used.  */
 1151 
 1152   /* Fetch the locale name, through the POSIX method of looking to `LC_ALL',
 1153      `LC_xxx', and `LANG'.  On some systems this can be done by the
 1154      `setlocale' function itself.  */
 1155 #ifdef _LIBC
 1156   locale = __current_locale_name (category);
 1157 #else
 1158   locale = _nl_locale_name_posix (category, categoryname);
 1159   locale_defaulted = 0;
 1160   if (locale == NULL)
 1161     {
 1162       locale = _nl_locale_name_default ();
 1163       locale_defaulted = 1;
 1164     }
 1165 #endif
 1166 
 1167   /* Ignore LANGUAGE and its system-dependent analogon if the locale is set
 1168      to "C" because
 1169      1. "C" locale usually uses the ASCII encoding, and most international
 1170     messages use non-ASCII characters. These characters get displayed
 1171     as question marks (if using glibc's iconv()) or as invalid 8-bit
 1172     characters (because other iconv()s refuse to convert most non-ASCII
 1173     characters to ASCII). In any case, the output is ugly.
 1174      2. The precise output of some programs in the "C" locale is specified
 1175     by POSIX and should not depend on environment variables like
 1176     "LANGUAGE" or system-dependent information.  We allow such programs
 1177         to use gettext().  */
 1178   if (strcmp (locale, "C") == 0)
 1179     return locale;
 1180 
 1181   /* The highest priority value is the value of the 'LANGUAGE' environment
 1182      variable.  */
 1183   language = getenv ("LANGUAGE");
 1184   if (language != NULL && language[0] != '\0')
 1185     return language;
 1186 #ifndef _LIBC
 1187   /* The next priority value is the locale name, if not defaulted.  */
 1188   if (locale_defaulted)
 1189     {
 1190       /* The next priority value is the default language preferences list. */
 1191       language_default = _nl_language_preferences_default ();
 1192       if (language_default != NULL)
 1193         return language_default;
 1194     }
 1195   /* The least priority value is the locale name, if defaulted.  */
 1196 #endif
 1197   return locale;
 1198 }
 1199 
 1200 /* @@ begin of epilog @@ */
 1201 
 1202 /* We don't want libintl.a to depend on any other library.  So we
 1203    avoid the non-standard function stpcpy.  In GNU C Library this
 1204    function is available, though.  Also allow the symbol HAVE_STPCPY
 1205    to be defined.  */
 1206 #if !_LIBC && !HAVE_STPCPY
 1207 static char *
 1208 stpcpy (char *dest, const char *src)
 1209 {
 1210   while ((*dest++ = *src++) != '\0')
 1211     /* Do nothing. */ ;
 1212   return dest - 1;
 1213 }
 1214 #endif
 1215 
 1216 #if !_LIBC && !HAVE_MEMPCPY
 1217 static void *
 1218 mempcpy (void *dest, const void *src, size_t n)
 1219 {
 1220   return (void *) ((char *) memcpy (dest, src, n) + n);
 1221 }
 1222 #endif
 1223 
 1224 
 1225 #ifdef _LIBC
 1226 /* If we want to free all resources we have to do some work at
 1227    program's end.  */
 1228 libc_freeres_fn (free_mem)
 1229 {
 1230   void *old;
 1231 
 1232   while (_nl_domain_bindings != NULL)
 1233     {
 1234       struct binding *oldp = _nl_domain_bindings;
 1235       _nl_domain_bindings = _nl_domain_bindings->next;
 1236       if (oldp->dirname != INTUSE(_nl_default_dirname))
 1237     /* Yes, this is a pointer comparison.  */
 1238     free (oldp->dirname);
 1239       free (oldp->codeset);
 1240       free (oldp);
 1241     }
 1242 
 1243   if (_nl_current_default_domain != _nl_default_default_domain)
 1244     /* Yes, again a pointer comparison.  */
 1245     free ((char *) _nl_current_default_domain);
 1246 
 1247   /* Remove the search tree with the known translations.  */
 1248   __tdestroy (root, free);
 1249   root = NULL;
 1250 
 1251   while (transmem_list != NULL)
 1252     {
 1253       old = transmem_list;
 1254       transmem_list = transmem_list->next;
 1255       free (old);
 1256     }
 1257 }
 1258 #endif