~ubuntu-branches/ubuntu/breezy/gettext/breezy

« back to all changes in this revision

Viewing changes to intl/dcigettext.c

  • Committer: Bazaar Package Importer
  • Author(s): Santiago Vila
  • Date: 2002-04-10 13:17:42 UTC
  • Revision ID: james.westby@ubuntu.com-20020410131742-npf89tsaygdolprj
Tags: upstream-0.10.40
ImportĀ upstreamĀ versionĀ 0.10.40

Show diffs side-by-side

added added

removed removed

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