xref: /openbsd/gnu/usr.bin/gcc/gcc/intl/dcigettext.c (revision c87b03e5)
1*c87b03e5Sespie /* Implementation of the internal dcigettext function.
2*c87b03e5Sespie    Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
3*c87b03e5Sespie 
4*c87b03e5Sespie    This program is free software; you can redistribute it and/or modify it
5*c87b03e5Sespie    under the terms of the GNU Library General Public License as published
6*c87b03e5Sespie    by the Free Software Foundation; either version 2, or (at your option)
7*c87b03e5Sespie    any later version.
8*c87b03e5Sespie 
9*c87b03e5Sespie    This program is distributed in the hope that it will be useful,
10*c87b03e5Sespie    but WITHOUT ANY WARRANTY; without even the implied warranty of
11*c87b03e5Sespie    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12*c87b03e5Sespie    Library General Public License for more details.
13*c87b03e5Sespie 
14*c87b03e5Sespie    You should have received a copy of the GNU Library General Public
15*c87b03e5Sespie    License along with this program; if not, write to the Free Software
16*c87b03e5Sespie    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17*c87b03e5Sespie    USA.  */
18*c87b03e5Sespie 
19*c87b03e5Sespie /* Tell glibc's <string.h> to provide a prototype for mempcpy().
20*c87b03e5Sespie    This must come before <config.h> because <config.h> may include
21*c87b03e5Sespie    <features.h>, and once <features.h> has been included, it's too late.  */
22*c87b03e5Sespie #ifndef _GNU_SOURCE
23*c87b03e5Sespie # define _GNU_SOURCE	1
24*c87b03e5Sespie #endif
25*c87b03e5Sespie 
26*c87b03e5Sespie #ifdef HAVE_CONFIG_H
27*c87b03e5Sespie # include <config.h>
28*c87b03e5Sespie #endif
29*c87b03e5Sespie 
30*c87b03e5Sespie #include <sys/types.h>
31*c87b03e5Sespie 
32*c87b03e5Sespie #ifdef __GNUC__
33*c87b03e5Sespie # define alloca __builtin_alloca
34*c87b03e5Sespie # define HAVE_ALLOCA 1
35*c87b03e5Sespie #else
36*c87b03e5Sespie # if defined HAVE_ALLOCA_H || defined _LIBC
37*c87b03e5Sespie #  include <alloca.h>
38*c87b03e5Sespie # else
39*c87b03e5Sespie #  ifdef _AIX
40*c87b03e5Sespie  #pragma alloca
41*c87b03e5Sespie #  else
42*c87b03e5Sespie #   ifndef alloca
43*c87b03e5Sespie char *alloca ();
44*c87b03e5Sespie #   endif
45*c87b03e5Sespie #  endif
46*c87b03e5Sespie # endif
47*c87b03e5Sespie #endif
48*c87b03e5Sespie 
49*c87b03e5Sespie #include <errno.h>
50*c87b03e5Sespie #ifndef errno
51*c87b03e5Sespie extern int errno;
52*c87b03e5Sespie #endif
53*c87b03e5Sespie #ifndef __set_errno
54*c87b03e5Sespie # define __set_errno(val) errno = (val)
55*c87b03e5Sespie #endif
56*c87b03e5Sespie 
57*c87b03e5Sespie #include <stddef.h>
58*c87b03e5Sespie #include <stdlib.h>
59*c87b03e5Sespie 
60*c87b03e5Sespie #include <string.h>
61*c87b03e5Sespie #if !HAVE_STRCHR && !defined _LIBC
62*c87b03e5Sespie # ifndef strchr
63*c87b03e5Sespie #  define strchr index
64*c87b03e5Sespie # endif
65*c87b03e5Sespie #endif
66*c87b03e5Sespie 
67*c87b03e5Sespie #if defined HAVE_UNISTD_H || defined _LIBC
68*c87b03e5Sespie # include <unistd.h>
69*c87b03e5Sespie #endif
70*c87b03e5Sespie 
71*c87b03e5Sespie #include <locale.h>
72*c87b03e5Sespie 
73*c87b03e5Sespie #if defined HAVE_SYS_PARAM_H || defined _LIBC
74*c87b03e5Sespie # include <sys/param.h>
75*c87b03e5Sespie #endif
76*c87b03e5Sespie 
77*c87b03e5Sespie #include "gettextP.h"
78*c87b03e5Sespie #ifdef _LIBC
79*c87b03e5Sespie # include <libintl.h>
80*c87b03e5Sespie #else
81*c87b03e5Sespie # include "libgnuintl.h"
82*c87b03e5Sespie #endif
83*c87b03e5Sespie #include "hash-string.h"
84*c87b03e5Sespie 
85*c87b03e5Sespie /* Thread safetyness.  */
86*c87b03e5Sespie #ifdef _LIBC
87*c87b03e5Sespie # include <bits/libc-lock.h>
88*c87b03e5Sespie #else
89*c87b03e5Sespie /* Provide dummy implementation if this is outside glibc.  */
90*c87b03e5Sespie # define __libc_lock_define_initialized(CLASS, NAME)
91*c87b03e5Sespie # define __libc_lock_lock(NAME)
92*c87b03e5Sespie # define __libc_lock_unlock(NAME)
93*c87b03e5Sespie # define __libc_rwlock_define_initialized(CLASS, NAME)
94*c87b03e5Sespie # define __libc_rwlock_rdlock(NAME)
95*c87b03e5Sespie # define __libc_rwlock_unlock(NAME)
96*c87b03e5Sespie #endif
97*c87b03e5Sespie 
98*c87b03e5Sespie /* Alignment of types.  */
99*c87b03e5Sespie #if defined __GNUC__ && __GNUC__ >= 2
100*c87b03e5Sespie # define alignof(TYPE) __alignof__ (TYPE)
101*c87b03e5Sespie #else
102*c87b03e5Sespie # define alignof(TYPE) \
103*c87b03e5Sespie     ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
104*c87b03e5Sespie #endif
105*c87b03e5Sespie 
106*c87b03e5Sespie /* The internal variables in the standalone libintl.a must have different
107*c87b03e5Sespie    names than the internal variables in GNU libc, otherwise programs
108*c87b03e5Sespie    using libintl.a cannot be linked statically.  */
109*c87b03e5Sespie #if !defined _LIBC
110*c87b03e5Sespie # define _nl_default_default_domain _nl_default_default_domain__
111*c87b03e5Sespie # define _nl_current_default_domain _nl_current_default_domain__
112*c87b03e5Sespie # define _nl_default_dirname _nl_default_dirname__
113*c87b03e5Sespie # define _nl_domain_bindings _nl_domain_bindings__
114*c87b03e5Sespie #endif
115*c87b03e5Sespie 
116*c87b03e5Sespie /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
117*c87b03e5Sespie #ifndef offsetof
118*c87b03e5Sespie # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
119*c87b03e5Sespie #endif
120*c87b03e5Sespie 
121*c87b03e5Sespie /* @@ end of prolog @@ */
122*c87b03e5Sespie 
123*c87b03e5Sespie #ifdef _LIBC
124*c87b03e5Sespie /* Rename the non ANSI C functions.  This is required by the standard
125*c87b03e5Sespie    because some ANSI C functions will require linking with this object
126*c87b03e5Sespie    file and the name space must not be polluted.
127*c87b03e5Sespie    GCC LOCAL: Don't use #elif.  */
128*c87b03e5Sespie # define getcwd __getcwd
129*c87b03e5Sespie # ifndef stpcpy
130*c87b03e5Sespie #  define stpcpy __stpcpy
131*c87b03e5Sespie # endif
132*c87b03e5Sespie # define tfind __tfind
133*c87b03e5Sespie #else
134*c87b03e5Sespie # if !defined HAVE_GETCWD
135*c87b03e5Sespie char *getwd ();
136*c87b03e5Sespie #  define getcwd(buf, max) getwd (buf)
137*c87b03e5Sespie # else
138*c87b03e5Sespie #  if !defined HAVE_DECL_GETCWD
139*c87b03e5Sespie char *getcwd ();
140*c87b03e5Sespie #  endif
141*c87b03e5Sespie # endif
142*c87b03e5Sespie # ifndef HAVE_STPCPY
143*c87b03e5Sespie static char *stpcpy PARAMS ((char *dest, const char *src));
144*c87b03e5Sespie # endif
145*c87b03e5Sespie # ifndef HAVE_MEMPCPY
146*c87b03e5Sespie static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
147*c87b03e5Sespie # endif
148*c87b03e5Sespie #endif
149*c87b03e5Sespie 
150*c87b03e5Sespie /* Amount to increase buffer size by in each try.  */
151*c87b03e5Sespie #define PATH_INCR 32
152*c87b03e5Sespie 
153*c87b03e5Sespie /* The following is from pathmax.h.  */
154*c87b03e5Sespie /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
155*c87b03e5Sespie    PATH_MAX but might cause redefinition warnings when sys/param.h is
156*c87b03e5Sespie    later included (as on MORE/BSD 4.3).  */
157*c87b03e5Sespie #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
158*c87b03e5Sespie # include <limits.h>
159*c87b03e5Sespie #endif
160*c87b03e5Sespie 
161*c87b03e5Sespie #ifndef _POSIX_PATH_MAX
162*c87b03e5Sespie # define _POSIX_PATH_MAX 255
163*c87b03e5Sespie #endif
164*c87b03e5Sespie 
165*c87b03e5Sespie #if !defined PATH_MAX && defined _PC_PATH_MAX
166*c87b03e5Sespie # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
167*c87b03e5Sespie #endif
168*c87b03e5Sespie 
169*c87b03e5Sespie /* Don't include sys/param.h if it already has been.  */
170*c87b03e5Sespie #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
171*c87b03e5Sespie # include <sys/param.h>
172*c87b03e5Sespie #endif
173*c87b03e5Sespie 
174*c87b03e5Sespie #if !defined PATH_MAX && defined MAXPATHLEN
175*c87b03e5Sespie # define PATH_MAX MAXPATHLEN
176*c87b03e5Sespie #endif
177*c87b03e5Sespie 
178*c87b03e5Sespie #ifndef PATH_MAX
179*c87b03e5Sespie # define PATH_MAX _POSIX_PATH_MAX
180*c87b03e5Sespie #endif
181*c87b03e5Sespie 
182*c87b03e5Sespie /* Pathname support.
183*c87b03e5Sespie    ISSLASH(C)           tests whether C is a directory separator character.
184*c87b03e5Sespie    IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
185*c87b03e5Sespie                         it may be concatenated to a directory pathname.
186*c87b03e5Sespie    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
187*c87b03e5Sespie  */
188*c87b03e5Sespie #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
189*c87b03e5Sespie   /* Win32, OS/2, DOS */
190*c87b03e5Sespie # define ISSLASH(C) ((C) == '/' || (C) == '\\')
191*c87b03e5Sespie # define HAS_DEVICE(P) \
192*c87b03e5Sespie     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
193*c87b03e5Sespie      && (P)[1] == ':')
194*c87b03e5Sespie # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
195*c87b03e5Sespie # define IS_PATH_WITH_DIR(P) \
196*c87b03e5Sespie     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
197*c87b03e5Sespie #else
198*c87b03e5Sespie   /* Unix */
199*c87b03e5Sespie # define ISSLASH(C) ((C) == '/')
200*c87b03e5Sespie # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
201*c87b03e5Sespie # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
202*c87b03e5Sespie #endif
203*c87b03e5Sespie 
204*c87b03e5Sespie /* XPG3 defines the result of `setlocale (category, NULL)' as:
205*c87b03e5Sespie    ``Directs `setlocale()' to query `category' and return the current
206*c87b03e5Sespie      setting of `local'.''
207*c87b03e5Sespie    However it does not specify the exact format.  Neither do SUSV2 and
208*c87b03e5Sespie    ISO C 99.  So we can use this feature only on selected systems (e.g.
209*c87b03e5Sespie    those using GNU C Library).  */
210*c87b03e5Sespie #if defined _LIBC || (defined __GNU_LIBRARY__ && __GNU_LIBRARY__ >= 2)
211*c87b03e5Sespie # define HAVE_LOCALE_NULL
212*c87b03e5Sespie #endif
213*c87b03e5Sespie 
214*c87b03e5Sespie /* This is the type used for the search tree where known translations
215*c87b03e5Sespie    are stored.  */
216*c87b03e5Sespie struct known_translation_t
217*c87b03e5Sespie {
218*c87b03e5Sespie   /* Domain in which to search.  */
219*c87b03e5Sespie   char *domainname;
220*c87b03e5Sespie 
221*c87b03e5Sespie   /* The category.  */
222*c87b03e5Sespie   int category;
223*c87b03e5Sespie 
224*c87b03e5Sespie   /* State of the catalog counter at the point the string was found.  */
225*c87b03e5Sespie   int counter;
226*c87b03e5Sespie 
227*c87b03e5Sespie   /* Catalog where the string was found.  */
228*c87b03e5Sespie   struct loaded_l10nfile *domain;
229*c87b03e5Sespie 
230*c87b03e5Sespie   /* And finally the translation.  */
231*c87b03e5Sespie   const char *translation;
232*c87b03e5Sespie   size_t translation_length;
233*c87b03e5Sespie 
234*c87b03e5Sespie   /* Pointer to the string in question.  */
235*c87b03e5Sespie   char msgid[ZERO];
236*c87b03e5Sespie };
237*c87b03e5Sespie 
238*c87b03e5Sespie /* Root of the search tree with known translations.  We can use this
239*c87b03e5Sespie    only if the system provides the `tsearch' function family.  */
240*c87b03e5Sespie #if defined HAVE_TSEARCH || defined _LIBC
241*c87b03e5Sespie # include <search.h>
242*c87b03e5Sespie 
243*c87b03e5Sespie static void *root;
244*c87b03e5Sespie 
245*c87b03e5Sespie # ifdef _LIBC
246*c87b03e5Sespie #  define tsearch __tsearch
247*c87b03e5Sespie # endif
248*c87b03e5Sespie 
249*c87b03e5Sespie /* Function to compare two entries in the table of known translations.  */
250*c87b03e5Sespie static int transcmp PARAMS ((const void *p1, const void *p2));
251*c87b03e5Sespie static int
transcmp(p1,p2)252*c87b03e5Sespie transcmp (p1, p2)
253*c87b03e5Sespie      const void *p1;
254*c87b03e5Sespie      const void *p2;
255*c87b03e5Sespie {
256*c87b03e5Sespie   const struct known_translation_t *s1;
257*c87b03e5Sespie   const struct known_translation_t *s2;
258*c87b03e5Sespie   int result;
259*c87b03e5Sespie 
260*c87b03e5Sespie   s1 = (const struct known_translation_t *) p1;
261*c87b03e5Sespie   s2 = (const struct known_translation_t *) p2;
262*c87b03e5Sespie 
263*c87b03e5Sespie   result = strcmp (s1->msgid, s2->msgid);
264*c87b03e5Sespie   if (result == 0)
265*c87b03e5Sespie     {
266*c87b03e5Sespie       result = strcmp (s1->domainname, s2->domainname);
267*c87b03e5Sespie       if (result == 0)
268*c87b03e5Sespie 	/* We compare the category last (though this is the cheapest
269*c87b03e5Sespie 	   operation) since it is hopefully always the same (namely
270*c87b03e5Sespie 	   LC_MESSAGES).  */
271*c87b03e5Sespie 	result = s1->category - s2->category;
272*c87b03e5Sespie     }
273*c87b03e5Sespie 
274*c87b03e5Sespie   return result;
275*c87b03e5Sespie }
276*c87b03e5Sespie #endif
277*c87b03e5Sespie 
278*c87b03e5Sespie /* Name of the default domain used for gettext(3) prior any call to
279*c87b03e5Sespie    textdomain(3).  The default value for this is "messages".  */
280*c87b03e5Sespie const char _nl_default_default_domain[] = "messages";
281*c87b03e5Sespie 
282*c87b03e5Sespie /* Value used as the default domain for gettext(3).  */
283*c87b03e5Sespie const char *_nl_current_default_domain = _nl_default_default_domain;
284*c87b03e5Sespie 
285*c87b03e5Sespie /* Contains the default location of the message catalogs.  */
286*c87b03e5Sespie const char _nl_default_dirname[] = LOCALEDIR;
287*c87b03e5Sespie 
288*c87b03e5Sespie /* List with bindings of specific domains created by bindtextdomain()
289*c87b03e5Sespie    calls.  */
290*c87b03e5Sespie struct binding *_nl_domain_bindings;
291*c87b03e5Sespie 
292*c87b03e5Sespie /* Prototypes for local functions.  */
293*c87b03e5Sespie static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
294*c87b03e5Sespie 				    unsigned long int n,
295*c87b03e5Sespie 				    const char *translation,
296*c87b03e5Sespie 				    size_t translation_len))
297*c87b03e5Sespie      internal_function;
298*c87b03e5Sespie static unsigned long int plural_eval PARAMS ((struct expression *pexp,
299*c87b03e5Sespie 					      unsigned long int n))
300*c87b03e5Sespie      internal_function;
301*c87b03e5Sespie static const char *category_to_name PARAMS ((int category)) internal_function;
302*c87b03e5Sespie static const char *guess_category_value PARAMS ((int category,
303*c87b03e5Sespie 						 const char *categoryname))
304*c87b03e5Sespie      internal_function;
305*c87b03e5Sespie 
306*c87b03e5Sespie 
307*c87b03e5Sespie /* For those loosing systems which don't have `alloca' we have to add
308*c87b03e5Sespie    some additional code emulating it.  */
309*c87b03e5Sespie #ifdef HAVE_ALLOCA
310*c87b03e5Sespie /* Nothing has to be done.  */
311*c87b03e5Sespie # define ADD_BLOCK(list, address) /* nothing */
312*c87b03e5Sespie # define FREE_BLOCKS(list) /* nothing */
313*c87b03e5Sespie #else
314*c87b03e5Sespie struct block_list
315*c87b03e5Sespie {
316*c87b03e5Sespie   void *address;
317*c87b03e5Sespie   struct block_list *next;
318*c87b03e5Sespie };
319*c87b03e5Sespie # define ADD_BLOCK(list, addr)						      \
320*c87b03e5Sespie   do {									      \
321*c87b03e5Sespie     struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
322*c87b03e5Sespie     /* If we cannot get a free block we cannot add the new element to	      \
323*c87b03e5Sespie        the list.  */							      \
324*c87b03e5Sespie     if (newp != NULL) {							      \
325*c87b03e5Sespie       newp->address = (addr);						      \
326*c87b03e5Sespie       newp->next = (list);						      \
327*c87b03e5Sespie       (list) = newp;							      \
328*c87b03e5Sespie     }									      \
329*c87b03e5Sespie   } while (0)
330*c87b03e5Sespie # define FREE_BLOCKS(list)						      \
331*c87b03e5Sespie   do {									      \
332*c87b03e5Sespie     while (list != NULL) {						      \
333*c87b03e5Sespie       struct block_list *old = list;					      \
334*c87b03e5Sespie       list = list->next;						      \
335*c87b03e5Sespie       free (old);							      \
336*c87b03e5Sespie     }									      \
337*c87b03e5Sespie   } while (0)
338*c87b03e5Sespie # undef alloca
339*c87b03e5Sespie # define alloca(size) (malloc (size))
340*c87b03e5Sespie #endif	/* have alloca */
341*c87b03e5Sespie 
342*c87b03e5Sespie 
343*c87b03e5Sespie #ifdef _LIBC
344*c87b03e5Sespie /* List of blocks allocated for translations.  */
345*c87b03e5Sespie typedef struct transmem_list
346*c87b03e5Sespie {
347*c87b03e5Sespie   struct transmem_list *next;
348*c87b03e5Sespie   char data[ZERO];
349*c87b03e5Sespie } transmem_block_t;
350*c87b03e5Sespie static struct transmem_list *transmem_list;
351*c87b03e5Sespie #else
352*c87b03e5Sespie typedef unsigned char transmem_block_t;
353*c87b03e5Sespie #endif
354*c87b03e5Sespie 
355*c87b03e5Sespie 
356*c87b03e5Sespie /* Names for the libintl functions are a problem.  They must not clash
357*c87b03e5Sespie    with existing names and they should follow ANSI C.  But this source
358*c87b03e5Sespie    code is also used in GNU C Library where the names have a __
359*c87b03e5Sespie    prefix.  So we have to make a difference here.  */
360*c87b03e5Sespie #ifdef _LIBC
361*c87b03e5Sespie # define DCIGETTEXT __dcigettext
362*c87b03e5Sespie #else
363*c87b03e5Sespie # define DCIGETTEXT dcigettext__
364*c87b03e5Sespie #endif
365*c87b03e5Sespie 
366*c87b03e5Sespie /* Lock variable to protect the global data in the gettext implementation.  */
367*c87b03e5Sespie #ifdef _LIBC
368*c87b03e5Sespie __libc_rwlock_define_initialized (, _nl_state_lock)
369*c87b03e5Sespie #endif
370*c87b03e5Sespie 
371*c87b03e5Sespie /* Checking whether the binaries runs SUID must be done and glibc provides
372*c87b03e5Sespie    easier methods therefore we make a difference here.  */
373*c87b03e5Sespie #ifdef _LIBC
374*c87b03e5Sespie # define ENABLE_SECURE __libc_enable_secure
375*c87b03e5Sespie # define DETERMINE_SECURE
376*c87b03e5Sespie #else
377*c87b03e5Sespie # ifndef HAVE_GETUID
378*c87b03e5Sespie #  define getuid() 0
379*c87b03e5Sespie # endif
380*c87b03e5Sespie # ifndef HAVE_GETGID
381*c87b03e5Sespie #  define getgid() 0
382*c87b03e5Sespie # endif
383*c87b03e5Sespie # ifndef HAVE_GETEUID
384*c87b03e5Sespie #  define geteuid() getuid()
385*c87b03e5Sespie # endif
386*c87b03e5Sespie # ifndef HAVE_GETEGID
387*c87b03e5Sespie #  define getegid() getgid()
388*c87b03e5Sespie # endif
389*c87b03e5Sespie static int enable_secure;
390*c87b03e5Sespie # define ENABLE_SECURE (enable_secure == 1)
391*c87b03e5Sespie # define DETERMINE_SECURE \
392*c87b03e5Sespie   if (enable_secure == 0)						      \
393*c87b03e5Sespie     {									      \
394*c87b03e5Sespie       if (getuid () != geteuid () || getgid () != getegid ())		      \
395*c87b03e5Sespie 	enable_secure = 1;						      \
396*c87b03e5Sespie       else								      \
397*c87b03e5Sespie 	enable_secure = -1;						      \
398*c87b03e5Sespie     }
399*c87b03e5Sespie #endif
400*c87b03e5Sespie 
401*c87b03e5Sespie /* Look up MSGID in the DOMAINNAME message catalog for the current
402*c87b03e5Sespie    CATEGORY locale and, if PLURAL is nonzero, search over string
403*c87b03e5Sespie    depending on the plural form determined by N.  */
404*c87b03e5Sespie char *
405*c87b03e5Sespie DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
406*c87b03e5Sespie      const char *domainname;
407*c87b03e5Sespie      const char *msgid1;
408*c87b03e5Sespie      const char *msgid2;
409*c87b03e5Sespie      int plural;
410*c87b03e5Sespie      unsigned long int n;
411*c87b03e5Sespie      int category;
412*c87b03e5Sespie {
413*c87b03e5Sespie #ifndef HAVE_ALLOCA
414*c87b03e5Sespie   struct block_list *block_list = NULL;
415*c87b03e5Sespie #endif
416*c87b03e5Sespie   struct loaded_l10nfile *domain;
417*c87b03e5Sespie   struct binding *binding;
418*c87b03e5Sespie   const char *categoryname;
419*c87b03e5Sespie   const char *categoryvalue;
420*c87b03e5Sespie   char *dirname, *xdomainname;
421*c87b03e5Sespie   char *single_locale;
422*c87b03e5Sespie   char *retval;
423*c87b03e5Sespie   size_t retlen;
424*c87b03e5Sespie   int saved_errno;
425*c87b03e5Sespie #if defined HAVE_TSEARCH || defined _LIBC
426*c87b03e5Sespie   struct known_translation_t *search;
427*c87b03e5Sespie   struct known_translation_t **foundp = NULL;
428*c87b03e5Sespie   size_t msgid_len;
429*c87b03e5Sespie #endif
430*c87b03e5Sespie   size_t domainname_len;
431*c87b03e5Sespie 
432*c87b03e5Sespie   /* If no real MSGID is given return NULL.  */
433*c87b03e5Sespie   if (msgid1 == NULL)
434*c87b03e5Sespie     return NULL;
435*c87b03e5Sespie 
436*c87b03e5Sespie   __libc_rwlock_rdlock (_nl_state_lock);
437*c87b03e5Sespie 
438*c87b03e5Sespie   /* If DOMAINNAME is NULL, we are interested in the default domain.  If
439*c87b03e5Sespie      CATEGORY is not LC_MESSAGES this might not make much sense but the
440*c87b03e5Sespie      definition left this undefined.  */
441*c87b03e5Sespie   if (domainname == NULL)
442*c87b03e5Sespie     domainname = _nl_current_default_domain;
443*c87b03e5Sespie 
444*c87b03e5Sespie #if defined HAVE_TSEARCH || defined _LIBC
445*c87b03e5Sespie   msgid_len = strlen (msgid1) + 1;
446*c87b03e5Sespie 
447*c87b03e5Sespie   /* Try to find the translation among those which we found at
448*c87b03e5Sespie      some time.  */
449*c87b03e5Sespie   search = (struct known_translation_t *)
450*c87b03e5Sespie 	   alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
451*c87b03e5Sespie   memcpy (search->msgid, msgid1, msgid_len);
452*c87b03e5Sespie   search->domainname = (char *) domainname;
453*c87b03e5Sespie   search->category = category;
454*c87b03e5Sespie 
455*c87b03e5Sespie   foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
456*c87b03e5Sespie   if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
457*c87b03e5Sespie     {
458*c87b03e5Sespie       /* Now deal with plural.  */
459*c87b03e5Sespie       if (plural)
460*c87b03e5Sespie 	retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
461*c87b03e5Sespie 				(*foundp)->translation_length);
462*c87b03e5Sespie       else
463*c87b03e5Sespie 	retval = (char *) (*foundp)->translation;
464*c87b03e5Sespie 
465*c87b03e5Sespie       __libc_rwlock_unlock (_nl_state_lock);
466*c87b03e5Sespie       return retval;
467*c87b03e5Sespie     }
468*c87b03e5Sespie #endif
469*c87b03e5Sespie 
470*c87b03e5Sespie   /* Preserve the `errno' value.  */
471*c87b03e5Sespie   saved_errno = errno;
472*c87b03e5Sespie 
473*c87b03e5Sespie   /* See whether this is a SUID binary or not.  */
474*c87b03e5Sespie   DETERMINE_SECURE;
475*c87b03e5Sespie 
476*c87b03e5Sespie   /* First find matching binding.  */
477*c87b03e5Sespie   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
478*c87b03e5Sespie     {
479*c87b03e5Sespie       int compare = strcmp (domainname, binding->domainname);
480*c87b03e5Sespie       if (compare == 0)
481*c87b03e5Sespie 	/* We found it!  */
482*c87b03e5Sespie 	break;
483*c87b03e5Sespie       if (compare < 0)
484*c87b03e5Sespie 	{
485*c87b03e5Sespie 	  /* It is not in the list.  */
486*c87b03e5Sespie 	  binding = NULL;
487*c87b03e5Sespie 	  break;
488*c87b03e5Sespie 	}
489*c87b03e5Sespie     }
490*c87b03e5Sespie 
491*c87b03e5Sespie   if (binding == NULL)
492*c87b03e5Sespie     dirname = (char *) _nl_default_dirname;
493*c87b03e5Sespie   else if (IS_ABSOLUTE_PATH (binding->dirname))
494*c87b03e5Sespie     dirname = binding->dirname;
495*c87b03e5Sespie   else
496*c87b03e5Sespie     {
497*c87b03e5Sespie       /* We have a relative path.  Make it absolute now.  */
498*c87b03e5Sespie       size_t dirname_len = strlen (binding->dirname) + 1;
499*c87b03e5Sespie       size_t path_max;
500*c87b03e5Sespie       char *ret;
501*c87b03e5Sespie 
502*c87b03e5Sespie       path_max = (unsigned int) PATH_MAX;
503*c87b03e5Sespie       path_max += 2;		/* The getcwd docs say to do this.  */
504*c87b03e5Sespie 
505*c87b03e5Sespie       for (;;)
506*c87b03e5Sespie 	{
507*c87b03e5Sespie 	  dirname = (char *) alloca (path_max + dirname_len);
508*c87b03e5Sespie 	  ADD_BLOCK (block_list, dirname);
509*c87b03e5Sespie 
510*c87b03e5Sespie 	  __set_errno (0);
511*c87b03e5Sespie 	  ret = getcwd (dirname, path_max);
512*c87b03e5Sespie 	  if (ret != NULL || errno != ERANGE)
513*c87b03e5Sespie 	    break;
514*c87b03e5Sespie 
515*c87b03e5Sespie 	  path_max += path_max / 2;
516*c87b03e5Sespie 	  path_max += PATH_INCR;
517*c87b03e5Sespie 	}
518*c87b03e5Sespie 
519*c87b03e5Sespie       if (ret == NULL)
520*c87b03e5Sespie 	{
521*c87b03e5Sespie 	  /* We cannot get the current working directory.  Don't signal an
522*c87b03e5Sespie 	     error but simply return the default string.  */
523*c87b03e5Sespie 	  FREE_BLOCKS (block_list);
524*c87b03e5Sespie 	  __libc_rwlock_unlock (_nl_state_lock);
525*c87b03e5Sespie 	  __set_errno (saved_errno);
526*c87b03e5Sespie 	  return (plural == 0
527*c87b03e5Sespie 		  ? (char *) msgid1
528*c87b03e5Sespie 		  /* Use the Germanic plural rule.  */
529*c87b03e5Sespie 		  : n == 1 ? (char *) msgid1 : (char *) msgid2);
530*c87b03e5Sespie 	}
531*c87b03e5Sespie 
532*c87b03e5Sespie       stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
533*c87b03e5Sespie     }
534*c87b03e5Sespie 
535*c87b03e5Sespie   /* Now determine the symbolic name of CATEGORY and its value.  */
536*c87b03e5Sespie   categoryname = category_to_name (category);
537*c87b03e5Sespie   categoryvalue = guess_category_value (category, categoryname);
538*c87b03e5Sespie 
539*c87b03e5Sespie   domainname_len = strlen (domainname);
540*c87b03e5Sespie   xdomainname = (char *) alloca (strlen (categoryname)
541*c87b03e5Sespie 				 + domainname_len + 5);
542*c87b03e5Sespie   ADD_BLOCK (block_list, xdomainname);
543*c87b03e5Sespie 
544*c87b03e5Sespie   stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
545*c87b03e5Sespie 		  domainname, domainname_len),
546*c87b03e5Sespie 	  ".mo");
547*c87b03e5Sespie 
548*c87b03e5Sespie   /* Creating working area.  */
549*c87b03e5Sespie   single_locale = (char *) alloca (strlen (categoryvalue) + 1);
550*c87b03e5Sespie   ADD_BLOCK (block_list, single_locale);
551*c87b03e5Sespie 
552*c87b03e5Sespie 
553*c87b03e5Sespie   /* Search for the given string.  This is a loop because we perhaps
554*c87b03e5Sespie      got an ordered list of languages to consider for the translation.  */
555*c87b03e5Sespie   while (1)
556*c87b03e5Sespie     {
557*c87b03e5Sespie       /* Make CATEGORYVALUE point to the next element of the list.  */
558*c87b03e5Sespie       while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
559*c87b03e5Sespie 	++categoryvalue;
560*c87b03e5Sespie       if (categoryvalue[0] == '\0')
561*c87b03e5Sespie 	{
562*c87b03e5Sespie 	  /* The whole contents of CATEGORYVALUE has been searched but
563*c87b03e5Sespie 	     no valid entry has been found.  We solve this situation
564*c87b03e5Sespie 	     by implicitly appending a "C" entry, i.e. no translation
565*c87b03e5Sespie 	     will take place.  */
566*c87b03e5Sespie 	  single_locale[0] = 'C';
567*c87b03e5Sespie 	  single_locale[1] = '\0';
568*c87b03e5Sespie 	}
569*c87b03e5Sespie       else
570*c87b03e5Sespie 	{
571*c87b03e5Sespie 	  char *cp = single_locale;
572*c87b03e5Sespie 	  while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
573*c87b03e5Sespie 	    *cp++ = *categoryvalue++;
574*c87b03e5Sespie 	  *cp = '\0';
575*c87b03e5Sespie 
576*c87b03e5Sespie 	  /* When this is a SUID binary we must not allow accessing files
577*c87b03e5Sespie 	     outside the dedicated directories.  */
578*c87b03e5Sespie 	  if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
579*c87b03e5Sespie 	    /* Ingore this entry.  */
580*c87b03e5Sespie 	    continue;
581*c87b03e5Sespie 	}
582*c87b03e5Sespie 
583*c87b03e5Sespie       /* If the current locale value is C (or POSIX) we don't load a
584*c87b03e5Sespie 	 domain.  Return the MSGID.  */
585*c87b03e5Sespie       if (strcmp (single_locale, "C") == 0
586*c87b03e5Sespie 	  || strcmp (single_locale, "POSIX") == 0)
587*c87b03e5Sespie 	{
588*c87b03e5Sespie 	  FREE_BLOCKS (block_list);
589*c87b03e5Sespie 	  __libc_rwlock_unlock (_nl_state_lock);
590*c87b03e5Sespie 	  __set_errno (saved_errno);
591*c87b03e5Sespie 	  return (plural == 0
592*c87b03e5Sespie 		  ? (char *) msgid1
593*c87b03e5Sespie 		  /* Use the Germanic plural rule.  */
594*c87b03e5Sespie 		  : n == 1 ? (char *) msgid1 : (char *) msgid2);
595*c87b03e5Sespie 	}
596*c87b03e5Sespie 
597*c87b03e5Sespie 
598*c87b03e5Sespie       /* Find structure describing the message catalog matching the
599*c87b03e5Sespie 	 DOMAINNAME and CATEGORY.  */
600*c87b03e5Sespie       domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
601*c87b03e5Sespie 
602*c87b03e5Sespie       if (domain != NULL)
603*c87b03e5Sespie 	{
604*c87b03e5Sespie 	  retval = _nl_find_msg (domain, binding, msgid1, &retlen);
605*c87b03e5Sespie 
606*c87b03e5Sespie 	  if (retval == NULL)
607*c87b03e5Sespie 	    {
608*c87b03e5Sespie 	      int cnt;
609*c87b03e5Sespie 
610*c87b03e5Sespie 	      for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
611*c87b03e5Sespie 		{
612*c87b03e5Sespie 		  retval = _nl_find_msg (domain->successor[cnt], binding,
613*c87b03e5Sespie 					 msgid1, &retlen);
614*c87b03e5Sespie 
615*c87b03e5Sespie 		  if (retval != NULL)
616*c87b03e5Sespie 		    {
617*c87b03e5Sespie 		      domain = domain->successor[cnt];
618*c87b03e5Sespie 		      break;
619*c87b03e5Sespie 		    }
620*c87b03e5Sespie 		}
621*c87b03e5Sespie 	    }
622*c87b03e5Sespie 
623*c87b03e5Sespie 	  if (retval != NULL)
624*c87b03e5Sespie 	    {
625*c87b03e5Sespie 	      /* Found the translation of MSGID1 in domain DOMAIN:
626*c87b03e5Sespie 		 starting at RETVAL, RETLEN bytes.  */
627*c87b03e5Sespie 	      FREE_BLOCKS (block_list);
628*c87b03e5Sespie 	      __set_errno (saved_errno);
629*c87b03e5Sespie #if defined HAVE_TSEARCH || defined _LIBC
630*c87b03e5Sespie 	      if (foundp == NULL)
631*c87b03e5Sespie 		{
632*c87b03e5Sespie 		  /* Create a new entry and add it to the search tree.  */
633*c87b03e5Sespie 		  struct known_translation_t *newp;
634*c87b03e5Sespie 
635*c87b03e5Sespie 		  newp = (struct known_translation_t *)
636*c87b03e5Sespie 		    malloc (offsetof (struct known_translation_t, msgid)
637*c87b03e5Sespie 			    + msgid_len + domainname_len + 1);
638*c87b03e5Sespie 		  if (newp != NULL)
639*c87b03e5Sespie 		    {
640*c87b03e5Sespie 		      newp->domainname =
641*c87b03e5Sespie 			mempcpy (newp->msgid, msgid1, msgid_len);
642*c87b03e5Sespie 		      memcpy (newp->domainname, domainname, domainname_len + 1);
643*c87b03e5Sespie 		      newp->category = category;
644*c87b03e5Sespie 		      newp->counter = _nl_msg_cat_cntr;
645*c87b03e5Sespie 		      newp->domain = domain;
646*c87b03e5Sespie 		      newp->translation = retval;
647*c87b03e5Sespie 		      newp->translation_length = retlen;
648*c87b03e5Sespie 
649*c87b03e5Sespie 		      /* Insert the entry in the search tree.  */
650*c87b03e5Sespie 		      foundp = (struct known_translation_t **)
651*c87b03e5Sespie 			tsearch (newp, &root, transcmp);
652*c87b03e5Sespie 		      if (foundp == NULL
653*c87b03e5Sespie 			  || __builtin_expect (*foundp != newp, 0))
654*c87b03e5Sespie 			/* The insert failed.  */
655*c87b03e5Sespie 			free (newp);
656*c87b03e5Sespie 		    }
657*c87b03e5Sespie 		}
658*c87b03e5Sespie 	      else
659*c87b03e5Sespie 		{
660*c87b03e5Sespie 		  /* We can update the existing entry.  */
661*c87b03e5Sespie 		  (*foundp)->counter = _nl_msg_cat_cntr;
662*c87b03e5Sespie 		  (*foundp)->domain = domain;
663*c87b03e5Sespie 		  (*foundp)->translation = retval;
664*c87b03e5Sespie 		  (*foundp)->translation_length = retlen;
665*c87b03e5Sespie 		}
666*c87b03e5Sespie #endif
667*c87b03e5Sespie 	      /* Now deal with plural.  */
668*c87b03e5Sespie 	      if (plural)
669*c87b03e5Sespie 		retval = plural_lookup (domain, n, retval, retlen);
670*c87b03e5Sespie 
671*c87b03e5Sespie 	      __libc_rwlock_unlock (_nl_state_lock);
672*c87b03e5Sespie 	      return retval;
673*c87b03e5Sespie 	    }
674*c87b03e5Sespie 	}
675*c87b03e5Sespie     }
676*c87b03e5Sespie   /* NOTREACHED */
677*c87b03e5Sespie }
678*c87b03e5Sespie 
679*c87b03e5Sespie 
680*c87b03e5Sespie char *
681*c87b03e5Sespie internal_function
_nl_find_msg(domain_file,domainbinding,msgid,lengthp)682*c87b03e5Sespie _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
683*c87b03e5Sespie      struct loaded_l10nfile *domain_file;
684*c87b03e5Sespie      struct binding *domainbinding;
685*c87b03e5Sespie      const char *msgid;
686*c87b03e5Sespie      size_t *lengthp;
687*c87b03e5Sespie {
688*c87b03e5Sespie   struct loaded_domain *domain;
689*c87b03e5Sespie   size_t act;
690*c87b03e5Sespie   char *result;
691*c87b03e5Sespie   size_t resultlen;
692*c87b03e5Sespie 
693*c87b03e5Sespie   if (domain_file->decided == 0)
694*c87b03e5Sespie     _nl_load_domain (domain_file, domainbinding);
695*c87b03e5Sespie 
696*c87b03e5Sespie   if (domain_file->data == NULL)
697*c87b03e5Sespie     return NULL;
698*c87b03e5Sespie 
699*c87b03e5Sespie   domain = (struct loaded_domain *) domain_file->data;
700*c87b03e5Sespie 
701*c87b03e5Sespie   /* Locate the MSGID and its translation.  */
702*c87b03e5Sespie   if (domain->hash_size > 2 && domain->hash_tab != NULL)
703*c87b03e5Sespie     {
704*c87b03e5Sespie       /* Use the hashing table.  */
705*c87b03e5Sespie       nls_uint32 len = strlen (msgid);
706*c87b03e5Sespie       nls_uint32 hash_val = hash_string (msgid);
707*c87b03e5Sespie       nls_uint32 idx = hash_val % domain->hash_size;
708*c87b03e5Sespie       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
709*c87b03e5Sespie 
710*c87b03e5Sespie       while (1)
711*c87b03e5Sespie 	{
712*c87b03e5Sespie 	  nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
713*c87b03e5Sespie 
714*c87b03e5Sespie 	  if (nstr == 0)
715*c87b03e5Sespie 	    /* Hash table entry is empty.  */
716*c87b03e5Sespie 	    return NULL;
717*c87b03e5Sespie 
718*c87b03e5Sespie 	  /* Compare msgid with the original string at index nstr-1.
719*c87b03e5Sespie 	     We compare the lengths with >=, not ==, because plural entries
720*c87b03e5Sespie 	     are represented by strings with an embedded NUL.  */
721*c87b03e5Sespie 	  if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
722*c87b03e5Sespie 	      && (strcmp (msgid,
723*c87b03e5Sespie 			  domain->data + W (domain->must_swap,
724*c87b03e5Sespie 					    domain->orig_tab[nstr - 1].offset))
725*c87b03e5Sespie 		  == 0))
726*c87b03e5Sespie 	    {
727*c87b03e5Sespie 	      act = nstr - 1;
728*c87b03e5Sespie 	      goto found;
729*c87b03e5Sespie 	    }
730*c87b03e5Sespie 
731*c87b03e5Sespie 	  if (idx >= domain->hash_size - incr)
732*c87b03e5Sespie 	    idx -= domain->hash_size - incr;
733*c87b03e5Sespie 	  else
734*c87b03e5Sespie 	    idx += incr;
735*c87b03e5Sespie 	}
736*c87b03e5Sespie       /* NOTREACHED */
737*c87b03e5Sespie     }
738*c87b03e5Sespie   else
739*c87b03e5Sespie     {
740*c87b03e5Sespie       /* Try the default method:  binary search in the sorted array of
741*c87b03e5Sespie 	 messages.  */
742*c87b03e5Sespie       size_t top, bottom;
743*c87b03e5Sespie 
744*c87b03e5Sespie       bottom = 0;
745*c87b03e5Sespie       act = 0;
746*c87b03e5Sespie       top = domain->nstrings;
747*c87b03e5Sespie       while (bottom < top)
748*c87b03e5Sespie 	{
749*c87b03e5Sespie 	  int cmp_val;
750*c87b03e5Sespie 
751*c87b03e5Sespie 	  act = (bottom + top) / 2;
752*c87b03e5Sespie 	  cmp_val = strcmp (msgid, (domain->data
753*c87b03e5Sespie 				    + W (domain->must_swap,
754*c87b03e5Sespie 					 domain->orig_tab[act].offset)));
755*c87b03e5Sespie 	  if (cmp_val < 0)
756*c87b03e5Sespie 	    top = act;
757*c87b03e5Sespie 	  else if (cmp_val > 0)
758*c87b03e5Sespie 	    bottom = act + 1;
759*c87b03e5Sespie 	  else
760*c87b03e5Sespie 	    goto found;
761*c87b03e5Sespie 	}
762*c87b03e5Sespie       /* No translation was found.  */
763*c87b03e5Sespie       return NULL;
764*c87b03e5Sespie     }
765*c87b03e5Sespie 
766*c87b03e5Sespie  found:
767*c87b03e5Sespie   /* The translation was found at index ACT.  If we have to convert the
768*c87b03e5Sespie      string to use a different character set, this is the time.  */
769*c87b03e5Sespie   result = ((char *) domain->data
770*c87b03e5Sespie 	    + W (domain->must_swap, domain->trans_tab[act].offset));
771*c87b03e5Sespie   resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
772*c87b03e5Sespie 
773*c87b03e5Sespie #if defined _LIBC || HAVE_ICONV
774*c87b03e5Sespie   if (domain->codeset_cntr
775*c87b03e5Sespie       != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
776*c87b03e5Sespie     {
777*c87b03e5Sespie       /* The domain's codeset has changed through bind_textdomain_codeset()
778*c87b03e5Sespie 	 since the message catalog was initialized or last accessed.  We
779*c87b03e5Sespie 	 have to reinitialize the converter.  */
780*c87b03e5Sespie       _nl_free_domain_conv (domain);
781*c87b03e5Sespie       _nl_init_domain_conv (domain_file, domain, domainbinding);
782*c87b03e5Sespie     }
783*c87b03e5Sespie 
784*c87b03e5Sespie   if (
785*c87b03e5Sespie # ifdef _LIBC
786*c87b03e5Sespie       domain->conv != (__gconv_t) -1
787*c87b03e5Sespie # else
788*c87b03e5Sespie #  if HAVE_ICONV
789*c87b03e5Sespie       domain->conv != (iconv_t) -1
790*c87b03e5Sespie #  endif
791*c87b03e5Sespie # endif
792*c87b03e5Sespie       )
793*c87b03e5Sespie     {
794*c87b03e5Sespie       /* We are supposed to do a conversion.  First allocate an
795*c87b03e5Sespie 	 appropriate table with the same structure as the table
796*c87b03e5Sespie 	 of translations in the file, where we can put the pointers
797*c87b03e5Sespie 	 to the converted strings in.
798*c87b03e5Sespie 	 There is a slight complication with plural entries.  They
799*c87b03e5Sespie 	 are represented by consecutive NUL terminated strings.  We
800*c87b03e5Sespie 	 handle this case by converting RESULTLEN bytes, including
801*c87b03e5Sespie 	 NULs.  */
802*c87b03e5Sespie 
803*c87b03e5Sespie       if (domain->conv_tab == NULL
804*c87b03e5Sespie 	  && ((domain->conv_tab = (char **) calloc (domain->nstrings,
805*c87b03e5Sespie 						    sizeof (char *)))
806*c87b03e5Sespie 	      == NULL))
807*c87b03e5Sespie 	/* Mark that we didn't succeed allocating a table.  */
808*c87b03e5Sespie 	domain->conv_tab = (char **) -1;
809*c87b03e5Sespie 
810*c87b03e5Sespie       if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
811*c87b03e5Sespie 	/* Nothing we can do, no more memory.  */
812*c87b03e5Sespie 	goto converted;
813*c87b03e5Sespie 
814*c87b03e5Sespie       if (domain->conv_tab[act] == NULL)
815*c87b03e5Sespie 	{
816*c87b03e5Sespie 	  /* We haven't used this string so far, so it is not
817*c87b03e5Sespie 	     translated yet.  Do this now.  */
818*c87b03e5Sespie 	  /* We use a bit more efficient memory handling.
819*c87b03e5Sespie 	     We allocate always larger blocks which get used over
820*c87b03e5Sespie 	     time.  This is faster than many small allocations.   */
821*c87b03e5Sespie 	  __libc_lock_define_initialized (static, lock)
822*c87b03e5Sespie # define INITIAL_BLOCK_SIZE	4080
823*c87b03e5Sespie 	  static unsigned char *freemem;
824*c87b03e5Sespie 	  static size_t freemem_size;
825*c87b03e5Sespie 
826*c87b03e5Sespie 	  const unsigned char *inbuf;
827*c87b03e5Sespie 	  unsigned char *outbuf;
828*c87b03e5Sespie 	  int malloc_count;
829*c87b03e5Sespie # ifndef _LIBC
830*c87b03e5Sespie 	  transmem_block_t *transmem_list = NULL;
831*c87b03e5Sespie # endif
832*c87b03e5Sespie 
833*c87b03e5Sespie 	  __libc_lock_lock (lock);
834*c87b03e5Sespie 
835*c87b03e5Sespie 	  inbuf = (const unsigned char *) result;
836*c87b03e5Sespie 	  outbuf = freemem + sizeof (size_t);
837*c87b03e5Sespie 
838*c87b03e5Sespie 	  malloc_count = 0;
839*c87b03e5Sespie 	  while (1)
840*c87b03e5Sespie 	    {
841*c87b03e5Sespie 	      transmem_block_t *newmem;
842*c87b03e5Sespie # ifdef _LIBC
843*c87b03e5Sespie 	      size_t non_reversible;
844*c87b03e5Sespie 	      int res;
845*c87b03e5Sespie 
846*c87b03e5Sespie 	      if (freemem_size < sizeof (size_t))
847*c87b03e5Sespie 		goto resize_freemem;
848*c87b03e5Sespie 
849*c87b03e5Sespie 	      res = __gconv (domain->conv,
850*c87b03e5Sespie 			     &inbuf, inbuf + resultlen,
851*c87b03e5Sespie 			     &outbuf,
852*c87b03e5Sespie 			     outbuf + freemem_size - sizeof (size_t),
853*c87b03e5Sespie 			     &non_reversible);
854*c87b03e5Sespie 
855*c87b03e5Sespie 	      if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
856*c87b03e5Sespie 		break;
857*c87b03e5Sespie 
858*c87b03e5Sespie 	      if (res != __GCONV_FULL_OUTPUT)
859*c87b03e5Sespie 		{
860*c87b03e5Sespie 		  __libc_lock_unlock (lock);
861*c87b03e5Sespie 		  goto converted;
862*c87b03e5Sespie 		}
863*c87b03e5Sespie 
864*c87b03e5Sespie 	      inbuf = result;
865*c87b03e5Sespie # else
866*c87b03e5Sespie #  if HAVE_ICONV
867*c87b03e5Sespie 	      const char *inptr = (const char *) inbuf;
868*c87b03e5Sespie 	      size_t inleft = resultlen;
869*c87b03e5Sespie 	      char *outptr = (char *) outbuf;
870*c87b03e5Sespie 	      size_t outleft;
871*c87b03e5Sespie 
872*c87b03e5Sespie 	      if (freemem_size < sizeof (size_t))
873*c87b03e5Sespie 		goto resize_freemem;
874*c87b03e5Sespie 
875*c87b03e5Sespie 	      outleft = freemem_size - sizeof (size_t);
876*c87b03e5Sespie 	      if (iconv (domain->conv,
877*c87b03e5Sespie 			 (ICONV_CONST char **) &inptr, &inleft,
878*c87b03e5Sespie 			 &outptr, &outleft)
879*c87b03e5Sespie 		  != (size_t) (-1))
880*c87b03e5Sespie 		{
881*c87b03e5Sespie 		  outbuf = (unsigned char *) outptr;
882*c87b03e5Sespie 		  break;
883*c87b03e5Sespie 		}
884*c87b03e5Sespie 	      if (errno != E2BIG)
885*c87b03e5Sespie 		{
886*c87b03e5Sespie 		  __libc_lock_unlock (lock);
887*c87b03e5Sespie 		  goto converted;
888*c87b03e5Sespie 		}
889*c87b03e5Sespie #  endif
890*c87b03e5Sespie # endif
891*c87b03e5Sespie 
892*c87b03e5Sespie 	    resize_freemem:
893*c87b03e5Sespie 	      /* We must allocate a new buffer or resize the old one.  */
894*c87b03e5Sespie 	      if (malloc_count > 0)
895*c87b03e5Sespie 		{
896*c87b03e5Sespie 		  ++malloc_count;
897*c87b03e5Sespie 		  freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
898*c87b03e5Sespie 		  newmem = (transmem_block_t *) realloc (transmem_list,
899*c87b03e5Sespie 							 freemem_size);
900*c87b03e5Sespie # ifdef _LIBC
901*c87b03e5Sespie 		  if (newmem != NULL)
902*c87b03e5Sespie 		    transmem_list = transmem_list->next;
903*c87b03e5Sespie 		  else
904*c87b03e5Sespie 		    {
905*c87b03e5Sespie 		      struct transmem_list *old = transmem_list;
906*c87b03e5Sespie 
907*c87b03e5Sespie 		      transmem_list = transmem_list->next;
908*c87b03e5Sespie 		      free (old);
909*c87b03e5Sespie 		    }
910*c87b03e5Sespie # endif
911*c87b03e5Sespie 		}
912*c87b03e5Sespie 	      else
913*c87b03e5Sespie 		{
914*c87b03e5Sespie 		  malloc_count = 1;
915*c87b03e5Sespie 		  freemem_size = INITIAL_BLOCK_SIZE;
916*c87b03e5Sespie 		  newmem = (transmem_block_t *) malloc (freemem_size);
917*c87b03e5Sespie 		}
918*c87b03e5Sespie 	      if (__builtin_expect (newmem == NULL, 0))
919*c87b03e5Sespie 		{
920*c87b03e5Sespie 		  freemem = NULL;
921*c87b03e5Sespie 		  freemem_size = 0;
922*c87b03e5Sespie 		  __libc_lock_unlock (lock);
923*c87b03e5Sespie 		  goto converted;
924*c87b03e5Sespie 		}
925*c87b03e5Sespie 
926*c87b03e5Sespie # ifdef _LIBC
927*c87b03e5Sespie 	      /* Add the block to the list of blocks we have to free
928*c87b03e5Sespie                  at some point.  */
929*c87b03e5Sespie 	      newmem->next = transmem_list;
930*c87b03e5Sespie 	      transmem_list = newmem;
931*c87b03e5Sespie 
932*c87b03e5Sespie 	      freemem = newmem->data;
933*c87b03e5Sespie 	      freemem_size -= offsetof (struct transmem_list, data);
934*c87b03e5Sespie # else
935*c87b03e5Sespie 	      transmem_list = newmem;
936*c87b03e5Sespie 	      freemem = newmem;
937*c87b03e5Sespie # endif
938*c87b03e5Sespie 
939*c87b03e5Sespie 	      outbuf = freemem + sizeof (size_t);
940*c87b03e5Sespie 	    }
941*c87b03e5Sespie 
942*c87b03e5Sespie 	  /* We have now in our buffer a converted string.  Put this
943*c87b03e5Sespie 	     into the table of conversions.  */
944*c87b03e5Sespie 	  *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
945*c87b03e5Sespie 	  domain->conv_tab[act] = (char *) freemem;
946*c87b03e5Sespie 	  /* Shrink freemem, but keep it aligned.  */
947*c87b03e5Sespie 	  freemem_size -= outbuf - freemem;
948*c87b03e5Sespie 	  freemem = outbuf;
949*c87b03e5Sespie 	  freemem += freemem_size & (alignof (size_t) - 1);
950*c87b03e5Sespie 	  freemem_size = freemem_size & ~ (alignof (size_t) - 1);
951*c87b03e5Sespie 
952*c87b03e5Sespie 	  __libc_lock_unlock (lock);
953*c87b03e5Sespie 	}
954*c87b03e5Sespie 
955*c87b03e5Sespie       /* Now domain->conv_tab[act] contains the translation of all
956*c87b03e5Sespie 	 the plural variants.  */
957*c87b03e5Sespie       result = domain->conv_tab[act] + sizeof (size_t);
958*c87b03e5Sespie       resultlen = *(size_t *) domain->conv_tab[act];
959*c87b03e5Sespie     }
960*c87b03e5Sespie 
961*c87b03e5Sespie  converted:
962*c87b03e5Sespie   /* The result string is converted.  */
963*c87b03e5Sespie 
964*c87b03e5Sespie #endif /* _LIBC || HAVE_ICONV */
965*c87b03e5Sespie 
966*c87b03e5Sespie   *lengthp = resultlen;
967*c87b03e5Sespie   return result;
968*c87b03e5Sespie }
969*c87b03e5Sespie 
970*c87b03e5Sespie 
971*c87b03e5Sespie /* Look up a plural variant.  */
972*c87b03e5Sespie static char *
973*c87b03e5Sespie internal_function
plural_lookup(domain,n,translation,translation_len)974*c87b03e5Sespie plural_lookup (domain, n, translation, translation_len)
975*c87b03e5Sespie      struct loaded_l10nfile *domain;
976*c87b03e5Sespie      unsigned long int n;
977*c87b03e5Sespie      const char *translation;
978*c87b03e5Sespie      size_t translation_len;
979*c87b03e5Sespie {
980*c87b03e5Sespie   struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
981*c87b03e5Sespie   unsigned long int index;
982*c87b03e5Sespie   const char *p;
983*c87b03e5Sespie 
984*c87b03e5Sespie   index = plural_eval (domaindata->plural, n);
985*c87b03e5Sespie   if (index >= domaindata->nplurals)
986*c87b03e5Sespie     /* This should never happen.  It means the plural expression and the
987*c87b03e5Sespie        given maximum value do not match.  */
988*c87b03e5Sespie     index = 0;
989*c87b03e5Sespie 
990*c87b03e5Sespie   /* Skip INDEX strings at TRANSLATION.  */
991*c87b03e5Sespie   p = translation;
992*c87b03e5Sespie   while (index-- > 0)
993*c87b03e5Sespie     {
994*c87b03e5Sespie #ifdef _LIBC
995*c87b03e5Sespie       p = __rawmemchr (p, '\0');
996*c87b03e5Sespie #else
997*c87b03e5Sespie       p = strchr (p, '\0');
998*c87b03e5Sespie #endif
999*c87b03e5Sespie       /* And skip over the NUL byte.  */
1000*c87b03e5Sespie       p++;
1001*c87b03e5Sespie 
1002*c87b03e5Sespie       if (p >= translation + translation_len)
1003*c87b03e5Sespie 	/* This should never happen.  It means the plural expression
1004*c87b03e5Sespie 	   evaluated to a value larger than the number of variants
1005*c87b03e5Sespie 	   available for MSGID1.  */
1006*c87b03e5Sespie 	return (char *) translation;
1007*c87b03e5Sespie     }
1008*c87b03e5Sespie   return (char *) p;
1009*c87b03e5Sespie }
1010*c87b03e5Sespie 
1011*c87b03e5Sespie 
1012*c87b03e5Sespie /* Function to evaluate the plural expression and return an index value.  */
1013*c87b03e5Sespie static unsigned long int
1014*c87b03e5Sespie internal_function
plural_eval(pexp,n)1015*c87b03e5Sespie plural_eval (pexp, n)
1016*c87b03e5Sespie      struct expression *pexp;
1017*c87b03e5Sespie      unsigned long int n;
1018*c87b03e5Sespie {
1019*c87b03e5Sespie   switch (pexp->nargs)
1020*c87b03e5Sespie     {
1021*c87b03e5Sespie     case 0:
1022*c87b03e5Sespie       switch (pexp->operation)
1023*c87b03e5Sespie 	{
1024*c87b03e5Sespie 	case var:
1025*c87b03e5Sespie 	  return n;
1026*c87b03e5Sespie 	case num:
1027*c87b03e5Sespie 	  return pexp->val.num;
1028*c87b03e5Sespie 	default:
1029*c87b03e5Sespie 	  break;
1030*c87b03e5Sespie 	}
1031*c87b03e5Sespie       /* NOTREACHED */
1032*c87b03e5Sespie       break;
1033*c87b03e5Sespie     case 1:
1034*c87b03e5Sespie       {
1035*c87b03e5Sespie 	/* pexp->operation must be lnot.  */
1036*c87b03e5Sespie 	unsigned long int arg = plural_eval (pexp->val.args[0], n);
1037*c87b03e5Sespie 	return ! arg;
1038*c87b03e5Sespie       }
1039*c87b03e5Sespie     case 2:
1040*c87b03e5Sespie       {
1041*c87b03e5Sespie 	unsigned long int leftarg = plural_eval (pexp->val.args[0], n);
1042*c87b03e5Sespie 	if (pexp->operation == lor)
1043*c87b03e5Sespie 	  return leftarg || plural_eval (pexp->val.args[1], n);
1044*c87b03e5Sespie 	else if (pexp->operation == land)
1045*c87b03e5Sespie 	  return leftarg && plural_eval (pexp->val.args[1], n);
1046*c87b03e5Sespie 	else
1047*c87b03e5Sespie 	  {
1048*c87b03e5Sespie 	    unsigned long int rightarg = plural_eval (pexp->val.args[1], n);
1049*c87b03e5Sespie 
1050*c87b03e5Sespie 	    switch (pexp->operation)
1051*c87b03e5Sespie 	      {
1052*c87b03e5Sespie 	      case mult:
1053*c87b03e5Sespie 		return leftarg * rightarg;
1054*c87b03e5Sespie 	      case divide:
1055*c87b03e5Sespie 		return leftarg / rightarg;
1056*c87b03e5Sespie 	      case module:
1057*c87b03e5Sespie 		return leftarg % rightarg;
1058*c87b03e5Sespie 	      case plus:
1059*c87b03e5Sespie 		return leftarg + rightarg;
1060*c87b03e5Sespie 	      case minus:
1061*c87b03e5Sespie 		return leftarg - rightarg;
1062*c87b03e5Sespie 	      case less_than:
1063*c87b03e5Sespie 		return leftarg < rightarg;
1064*c87b03e5Sespie 	      case greater_than:
1065*c87b03e5Sespie 		return leftarg > rightarg;
1066*c87b03e5Sespie 	      case less_or_equal:
1067*c87b03e5Sespie 		return leftarg <= rightarg;
1068*c87b03e5Sespie 	      case greater_or_equal:
1069*c87b03e5Sespie 		return leftarg >= rightarg;
1070*c87b03e5Sespie 	      case equal:
1071*c87b03e5Sespie 		return leftarg == rightarg;
1072*c87b03e5Sespie 	      case not_equal:
1073*c87b03e5Sespie 		return leftarg != rightarg;
1074*c87b03e5Sespie 	      default:
1075*c87b03e5Sespie 		break;
1076*c87b03e5Sespie 	      }
1077*c87b03e5Sespie 	  }
1078*c87b03e5Sespie 	/* NOTREACHED */
1079*c87b03e5Sespie 	break;
1080*c87b03e5Sespie       }
1081*c87b03e5Sespie     case 3:
1082*c87b03e5Sespie       {
1083*c87b03e5Sespie 	/* pexp->operation must be qmop.  */
1084*c87b03e5Sespie 	unsigned long int boolarg = plural_eval (pexp->val.args[0], n);
1085*c87b03e5Sespie 	return plural_eval (pexp->val.args[boolarg ? 1 : 2], n);
1086*c87b03e5Sespie       }
1087*c87b03e5Sespie     }
1088*c87b03e5Sespie   /* NOTREACHED */
1089*c87b03e5Sespie   return 0;
1090*c87b03e5Sespie }
1091*c87b03e5Sespie 
1092*c87b03e5Sespie 
1093*c87b03e5Sespie /* Return string representation of locale CATEGORY.  */
1094*c87b03e5Sespie static const char *
1095*c87b03e5Sespie internal_function
category_to_name(category)1096*c87b03e5Sespie category_to_name (category)
1097*c87b03e5Sespie      int category;
1098*c87b03e5Sespie {
1099*c87b03e5Sespie   const char *retval;
1100*c87b03e5Sespie 
1101*c87b03e5Sespie   switch (category)
1102*c87b03e5Sespie   {
1103*c87b03e5Sespie #ifdef LC_COLLATE
1104*c87b03e5Sespie   case LC_COLLATE:
1105*c87b03e5Sespie     retval = "LC_COLLATE";
1106*c87b03e5Sespie     break;
1107*c87b03e5Sespie #endif
1108*c87b03e5Sespie #ifdef LC_CTYPE
1109*c87b03e5Sespie   case LC_CTYPE:
1110*c87b03e5Sespie     retval = "LC_CTYPE";
1111*c87b03e5Sespie     break;
1112*c87b03e5Sespie #endif
1113*c87b03e5Sespie #ifdef LC_MONETARY
1114*c87b03e5Sespie   case LC_MONETARY:
1115*c87b03e5Sespie     retval = "LC_MONETARY";
1116*c87b03e5Sespie     break;
1117*c87b03e5Sespie #endif
1118*c87b03e5Sespie #ifdef LC_NUMERIC
1119*c87b03e5Sespie   case LC_NUMERIC:
1120*c87b03e5Sespie     retval = "LC_NUMERIC";
1121*c87b03e5Sespie     break;
1122*c87b03e5Sespie #endif
1123*c87b03e5Sespie #ifdef LC_TIME
1124*c87b03e5Sespie   case LC_TIME:
1125*c87b03e5Sespie     retval = "LC_TIME";
1126*c87b03e5Sespie     break;
1127*c87b03e5Sespie #endif
1128*c87b03e5Sespie #ifdef LC_MESSAGES
1129*c87b03e5Sespie   case LC_MESSAGES:
1130*c87b03e5Sespie     retval = "LC_MESSAGES";
1131*c87b03e5Sespie     break;
1132*c87b03e5Sespie #endif
1133*c87b03e5Sespie #ifdef LC_RESPONSE
1134*c87b03e5Sespie   case LC_RESPONSE:
1135*c87b03e5Sespie     retval = "LC_RESPONSE";
1136*c87b03e5Sespie     break;
1137*c87b03e5Sespie #endif
1138*c87b03e5Sespie #ifdef LC_ALL
1139*c87b03e5Sespie   case LC_ALL:
1140*c87b03e5Sespie     /* This might not make sense but is perhaps better than any other
1141*c87b03e5Sespie        value.  */
1142*c87b03e5Sespie     retval = "LC_ALL";
1143*c87b03e5Sespie     break;
1144*c87b03e5Sespie #endif
1145*c87b03e5Sespie   default:
1146*c87b03e5Sespie     /* If you have a better idea for a default value let me know.  */
1147*c87b03e5Sespie     retval = "LC_XXX";
1148*c87b03e5Sespie   }
1149*c87b03e5Sespie 
1150*c87b03e5Sespie   return retval;
1151*c87b03e5Sespie }
1152*c87b03e5Sespie 
1153*c87b03e5Sespie /* Guess value of current locale from value of the environment variables.  */
1154*c87b03e5Sespie static const char *
1155*c87b03e5Sespie internal_function
guess_category_value(category,categoryname)1156*c87b03e5Sespie guess_category_value (category, categoryname)
1157*c87b03e5Sespie      int category;
1158*c87b03e5Sespie      const char *categoryname;
1159*c87b03e5Sespie {
1160*c87b03e5Sespie   const char *language;
1161*c87b03e5Sespie   const char *retval;
1162*c87b03e5Sespie   (void) category;  /* shut up compiler */
1163*c87b03e5Sespie   (void) categoryname;  /* ditto */
1164*c87b03e5Sespie 
1165*c87b03e5Sespie   /* The highest priority value is the `LANGUAGE' environment
1166*c87b03e5Sespie      variable.  But we don't use the value if the currently selected
1167*c87b03e5Sespie      locale is the C locale.  This is a GNU extension.  */
1168*c87b03e5Sespie   language = getenv ("LANGUAGE");
1169*c87b03e5Sespie   if (language != NULL && language[0] == '\0')
1170*c87b03e5Sespie     language = NULL;
1171*c87b03e5Sespie 
1172*c87b03e5Sespie   /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1173*c87b03e5Sespie      `LC_xxx', and `LANG'.  On some systems this can be done by the
1174*c87b03e5Sespie      `setlocale' function itself.  */
1175*c87b03e5Sespie #if defined _LIBC || (defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL)
1176*c87b03e5Sespie   retval = setlocale (category, NULL);
1177*c87b03e5Sespie #else
1178*c87b03e5Sespie   /* Setting of LC_ALL overwrites all other.  */
1179*c87b03e5Sespie   retval = getenv ("LC_ALL");
1180*c87b03e5Sespie   if (retval == NULL || retval[0] == '\0')
1181*c87b03e5Sespie     {
1182*c87b03e5Sespie       /* Next comes the name of the desired category.  */
1183*c87b03e5Sespie       retval = getenv (categoryname);
1184*c87b03e5Sespie       if (retval == NULL || retval[0] == '\0')
1185*c87b03e5Sespie 	{
1186*c87b03e5Sespie 	  /* Last possibility is the LANG environment variable.  */
1187*c87b03e5Sespie 	  retval = getenv ("LANG");
1188*c87b03e5Sespie 	  if (retval == NULL || retval[0] == '\0')
1189*c87b03e5Sespie 	    /* We use C as the default domain.  POSIX says this is
1190*c87b03e5Sespie 	       implementation defined.  */
1191*c87b03e5Sespie 	    return "C";
1192*c87b03e5Sespie 	}
1193*c87b03e5Sespie     }
1194*c87b03e5Sespie #endif
1195*c87b03e5Sespie 
1196*c87b03e5Sespie   return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1197*c87b03e5Sespie }
1198*c87b03e5Sespie 
1199*c87b03e5Sespie /* @@ begin of epilog @@ */
1200*c87b03e5Sespie 
1201*c87b03e5Sespie /* We don't want libintl.a to depend on any other library.  So we
1202*c87b03e5Sespie    avoid the non-standard function stpcpy.  In GNU C Library this
1203*c87b03e5Sespie    function is available, though.  Also allow the symbol HAVE_STPCPY
1204*c87b03e5Sespie    to be defined.  */
1205*c87b03e5Sespie #if !_LIBC && !HAVE_STPCPY
1206*c87b03e5Sespie static char *
stpcpy(dest,src)1207*c87b03e5Sespie stpcpy (dest, src)
1208*c87b03e5Sespie      char *dest;
1209*c87b03e5Sespie      const char *src;
1210*c87b03e5Sespie {
1211*c87b03e5Sespie   while ((*dest++ = *src++) != '\0')
1212*c87b03e5Sespie     /* Do nothing. */ ;
1213*c87b03e5Sespie   return dest - 1;
1214*c87b03e5Sespie }
1215*c87b03e5Sespie #endif
1216*c87b03e5Sespie 
1217*c87b03e5Sespie #if !_LIBC && !HAVE_MEMPCPY
1218*c87b03e5Sespie static void *
mempcpy(dest,src,n)1219*c87b03e5Sespie mempcpy (dest, src, n)
1220*c87b03e5Sespie      void *dest;
1221*c87b03e5Sespie      const void *src;
1222*c87b03e5Sespie      size_t n;
1223*c87b03e5Sespie {
1224*c87b03e5Sespie   return (void *) ((char *) memcpy (dest, src, n) + n);
1225*c87b03e5Sespie }
1226*c87b03e5Sespie #endif
1227*c87b03e5Sespie 
1228*c87b03e5Sespie 
1229*c87b03e5Sespie #ifdef _LIBC
1230*c87b03e5Sespie /* If we want to free all resources we have to do some work at
1231*c87b03e5Sespie    program's end.  */
1232*c87b03e5Sespie static void __attribute__ ((unused))
free_mem(void)1233*c87b03e5Sespie free_mem (void)
1234*c87b03e5Sespie {
1235*c87b03e5Sespie   void *old;
1236*c87b03e5Sespie 
1237*c87b03e5Sespie   while (_nl_domain_bindings != NULL)
1238*c87b03e5Sespie     {
1239*c87b03e5Sespie       struct binding *oldp = _nl_domain_bindings;
1240*c87b03e5Sespie       _nl_domain_bindings = _nl_domain_bindings->next;
1241*c87b03e5Sespie       if (oldp->dirname != _nl_default_dirname)
1242*c87b03e5Sespie 	/* Yes, this is a pointer comparison.  */
1243*c87b03e5Sespie 	free (oldp->dirname);
1244*c87b03e5Sespie       free (oldp->codeset);
1245*c87b03e5Sespie       free (oldp);
1246*c87b03e5Sespie     }
1247*c87b03e5Sespie 
1248*c87b03e5Sespie   if (_nl_current_default_domain != _nl_default_default_domain)
1249*c87b03e5Sespie     /* Yes, again a pointer comparison.  */
1250*c87b03e5Sespie     free ((char *) _nl_current_default_domain);
1251*c87b03e5Sespie 
1252*c87b03e5Sespie   /* Remove the search tree with the known translations.  */
1253*c87b03e5Sespie   __tdestroy (root, free);
1254*c87b03e5Sespie   root = NULL;
1255*c87b03e5Sespie 
1256*c87b03e5Sespie   while (transmem_list != NULL)
1257*c87b03e5Sespie     {
1258*c87b03e5Sespie       old = transmem_list;
1259*c87b03e5Sespie       transmem_list = transmem_list->next;
1260*c87b03e5Sespie       free (old);
1261*c87b03e5Sespie     }
1262*c87b03e5Sespie }
1263*c87b03e5Sespie 
1264*c87b03e5Sespie text_set_element (__libc_subfreeres, free_mem);
1265*c87b03e5Sespie #endif
1266