Back to index

glibc  2.9
dcigettext.c
Go to the documentation of this file.
00001 /* Implementation of the internal dcigettext function.
00002    Copyright (C) 1995-2005, 2006, 2007, 2008
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
00022    This must come before <config.h> because <config.h> may include
00023    <features.h>, and once <features.h> has been included, it's too late.  */
00024 #ifndef _GNU_SOURCE
00025 # define _GNU_SOURCE 1
00026 #endif
00027 
00028 #ifdef HAVE_CONFIG_H
00029 # include <config.h>
00030 #endif
00031 
00032 #include <sys/types.h>
00033 
00034 #ifdef __GNUC__
00035 # define alloca __builtin_alloca
00036 # define HAVE_ALLOCA 1
00037 #else
00038 # if defined HAVE_ALLOCA_H || defined _LIBC
00039 #  include <alloca.h>
00040 # else
00041 #  ifdef _AIX
00042  #pragma alloca
00043 #  else
00044 #   ifndef alloca
00045 char *alloca ();
00046 #   endif
00047 #  endif
00048 # endif
00049 #endif
00050 
00051 #include <errno.h>
00052 #ifndef errno
00053 extern int errno;
00054 #endif
00055 #ifndef __set_errno
00056 # define __set_errno(val) errno = (val)
00057 #endif
00058 
00059 #include <stddef.h>
00060 #include <stdlib.h>
00061 #include <string.h>
00062 
00063 #if defined HAVE_UNISTD_H || defined _LIBC
00064 # include <unistd.h>
00065 #endif
00066 
00067 #include <locale.h>
00068 
00069 #if defined HAVE_SYS_PARAM_H || defined _LIBC
00070 # include <sys/param.h>
00071 #endif
00072 
00073 #include "gettextP.h"
00074 #include "plural-exp.h"
00075 #ifdef _LIBC
00076 # include <libintl.h>
00077 #else
00078 # include "libgnuintl.h"
00079 #endif
00080 #include "hash-string.h"
00081 
00082 /* Thread safetyness.  */
00083 #ifdef _LIBC
00084 # include <bits/libc-lock.h>
00085 #else
00086 /* Provide dummy implementation if this is outside glibc.  */
00087 # define __libc_lock_define_initialized(CLASS, NAME)
00088 # define __libc_lock_lock(NAME)
00089 # define __libc_lock_unlock(NAME)
00090 # define __libc_rwlock_define_initialized(CLASS, NAME)
00091 # define __libc_rwlock_rdlock(NAME)
00092 # define __libc_rwlock_unlock(NAME)
00093 #endif
00094 
00095 /* Alignment of types.  */
00096 #if defined __GNUC__ && __GNUC__ >= 2
00097 # define alignof(TYPE) __alignof__ (TYPE)
00098 #else
00099 # define alignof(TYPE) \
00100     ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
00101 #endif
00102 
00103 /* The internal variables in the standalone libintl.a must have different
00104    names than the internal variables in GNU libc, otherwise programs
00105    using libintl.a cannot be linked statically.  */
00106 #if !defined _LIBC
00107 # define _nl_default_default_domain libintl_nl_default_default_domain
00108 # define _nl_current_default_domain libintl_nl_current_default_domain
00109 # define _nl_default_dirname libintl_nl_default_dirname
00110 # define _nl_domain_bindings libintl_nl_domain_bindings
00111 #endif
00112 
00113 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
00114 #ifndef offsetof
00115 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
00116 #endif
00117 
00118 /* @@ end of prolog @@ */
00119 
00120 #ifdef _LIBC
00121 /* Rename the non ANSI C functions.  This is required by the standard
00122    because some ANSI C functions will require linking with this object
00123    file and the name space must not be polluted.  */
00124 # define getcwd __getcwd
00125 # ifndef stpcpy
00126 #  define stpcpy __stpcpy
00127 # endif
00128 # define tfind __tfind
00129 #else
00130 # if !defined HAVE_GETCWD
00131 char *getwd ();
00132 #  define getcwd(buf, max) getwd (buf)
00133 # else
00134 char *getcwd ();
00135 # endif
00136 # ifndef HAVE_STPCPY
00137 static char *stpcpy PARAMS ((char *dest, const char *src));
00138 # endif
00139 # ifndef HAVE_MEMPCPY
00140 static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
00141 # endif
00142 #endif
00143 
00144 /* Amount to increase buffer size by in each try.  */
00145 #define PATH_INCR 32
00146 
00147 /* The following is from pathmax.h.  */
00148 /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
00149    PATH_MAX but might cause redefinition warnings when sys/param.h is
00150    later included (as on MORE/BSD 4.3).  */
00151 #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
00152 # include <limits.h>
00153 #endif
00154 
00155 #ifndef _POSIX_PATH_MAX
00156 # define _POSIX_PATH_MAX 255
00157 #endif
00158 
00159 #if !defined PATH_MAX && defined _PC_PATH_MAX
00160 # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
00161 #endif
00162 
00163 /* Don't include sys/param.h if it already has been.  */
00164 #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
00165 # include <sys/param.h>
00166 #endif
00167 
00168 #if !defined PATH_MAX && defined MAXPATHLEN
00169 # define PATH_MAX MAXPATHLEN
00170 #endif
00171 
00172 #ifndef PATH_MAX
00173 # define PATH_MAX _POSIX_PATH_MAX
00174 #endif
00175 
00176 /* Whether to support different locales in different threads.  */
00177 #if defined _LIBC || HAVE_NL_LOCALE_NAME
00178 # define HAVE_PER_THREAD_LOCALE
00179 #endif
00180 
00181 /* This is the type used for the search tree where known translations
00182    are stored.  */
00183 struct known_translation_t
00184 {
00185   /* Domain in which to search.  */
00186   const char *domainname;
00187 
00188   /* The category.  */
00189   int category;
00190 
00191 #ifdef HAVE_PER_THREAD_LOCALE
00192   /* Name of the relevant locale category, or "" for the global locale.  */
00193   const char *localename;
00194 #endif
00195 
00196   /* State of the catalog counter at the point the string was found.  */
00197   int counter;
00198 
00199   /* Catalog where the string was found.  */
00200   struct loaded_l10nfile *domain;
00201 
00202   /* And finally the translation.  */
00203   const char *translation;
00204   size_t translation_length;
00205 
00206   /* Pointer to the string in question.  */
00207   union
00208     {
00209       char appended[ZERO];  /* used if domain != NULL */
00210       const char *ptr;      /* used if domain == NULL */
00211     }
00212   msgid;
00213 };
00214 
00215 /* Root of the search tree with known translations.  We can use this
00216    only if the system provides the `tsearch' function family.  */
00217 #if defined HAVE_TSEARCH || defined _LIBC
00218 # include <search.h>
00219 
00220 static void *root;
00221 
00222 # ifdef _LIBC
00223 #  define tsearch __tsearch
00224 # endif
00225 
00226 /* Function to compare two entries in the table of known translations.  */
00227 static int transcmp PARAMS ((const void *p1, const void *p2));
00228 static int
00229 transcmp (p1, p2)
00230      const void *p1;
00231      const void *p2;
00232 {
00233   const struct known_translation_t *s1;
00234   const struct known_translation_t *s2;
00235   int result;
00236 
00237   s1 = (const struct known_translation_t *) p1;
00238   s2 = (const struct known_translation_t *) p2;
00239 
00240   result = strcmp (s1->domain != NULL ? s1->msgid.appended : s1->msgid.ptr,
00241                  s2->domain != NULL ? s2->msgid.appended : s2->msgid.ptr);
00242   if (result == 0)
00243     {
00244       result = strcmp (s1->domainname, s2->domainname);
00245       if (result == 0)
00246        {
00247 #ifdef HAVE_PER_THREAD_LOCALE
00248          result = strcmp (s1->localename, s2->localename);
00249          if (result == 0)
00250 #endif
00251            /* We compare the category last (though this is the cheapest
00252               operation) since it is hopefully always the same (namely
00253               LC_MESSAGES).  */
00254            result = s1->category - s2->category;
00255        }
00256     }
00257 
00258   return result;
00259 }
00260 #endif
00261 
00262 /* Name of the default domain used for gettext(3) prior any call to
00263    textdomain(3).  The default value for this is "messages".  */
00264 const char _nl_default_default_domain[] attribute_hidden = "messages";
00265 
00266 /* Value used as the default domain for gettext(3).  */
00267 const char *_nl_current_default_domain attribute_hidden
00268      = _nl_default_default_domain;
00269 
00270 /* Contains the default location of the message catalogs.  */
00271 
00272 #ifdef _LIBC
00273 extern const char _nl_default_dirname[];
00274 libc_hidden_proto (_nl_default_dirname)
00275 #endif
00276 const char _nl_default_dirname[] = LOCALEDIR;
00277 #ifdef _LIBC
00278 libc_hidden_data_def (_nl_default_dirname)
00279 #endif
00280 
00281 /* List with bindings of specific domains created by bindtextdomain()
00282    calls.  */
00283 struct binding *_nl_domain_bindings;
00284 
00285 /* Prototypes for local functions.  */
00286 static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
00287                                 unsigned long int n,
00288                                 const char *translation,
00289                                 size_t translation_len))
00290      internal_function;
00291 static const char *guess_category_value PARAMS ((int category,
00292                                            const char *categoryname))
00293      internal_function;
00294 #ifdef _LIBC
00295 # include "../locale/localeinfo.h"
00296 # define category_to_name(category) \
00297   _nl_category_names.str + _nl_category_name_idxs[category]
00298 #else
00299 static const char *category_to_name PARAMS ((int category)) internal_function;
00300 #endif
00301 
00302 
00303 /* For those loosing systems which don't have `alloca' we have to add
00304    some additional code emulating it.  */
00305 #ifdef HAVE_ALLOCA
00306 /* Nothing has to be done.  */
00307 # define freea(p) /* nothing */
00308 # define ADD_BLOCK(list, address) /* nothing */
00309 # define FREE_BLOCKS(list) /* nothing */
00310 #else
00311 struct block_list
00312 {
00313   void *address;
00314   struct block_list *next;
00315 };
00316 # define ADD_BLOCK(list, addr)                                              \
00317   do {                                                               \
00318     struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
00319     /* If we cannot get a free block we cannot add the new element to       \
00320        the list.  */                                                 \
00321     if (newp != NULL) {                                                     \
00322       newp->address = (addr);                                               \
00323       newp->next = (list);                                           \
00324       (list) = newp;                                                 \
00325     }                                                                \
00326   } while (0)
00327 # define FREE_BLOCKS(list)                                           \
00328   do {                                                               \
00329     while (list != NULL) {                                           \
00330       struct block_list *old = list;                                        \
00331       list = list->next;                                             \
00332       free (old->address);                                           \
00333       free (old);                                                    \
00334     }                                                                \
00335   } while (0)
00336 # undef alloca
00337 # define alloca(size) (malloc (size))
00338 # define freea(p) free (p)
00339 #endif /* have alloca */
00340 
00341 
00342 #ifdef _LIBC
00343 /* List of blocks allocated for translations.  */
00344 typedef struct transmem_list
00345 {
00346   struct transmem_list *next;
00347   char data[ZERO];
00348 } transmem_block_t;
00349 static struct transmem_list *transmem_list;
00350 #else
00351 typedef unsigned char transmem_block_t;
00352 #endif
00353 #if defined _LIBC || HAVE_ICONV
00354 static const char *get_output_charset PARAMS ((struct binding *domainbinding))
00355      internal_function;
00356 #endif
00357 
00358 
00359 /* Names for the libintl functions are a problem.  They must not clash
00360    with existing names and they should follow ANSI C.  But this source
00361    code is also used in GNU C Library where the names have a __
00362    prefix.  So we have to make a difference here.  */
00363 #ifdef _LIBC
00364 # define DCIGETTEXT __dcigettext
00365 #else
00366 # define DCIGETTEXT libintl_dcigettext
00367 #endif
00368 
00369 /* Lock variable to protect the global data in the gettext implementation.  */
00370 #ifdef _LIBC
00371 __libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
00372 #endif
00373 
00374 /* Checking whether the binaries runs SUID must be done and glibc provides
00375    easier methods therefore we make a difference here.  */
00376 #ifdef _LIBC
00377 # define ENABLE_SECURE __libc_enable_secure
00378 # define DETERMINE_SECURE
00379 #else
00380 # ifndef HAVE_GETUID
00381 #  define getuid() 0
00382 # endif
00383 # ifndef HAVE_GETGID
00384 #  define getgid() 0
00385 # endif
00386 # ifndef HAVE_GETEUID
00387 #  define geteuid() getuid()
00388 # endif
00389 # ifndef HAVE_GETEGID
00390 #  define getegid() getgid()
00391 # endif
00392 static int enable_secure;
00393 # define ENABLE_SECURE (enable_secure == 1)
00394 # define DETERMINE_SECURE \
00395   if (enable_secure == 0)                                            \
00396     {                                                                \
00397       if (getuid () != geteuid () || getgid () != getegid ())               \
00398        enable_secure = 1;                                            \
00399       else                                                           \
00400        enable_secure = -1;                                           \
00401     }
00402 #endif
00403 
00404 /* Get the function to evaluate the plural expression.  */
00405 #include "plural-eval.c"
00406 
00407 /* Look up MSGID in the DOMAINNAME message catalog for the current
00408    CATEGORY locale and, if PLURAL is nonzero, search over string
00409    depending on the plural form determined by N.  */
00410 char *
00411 DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
00412      const char *domainname;
00413      const char *msgid1;
00414      const char *msgid2;
00415      int plural;
00416      unsigned long int n;
00417      int category;
00418 {
00419 #ifndef HAVE_ALLOCA
00420   struct block_list *block_list = NULL;
00421 #endif
00422   struct loaded_l10nfile *domain;
00423   struct binding *binding;
00424   const char *categoryname;
00425   const char *categoryvalue;
00426   char *dirname, *xdomainname;
00427   char *single_locale;
00428   char *retval;
00429   size_t retlen;
00430   int saved_errno;
00431 #if defined HAVE_TSEARCH || defined _LIBC
00432   struct known_translation_t search;
00433   struct known_translation_t **foundp = NULL;
00434 # ifdef HAVE_PER_THREAD_LOCALE
00435   const char *localename;
00436 # endif
00437 #endif
00438   size_t domainname_len;
00439 
00440   /* If no real MSGID is given return NULL.  */
00441   if (msgid1 == NULL)
00442     return NULL;
00443 
00444 #ifdef _LIBC
00445   if (category < 0 || category >= __LC_LAST || category == LC_ALL)
00446     /* Bogus.  */
00447     return (plural == 0
00448            ? (char *) msgid1
00449            /* Use the Germanic plural rule.  */
00450            : n == 1 ? (char *) msgid1 : (char *) msgid2);
00451 #endif
00452 
00453 #ifdef _LIBC
00454   __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
00455   __libc_rwlock_rdlock (__libc_setlocale_lock);
00456 #endif
00457 
00458   __libc_rwlock_rdlock (_nl_state_lock);
00459 
00460   /* If DOMAINNAME is NULL, we are interested in the default domain.  If
00461      CATEGORY is not LC_MESSAGES this might not make much sense but the
00462      definition left this undefined.  */
00463   if (domainname == NULL)
00464     domainname = _nl_current_default_domain;
00465 
00466 #if defined HAVE_TSEARCH || defined _LIBC
00467   /* Try to find the translation among those which we found at
00468      some time.  */
00469   search.domain = NULL;
00470   search.msgid.ptr = msgid1;
00471   search.domainname = domainname;
00472   search.category = category;
00473 # ifdef HAVE_PER_THREAD_LOCALE
00474 #  ifdef _LIBC
00475   localename = strdupa (__current_locale_name (category));
00476 #  endif
00477   search.localename = localename;
00478 # endif
00479 
00480   /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
00481      tsearch calls can be fatal.  */
00482   __libc_rwlock_define_initialized (static, tree_lock);
00483   __libc_rwlock_rdlock (tree_lock);
00484 
00485   foundp = (struct known_translation_t **) tfind (&search, &root, transcmp);
00486 
00487   __libc_rwlock_unlock (tree_lock);
00488 
00489   if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
00490     {
00491       /* Now deal with plural.  */
00492       if (plural)
00493        retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
00494                             (*foundp)->translation_length);
00495       else
00496        retval = (char *) (*foundp)->translation;
00497 
00498 # ifdef _LIBC
00499       __libc_rwlock_unlock (__libc_setlocale_lock);
00500 # endif
00501       __libc_rwlock_unlock (_nl_state_lock);
00502       return retval;
00503     }
00504 #endif
00505 
00506   /* Preserve the `errno' value.  */
00507   saved_errno = errno;
00508 
00509   /* See whether this is a SUID binary or not.  */
00510   DETERMINE_SECURE;
00511 
00512   /* First find matching binding.  */
00513   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
00514     {
00515       int compare = strcmp (domainname, binding->domainname);
00516       if (compare == 0)
00517        /* We found it!  */
00518        break;
00519       if (compare < 0)
00520        {
00521          /* It is not in the list.  */
00522          binding = NULL;
00523          break;
00524        }
00525     }
00526 
00527   if (binding == NULL)
00528     dirname = (char *) _nl_default_dirname;
00529   else if (binding->dirname[0] == '/')
00530     dirname = binding->dirname;
00531   else
00532     {
00533       /* We have a relative path.  Make it absolute now.  */
00534       size_t dirname_len = strlen (binding->dirname) + 1;
00535       size_t path_max;
00536       char *ret;
00537 
00538       path_max = (unsigned int) PATH_MAX;
00539       path_max += 2;        /* The getcwd docs say to do this.  */
00540 
00541       for (;;)
00542        {
00543          dirname = (char *) alloca (path_max + dirname_len);
00544          ADD_BLOCK (block_list, dirname);
00545 
00546          __set_errno (0);
00547          ret = getcwd (dirname, path_max);
00548          if (ret != NULL || errno != ERANGE)
00549            break;
00550 
00551          path_max += path_max / 2;
00552          path_max += PATH_INCR;
00553        }
00554 
00555       if (ret == NULL)
00556        {
00557          /* We cannot get the current working directory.  Don't signal an
00558             error but simply return the default string.  */
00559          FREE_BLOCKS (block_list);
00560          __libc_rwlock_unlock (__libc_setlocale_lock);
00561          __libc_rwlock_unlock (_nl_state_lock);
00562          __set_errno (saved_errno);
00563          return (plural == 0
00564                 ? (char *) msgid1
00565                 /* Use the Germanic plural rule.  */
00566                 : n == 1 ? (char *) msgid1 : (char *) msgid2);
00567        }
00568 
00569       stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
00570     }
00571 
00572   /* Now determine the symbolic name of CATEGORY and its value.  */
00573   categoryname = category_to_name (category);
00574   categoryvalue = guess_category_value (category, categoryname);
00575 
00576   domainname_len = strlen (domainname);
00577   xdomainname = (char *) alloca (strlen (categoryname)
00578                              + domainname_len + 5);
00579   ADD_BLOCK (block_list, xdomainname);
00580 
00581   stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
00582                 domainname, domainname_len),
00583          ".mo");
00584 
00585   /* Creating working area.  */
00586   single_locale = (char *) alloca (strlen (categoryvalue) + 1);
00587   ADD_BLOCK (block_list, single_locale);
00588 
00589 
00590   /* Search for the given string.  This is a loop because we perhaps
00591      got an ordered list of languages to consider for the translation.  */
00592   while (1)
00593     {
00594       /* Make CATEGORYVALUE point to the next element of the list.  */
00595       while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
00596        ++categoryvalue;
00597       if (categoryvalue[0] == '\0')
00598        {
00599          /* The whole contents of CATEGORYVALUE has been searched but
00600             no valid entry has been found.  We solve this situation
00601             by implicitly appending a "C" entry, i.e. no translation
00602             will take place.  */
00603          single_locale[0] = 'C';
00604          single_locale[1] = '\0';
00605        }
00606       else
00607        {
00608          char *cp = single_locale;
00609          while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
00610            *cp++ = *categoryvalue++;
00611          *cp = '\0';
00612 
00613          /* When this is a SUID binary we must not allow accessing files
00614             outside the dedicated directories.  */
00615          if (ENABLE_SECURE && strchr (single_locale, '/') != NULL)
00616            /* Ingore this entry.  */
00617            continue;
00618        }
00619 
00620       /* If the current locale value is C (or POSIX) we don't load a
00621         domain.  Return the MSGID.  */
00622       if (strcmp (single_locale, "C") == 0
00623          || strcmp (single_locale, "POSIX") == 0)
00624        {
00625        no_translation:
00626          FREE_BLOCKS (block_list);
00627          __libc_rwlock_unlock (__libc_setlocale_lock);
00628          __libc_rwlock_unlock (_nl_state_lock);
00629          __set_errno (saved_errno);
00630          return (plural == 0
00631                 ? (char *) msgid1
00632                 /* Use the Germanic plural rule.  */
00633                 : n == 1 ? (char *) msgid1 : (char *) msgid2);
00634        }
00635 
00636 
00637       /* Find structure describing the message catalog matching the
00638         DOMAINNAME and CATEGORY.  */
00639       domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
00640 
00641       if (domain != NULL)
00642        {
00643          retval = _nl_find_msg (domain, binding, msgid1, 1, &retlen);
00644 
00645          if (retval == NULL)
00646            {
00647              int cnt;
00648 
00649              for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
00650               {
00651                 retval = _nl_find_msg (domain->successor[cnt], binding,
00652                                     msgid1, 1, &retlen);
00653 
00654                 if (retval != NULL)
00655                   {
00656                     domain = domain->successor[cnt];
00657                     break;
00658                   }
00659               }
00660            }
00661 
00662          /* Returning -1 means that some resource problem exists
00663             (likely memory) and that the strings could not be
00664             converted.  Return the original strings.  */
00665          if (__builtin_expect (retval == (char *) -1, 0))
00666            goto no_translation;
00667 
00668          if (retval != NULL)
00669            {
00670              /* Found the translation of MSGID1 in domain DOMAIN:
00671                starting at RETVAL, RETLEN bytes.  */
00672              FREE_BLOCKS (block_list);
00673 #if defined HAVE_TSEARCH || defined _LIBC
00674              if (foundp == NULL)
00675               {
00676                 /* Create a new entry and add it to the search tree.  */
00677                 size_t msgid_len;
00678                 size_t size;
00679                 struct known_translation_t *newp;
00680 
00681                 msgid_len = strlen (msgid1) + 1;
00682                 size = offsetof (struct known_translation_t, msgid)
00683                       + msgid_len + domainname_len + 1;
00684 # ifdef HAVE_PER_THREAD_LOCALE
00685                 size += strlen (localename) + 1;
00686 # endif
00687                 newp = (struct known_translation_t *) malloc (size);
00688                 if (newp != NULL)
00689                   {
00690                     char *new_domainname;
00691 # ifdef HAVE_PER_THREAD_LOCALE
00692                     char *new_localename;
00693 # endif
00694 
00695                     new_domainname =
00696                      mempcpy (newp->msgid.appended, msgid1, msgid_len);
00697                     memcpy (new_domainname, domainname, domainname_len + 1);
00698 # ifdef HAVE_PER_THREAD_LOCALE
00699                     new_localename = new_domainname + domainname_len + 1;
00700                     strcpy (new_localename, localename);
00701 # endif
00702                     newp->domainname = new_domainname;
00703                     newp->category = category;
00704 # ifdef HAVE_PER_THREAD_LOCALE
00705                     newp->localename = new_localename;
00706 # endif
00707                     newp->counter = _nl_msg_cat_cntr;
00708                     newp->domain = domain;
00709                     newp->translation = retval;
00710                     newp->translation_length = retlen;
00711 
00712                     __libc_rwlock_wrlock (tree_lock);
00713 
00714                     /* Insert the entry in the search tree.  */
00715                     foundp = (struct known_translation_t **)
00716                      tsearch (newp, &root, transcmp);
00717 
00718                     __libc_rwlock_unlock (tree_lock);
00719 
00720                     if (foundp == NULL
00721                        || __builtin_expect (*foundp != newp, 0))
00722                      /* The insert failed.  */
00723                      free (newp);
00724                   }
00725               }
00726              else
00727               {
00728                 /* We can update the existing entry.  */
00729                 (*foundp)->counter = _nl_msg_cat_cntr;
00730                 (*foundp)->domain = domain;
00731                 (*foundp)->translation = retval;
00732                 (*foundp)->translation_length = retlen;
00733               }
00734 #endif
00735              __set_errno (saved_errno);
00736 
00737              /* Now deal with plural.  */
00738              if (plural)
00739               retval = plural_lookup (domain, n, retval, retlen);
00740 
00741              __libc_rwlock_unlock (__libc_setlocale_lock);
00742              __libc_rwlock_unlock (_nl_state_lock);
00743              return retval;
00744            }
00745        }
00746     }
00747   /* NOTREACHED */
00748 }
00749 
00750 
00751 char *
00752 internal_function
00753 _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
00754      struct loaded_l10nfile *domain_file;
00755      struct binding *domainbinding;
00756      const char *msgid;
00757      int convert;
00758      size_t *lengthp;
00759 {
00760   struct loaded_domain *domain;
00761   nls_uint32 nstrings;
00762   size_t act;
00763   char *result;
00764   size_t resultlen;
00765 
00766   if (domain_file->decided <= 0)
00767     _nl_load_domain (domain_file, domainbinding);
00768 
00769   if (domain_file->data == NULL)
00770     return NULL;
00771 
00772   domain = (struct loaded_domain *) domain_file->data;
00773 
00774   nstrings = domain->nstrings;
00775 
00776   /* Locate the MSGID and its translation.  */
00777   if (domain->hash_tab != NULL)
00778     {
00779       /* Use the hashing table.  */
00780       nls_uint32 len = strlen (msgid);
00781       nls_uint32 hash_val = __hash_string (msgid);
00782       nls_uint32 idx = hash_val % domain->hash_size;
00783       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
00784 
00785       while (1)
00786        {
00787          nls_uint32 nstr =
00788            W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
00789 
00790          if (nstr == 0)
00791            /* Hash table entry is empty.  */
00792            return NULL;
00793 
00794          nstr--;
00795 
00796          /* Compare msgid with the original string at index nstr.
00797             We compare the lengths with >=, not ==, because plural entries
00798             are represented by strings with an embedded NUL.  */
00799          if (nstr < nstrings
00800              ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
00801               && (strcmp (msgid,
00802                          domain->data + W (domain->must_swap,
00803                                          domain->orig_tab[nstr].offset))
00804                   == 0)
00805              : domain->orig_sysdep_tab[nstr - nstrings].length > len
00806               && (strcmp (msgid,
00807                          domain->orig_sysdep_tab[nstr - nstrings].pointer)
00808                   == 0))
00809            {
00810              act = nstr;
00811              goto found;
00812            }
00813 
00814          if (idx >= domain->hash_size - incr)
00815            idx -= domain->hash_size - incr;
00816          else
00817            idx += incr;
00818        }
00819       /* NOTREACHED */
00820     }
00821   else
00822     {
00823       /* Try the default method:  binary search in the sorted array of
00824         messages.  */
00825       size_t top, bottom;
00826 
00827       bottom = 0;
00828       top = nstrings;
00829       while (bottom < top)
00830        {
00831          int cmp_val;
00832 
00833          act = (bottom + top) / 2;
00834          cmp_val = strcmp (msgid, (domain->data
00835                                 + W (domain->must_swap,
00836                                     domain->orig_tab[act].offset)));
00837          if (cmp_val < 0)
00838            top = act;
00839          else if (cmp_val > 0)
00840            bottom = act + 1;
00841          else
00842            goto found;
00843        }
00844       /* No translation was found.  */
00845       return NULL;
00846     }
00847 
00848  found:
00849   /* The translation was found at index ACT.  If we have to convert the
00850      string to use a different character set, this is the time.  */
00851   if (act < nstrings)
00852     {
00853       result = (char *)
00854        (domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
00855       resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
00856     }
00857   else
00858     {
00859       result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
00860       resultlen = domain->trans_sysdep_tab[act - nstrings].length;
00861     }
00862 
00863 #if defined _LIBC || HAVE_ICONV
00864   if (convert)
00865     {
00866       /* We are supposed to do a conversion.  */
00867       const char *encoding = get_output_charset (domainbinding);
00868 
00869       /* Protect against reallocation of the table.  */
00870       __libc_rwlock_rdlock (domain->conversions_lock);
00871 
00872       /* Search whether a table with converted translations for this
00873         encoding has already been allocated.  */
00874       size_t nconversions = domain->nconversions;
00875       struct converted_domain *convd = NULL;
00876       size_t i;
00877 
00878       for (i = nconversions; i > 0; )
00879        {
00880          i--;
00881          if (strcmp (domain->conversions[i].encoding, encoding) == 0)
00882            {
00883              convd = &domain->conversions[i];
00884              break;
00885            }
00886        }
00887 
00888       __libc_rwlock_unlock (domain->conversions_lock);
00889 
00890       if (convd == NULL)
00891        {
00892          /* We have to allocate a new conversions table.  */
00893          __libc_rwlock_wrlock (domain->conversions_lock);
00894          nconversions = domain->nconversions;
00895 
00896          /* Maybe in the meantime somebody added the translation.
00897             Recheck.  */
00898          for (i = nconversions; i > 0; )
00899            {
00900              i--;
00901              if (strcmp (domain->conversions[i].encoding, encoding) == 0)
00902               {
00903                 convd = &domain->conversions[i];
00904                 goto found_convd;
00905               }
00906            }
00907 
00908          /* Allocate a table for the converted translations for this
00909             encoding.  */
00910          struct converted_domain *new_conversions =
00911            (struct converted_domain *)
00912            realloc (domain->conversions,
00913                    (nconversions + 1) * sizeof (struct converted_domain));
00914 
00915          if (__builtin_expect (new_conversions == NULL, 0))
00916            {
00917              /* Nothing we can do, no more memory.  We cannot use the
00918                translation because it might be encoded incorrectly.  */
00919            unlock_fail:
00920              __libc_rwlock_unlock (domain->conversions_lock);
00921              return (char *) -1;
00922            }
00923 
00924          domain->conversions = new_conversions;
00925 
00926          /* Copy the 'encoding' string to permanent storage.  */
00927          encoding = strdup (encoding);
00928          if (__builtin_expect (encoding == NULL, 0))
00929            /* Nothing we can do, no more memory.  We cannot use the
00930               translation because it might be encoded incorrectly.  */
00931            goto unlock_fail;
00932 
00933          convd = &new_conversions[nconversions];
00934          convd->encoding = encoding;
00935 
00936          /* Find out about the character set the file is encoded with.
00937             This can be found (in textual form) in the entry "".  If this
00938             entry does not exist or if this does not contain the 'charset='
00939             information, we will assume the charset matches the one the
00940             current locale and we don't have to perform any conversion.  */
00941 # ifdef _LIBC
00942          convd->conv = (__gconv_t) -1;
00943 # else
00944 #  if HAVE_ICONV
00945          convd->conv = (iconv_t) -1;
00946 #  endif
00947 # endif
00948          {
00949            char *nullentry;
00950            size_t nullentrylen;
00951 
00952            /* Get the header entry.  This is a recursion, but it doesn't
00953               reallocate domain->conversions because we pass convert = 0.  */
00954            nullentry =
00955              _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
00956 
00957            if (nullentry != NULL)
00958              {
00959               const char *charsetstr;
00960 
00961               charsetstr = strstr (nullentry, "charset=");
00962               if (charsetstr != NULL)
00963                 {
00964                   size_t len;
00965                   char *charset;
00966                   const char *outcharset;
00967 
00968                   charsetstr += strlen ("charset=");
00969                   len = strcspn (charsetstr, " \t\n");
00970 
00971                   charset = (char *) alloca (len + 1);
00972 # if defined _LIBC || HAVE_MEMPCPY
00973                   *((char *) mempcpy (charset, charsetstr, len)) = '\0';
00974 # else
00975                   memcpy (charset, charsetstr, len);
00976                   charset[len] = '\0';
00977 # endif
00978 
00979                   outcharset = encoding;
00980 
00981 # ifdef _LIBC
00982                   /* We always want to use transliteration.  */
00983                   outcharset = norm_add_slashes (outcharset, "TRANSLIT");
00984                   charset = norm_add_slashes (charset, "");
00985                   int r = __gconv_open (outcharset, charset, &convd->conv,
00986                                      GCONV_AVOID_NOCONV);
00987                   if (__builtin_expect (r != __GCONV_OK, 0))
00988                     {
00989                      /* If the output encoding is the same there is
00990                         nothing to do.  Otherwise do not use the
00991                         translation at all.  */
00992                      if (__builtin_expect (r != __GCONV_NULCONV, 1))
00993                        {
00994                          __libc_rwlock_unlock (domain->conversions_lock);
00995                          free ((char *) encoding);
00996                          return NULL;
00997                        }
00998 
00999                      convd->conv = (__gconv_t) -1;
01000                     }
01001 # else
01002 #  if HAVE_ICONV
01003                   /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
01004                      we want to use transliteration.  */
01005 #   if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
01006        || _LIBICONV_VERSION >= 0x0105
01007                   if (strchr (outcharset, '/') == NULL)
01008                     {
01009                      char *tmp;
01010 
01011                      len = strlen (outcharset);
01012                      tmp = (char *) alloca (len + 10 + 1);
01013                      memcpy (tmp, outcharset, len);
01014                      memcpy (tmp + len, "//TRANSLIT", 10 + 1);
01015                      outcharset = tmp;
01016 
01017                      convd->conv = iconv_open (outcharset, charset);
01018 
01019                      freea (outcharset);
01020                     }
01021                   else
01022 #   endif
01023                     convd->conv = iconv_open (outcharset, charset);
01024 #  endif
01025 # endif
01026 
01027                   freea (charset);
01028                 }
01029              }
01030          }
01031          convd->conv_tab = NULL;
01032          /* Here domain->conversions is still == new_conversions.  */
01033          domain->nconversions++;
01034 
01035        found_convd:
01036          __libc_rwlock_unlock (domain->conversions_lock);
01037        }
01038 
01039       if (
01040 # ifdef _LIBC
01041          convd->conv != (__gconv_t) -1
01042 # else
01043 #  if HAVE_ICONV
01044          convd->conv != (iconv_t) -1
01045 #  endif
01046 # endif
01047          )
01048        {
01049          __libc_lock_define_initialized (static, lock)
01050          /* We are supposed to do a conversion.  First allocate an
01051             appropriate table with the same structure as the table
01052             of translations in the file, where we can put the pointers
01053             to the converted strings in.
01054             There is a slight complication with plural entries.  They
01055             are represented by consecutive NUL terminated strings.  We
01056             handle this case by converting RESULTLEN bytes, including
01057             NULs.  */
01058 
01059          if (__builtin_expect (convd->conv_tab == NULL, 0))
01060            {
01061              __libc_lock_lock (lock);
01062              if (convd->conv_tab == NULL)
01063               {
01064                 convd->conv_tab
01065                   = calloc (nstrings + domain->n_sysdep_strings,
01066                            sizeof (char *));
01067                 if (convd->conv_tab != NULL)
01068                   goto not_translated_yet;
01069                 /* Mark that we didn't succeed allocating a table.  */
01070                 convd->conv_tab = (char **) -1;
01071               }
01072              __libc_lock_unlock (lock);
01073            }
01074 
01075          if (__builtin_expect (convd->conv_tab == (char **) -1, 0))
01076            /* Nothing we can do, no more memory.  We cannot use the
01077               translation because it might be encoded incorrectly.  */
01078            return (char *) -1;
01079 
01080          if (convd->conv_tab[act] == NULL)
01081            {
01082              __libc_lock_lock (lock);
01083            not_translated_yet:;
01084 
01085              /* We haven't used this string so far, so it is not
01086                translated yet.  Do this now.  */
01087              /* We use a bit more efficient memory handling.
01088                We allocate always larger blocks which get used over
01089                time.  This is faster than many small allocations.   */
01090 # define INITIAL_BLOCK_SIZE 4080
01091              static unsigned char *freemem;
01092              static size_t freemem_size;
01093 
01094              const unsigned char *inbuf;
01095              unsigned char *outbuf;
01096              int malloc_count;
01097 # ifndef _LIBC
01098              transmem_block_t *transmem_list = NULL;
01099 # endif
01100 
01101              inbuf = (const unsigned char *) result;
01102              outbuf = freemem + sizeof (size_t);
01103 
01104              malloc_count = 0;
01105              while (1)
01106               {
01107                 transmem_block_t *newmem;
01108 # ifdef _LIBC
01109                 size_t non_reversible;
01110                 int res;
01111 
01112                 if (freemem_size < sizeof (size_t))
01113                   goto resize_freemem;
01114 
01115                 res = __gconv (convd->conv,
01116                              &inbuf, inbuf + resultlen,
01117                              &outbuf,
01118                              outbuf + freemem_size - sizeof (size_t),
01119                              &non_reversible);
01120 
01121                 if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
01122                   break;
01123 
01124                 if (res != __GCONV_FULL_OUTPUT)
01125                   {
01126                     /* We should not use the translation at all, it
01127                       is incorrectly encoded.  */
01128                     __libc_lock_unlock (lock);
01129                     return NULL;
01130                   }
01131 
01132                 inbuf = (const unsigned char *) result;
01133 # else
01134 #  if HAVE_ICONV
01135                 const char *inptr = (const char *) inbuf;
01136                 size_t inleft = resultlen;
01137                 char *outptr = (char *) outbuf;
01138                 size_t outleft;
01139 
01140                 if (freemem_size < sizeof (size_t))
01141                   goto resize_freemem;
01142 
01143                 outleft = freemem_size - sizeof (size_t);
01144                 if (iconv (convd->conv,
01145                           (ICONV_CONST char **) &inptr, &inleft,
01146                           &outptr, &outleft)
01147                     != (size_t) (-1))
01148                   {
01149                     outbuf = (unsigned char *) outptr;
01150                     break;
01151                   }
01152                 if (errno != E2BIG)
01153                   {
01154                     __libc_lock_unlock (lock);
01155                     return NULL;
01156                   }
01157 #  endif
01158 # endif
01159 
01160               resize_freemem:
01161                 /* We must allocate a new buffer or resize the old one.  */
01162                 if (malloc_count > 0)
01163                   {
01164                     ++malloc_count;
01165                     freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
01166                     newmem = (transmem_block_t *) realloc (transmem_list,
01167                                                       freemem_size);
01168 # ifdef _LIBC
01169                     if (newmem != NULL)
01170                      transmem_list = transmem_list->next;
01171                     else
01172                      {
01173                        struct transmem_list *old = transmem_list;
01174 
01175                        transmem_list = transmem_list->next;
01176                        free (old);
01177                      }
01178 # endif
01179                   }
01180                 else
01181                   {
01182                     malloc_count = 1;
01183                     freemem_size = INITIAL_BLOCK_SIZE;
01184                     newmem = (transmem_block_t *) malloc (freemem_size);
01185                   }
01186                 if (__builtin_expect (newmem == NULL, 0))
01187                   {
01188                     freemem = NULL;
01189                     freemem_size = 0;
01190                     __libc_lock_unlock (lock);
01191                     return (char *) -1;
01192                   }
01193 
01194 # ifdef _LIBC
01195                 /* Add the block to the list of blocks we have to free
01196                    at some point.  */
01197                 newmem->next = transmem_list;
01198                 transmem_list = newmem;
01199 
01200                 freemem = (unsigned char *) newmem->data;
01201                 freemem_size -= offsetof (struct transmem_list, data);
01202 # else
01203                 transmem_list = newmem;
01204                 freemem = newmem;
01205 # endif
01206 
01207                 outbuf = freemem + sizeof (size_t);
01208               }
01209 
01210              /* We have now in our buffer a converted string.  Put this
01211                into the table of conversions.  */
01212              *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
01213              convd->conv_tab[act] = (char *) freemem;
01214              /* Shrink freemem, but keep it aligned.  */
01215              freemem_size -= outbuf - freemem;
01216              freemem = outbuf;
01217              freemem += freemem_size & (alignof (size_t) - 1);
01218              freemem_size = freemem_size & ~ (alignof (size_t) - 1);
01219 
01220              __libc_lock_unlock (lock);
01221            }
01222 
01223          /* Now convd->conv_tab[act] contains the translation of all
01224             the plural variants.  */
01225          result = convd->conv_tab[act] + sizeof (size_t);
01226          resultlen = *(size_t *) convd->conv_tab[act];
01227        }
01228     }
01229 
01230   /* The result string is converted.  */
01231 
01232 #endif /* _LIBC || HAVE_ICONV */
01233 
01234   *lengthp = resultlen;
01235   return result;
01236 }
01237 
01238 
01239 /* Look up a plural variant.  */
01240 static char *
01241 internal_function
01242 plural_lookup (domain, n, translation, translation_len)
01243      struct loaded_l10nfile *domain;
01244      unsigned long int n;
01245      const char *translation;
01246      size_t translation_len;
01247 {
01248   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
01249   unsigned long int index;
01250   const char *p;
01251 
01252   index = plural_eval (domaindata->plural, n);
01253   if (index >= domaindata->nplurals)
01254     /* This should never happen.  It means the plural expression and the
01255        given maximum value do not match.  */
01256     index = 0;
01257 
01258   /* Skip INDEX strings at TRANSLATION.  */
01259   p = translation;
01260   while (index-- > 0)
01261     {
01262 #ifdef _LIBC
01263       p = __rawmemchr (p, '\0');
01264 #else
01265       p = strchr (p, '\0');
01266 #endif
01267       /* And skip over the NUL byte.  */
01268       p++;
01269 
01270       if (p >= translation + translation_len)
01271        /* This should never happen.  It means the plural expression
01272           evaluated to a value larger than the number of variants
01273           available for MSGID1.  */
01274        return (char *) translation;
01275     }
01276   return (char *) p;
01277 }
01278 
01279 #ifndef _LIBC
01280 /* Return string representation of locale CATEGORY.  */
01281 static const char *
01282 internal_function
01283 category_to_name (category)
01284      int category;
01285 {
01286   const char *retval;
01287 
01288   switch (category)
01289   {
01290 #ifdef LC_COLLATE
01291   case LC_COLLATE:
01292     retval = "LC_COLLATE";
01293     break;
01294 #endif
01295 #ifdef LC_CTYPE
01296   case LC_CTYPE:
01297     retval = "LC_CTYPE";
01298     break;
01299 #endif
01300 #ifdef LC_MONETARY
01301   case LC_MONETARY:
01302     retval = "LC_MONETARY";
01303     break;
01304 #endif
01305 #ifdef LC_NUMERIC
01306   case LC_NUMERIC:
01307     retval = "LC_NUMERIC";
01308     break;
01309 #endif
01310 #ifdef LC_TIME
01311   case LC_TIME:
01312     retval = "LC_TIME";
01313     break;
01314 #endif
01315 #ifdef LC_MESSAGES
01316   case LC_MESSAGES:
01317     retval = "LC_MESSAGES";
01318     break;
01319 #endif
01320 #ifdef LC_RESPONSE
01321   case LC_RESPONSE:
01322     retval = "LC_RESPONSE";
01323     break;
01324 #endif
01325 #ifdef LC_ALL
01326   case LC_ALL:
01327     /* This might not make sense but is perhaps better than any other
01328        value.  */
01329     retval = "LC_ALL";
01330     break;
01331 #endif
01332   default:
01333     /* If you have a better idea for a default value let me know.  */
01334     retval = "LC_XXX";
01335   }
01336 
01337   return retval;
01338 }
01339 #endif
01340 
01341 /* Guess value of current locale from value of the environment variables.  */
01342 static const char *
01343 internal_function
01344 guess_category_value (category, categoryname)
01345      int category;
01346      const char *categoryname;
01347 {
01348   const char *language;
01349   const char *retval;
01350 
01351   /* The highest priority value is the `LANGUAGE' environment
01352      variable.  But we don't use the value if the currently selected
01353      locale is the C locale.  This is a GNU extension.  */
01354   language = getenv ("LANGUAGE");
01355   if (language != NULL && language[0] == '\0')
01356     language = NULL;
01357 
01358   /* We have to proceed with the POSIX methods of looking to `LC_ALL',
01359      `LC_xxx', and `LANG'.  On some systems this can be done by the
01360      `setlocale' function itself.  */
01361 #ifdef _LIBC
01362   retval = __current_locale_name (category);
01363 #else
01364   retval = _nl_locale_name (category, categoryname);
01365 #endif
01366 
01367   return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
01368 }
01369 
01370 #if defined _LIBC || HAVE_ICONV
01371 /* Returns the output charset.  */
01372 static const char *
01373 internal_function
01374 get_output_charset (domainbinding)
01375      struct binding *domainbinding;
01376 {
01377   /* The output charset should normally be determined by the locale.  But
01378      sometimes the locale is not used or not correctly set up, so we provide
01379      a possibility for the user to override this: the OUTPUT_CHARSET
01380      environment variable.  Moreover, the value specified through
01381      bind_textdomain_codeset overrides both.  */
01382   if (domainbinding != NULL && domainbinding->codeset != NULL)
01383     return domainbinding->codeset;
01384   else
01385     {
01386       /* For speed reasons, we look at the value of OUTPUT_CHARSET only
01387         once.  This is a user variable that is not supposed to change
01388         during a program run.  */
01389       static char *output_charset_cache;
01390       static int output_charset_cached;
01391 
01392       if (!output_charset_cached)
01393        {
01394          const char *value = getenv ("OUTPUT_CHARSET");
01395 
01396          if (value != NULL && value[0] != '\0')
01397            {
01398              size_t len = strlen (value) + 1;
01399              char *value_copy = (char *) malloc (len);
01400 
01401              if (value_copy != NULL)
01402               memcpy (value_copy, value, len);
01403              output_charset_cache = value_copy;
01404            }
01405          output_charset_cached = 1;
01406        }
01407 
01408       if (output_charset_cache != NULL)
01409        return output_charset_cache;
01410       else
01411        {
01412 # ifdef _LIBC
01413          return _NL_CURRENT (LC_CTYPE, CODESET);
01414 # else
01415 #  if HAVE_ICONV
01416          extern const char *locale_charset PARAMS ((void);
01417          return locale_charset ();
01418 #  endif
01419 # endif
01420        }
01421     }
01422 }
01423 #endif
01424 
01425 /* @@ begin of epilog @@ */
01426 
01427 /* We don't want libintl.a to depend on any other library.  So we
01428    avoid the non-standard function stpcpy.  In GNU C Library this
01429    function is available, though.  Also allow the symbol HAVE_STPCPY
01430    to be defined.  */
01431 #if !_LIBC && !HAVE_STPCPY
01432 static char *
01433 stpcpy (dest, src)
01434      char *dest;
01435      const char *src;
01436 {
01437   while ((*dest++ = *src++) != '\0')
01438     /* Do nothing. */ ;
01439   return dest - 1;
01440 }
01441 #endif
01442 
01443 #if !_LIBC && !HAVE_MEMPCPY
01444 static void *
01445 mempcpy (dest, src, n)
01446      void *dest;
01447      const void *src;
01448      size_t n;
01449 {
01450   return (void *) ((char *) memcpy (dest, src, n) + n);
01451 }
01452 #endif
01453 
01454 
01455 #ifdef _LIBC
01456 /* If we want to free all resources we have to do some work at
01457    program's end.  */
01458 libc_freeres_fn (free_mem)
01459 {
01460   void *old;
01461 
01462   while (_nl_domain_bindings != NULL)
01463     {
01464       struct binding *oldp = _nl_domain_bindings;
01465       _nl_domain_bindings = _nl_domain_bindings->next;
01466       if (oldp->dirname != _nl_default_dirname)
01467        /* Yes, this is a pointer comparison.  */
01468        free (oldp->dirname);
01469       free (oldp->codeset);
01470       free (oldp);
01471     }
01472 
01473   if (_nl_current_default_domain != _nl_default_default_domain)
01474     /* Yes, again a pointer comparison.  */
01475     free ((char *) _nl_current_default_domain);
01476 
01477   /* Remove the search tree with the known translations.  */
01478   __tdestroy (root, free);
01479   root = NULL;
01480 
01481   while (transmem_list != NULL)
01482     {
01483       old = transmem_list;
01484       transmem_list = transmem_list->next;
01485       free (old);
01486     }
01487 }
01488 #endif