~csurbhi/ubuntu/maverick/e2fsprogs/e2fsprogs.fix-505719

« back to all changes in this revision

Viewing changes to intl/dcgettext.c

  • Committer: Bazaar Package Importer
  • Author(s): Matt Zimmerman
  • Date: 2004-09-19 09:43:14 UTC
  • mto: (8.1.1 lenny) (1.2.3 upstream)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20040919094314-2tafd19i76fhu6ei
Tags: upstream-1.35
ImportĀ upstreamĀ versionĀ 1.35

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* Implementation of the dcgettext(3) function.
2
 
   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
 
2
   Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3
3
 
4
 
   This program is free software; you can redistribute it and/or modify
5
 
   it under the terms of the GNU General Public License as published by
6
 
   the Free Software Foundation; either version 2, or (at your option)
 
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
7
   any later version.
8
8
 
9
9
   This program is distributed in the hope that it will be useful,
10
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
   GNU General Public License for more details.
 
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
   Library General Public License for more details.
13
13
 
14
 
   You should have received a copy of the GNU General Public License
15
 
   along with this program; if not, write to the Free Software Foundation,
16
 
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
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.  */
17
18
 
18
19
#ifdef HAVE_CONFIG_H
19
20
# include <config.h>
20
21
#endif
21
22
 
22
 
#include <sys/types.h>
23
 
 
24
 
#ifdef __GNUC__
25
 
# define alloca __builtin_alloca
26
 
# define HAVE_ALLOCA 1
27
 
#else
28
 
# if defined HAVE_ALLOCA_H || defined _LIBC
29
 
#  include <alloca.h>
30
 
# else
31
 
#  ifdef _AIX
32
 
 #pragma alloca
33
 
#  else
34
 
#   ifndef alloca
35
 
char *alloca ();
36
 
#   endif
37
 
#  endif
38
 
# endif
39
 
#endif
40
 
 
41
 
#include <errno.h>
42
 
#ifndef errno
43
 
extern int errno;
44
 
#endif
45
 
#ifndef __set_errno
46
 
# define __set_errno(val) errno = (val)
47
 
#endif
48
 
 
49
 
#if defined STDC_HEADERS || defined _LIBC
50
 
# include <stdlib.h>
51
 
#else
52
 
char *getenv ();
53
 
# ifdef HAVE_MALLOC_H
54
 
#  include <malloc.h>
55
 
# else
56
 
void free ();
57
 
# endif
58
 
#endif
59
 
 
60
 
#if defined HAVE_STRING_H || defined _LIBC
61
 
# ifndef _GNU_SOURCE
62
 
#  define _GNU_SOURCE   1
63
 
# endif
64
 
# include <string.h>
65
 
#else
66
 
# include <strings.h>
67
 
#endif
68
 
#if !HAVE_STRCHR && !defined _LIBC
69
 
# ifndef strchr
70
 
#  define strchr index
71
 
# endif
72
 
#endif
73
 
 
74
 
#if defined HAVE_UNISTD_H || defined _LIBC
75
 
# include <unistd.h>
76
 
#endif
77
 
 
78
 
#include "gettext.h"
79
23
#include "gettextP.h"
80
24
#ifdef _LIBC
81
25
# include <libintl.h>
82
26
#else
83
 
# include "libgettext.h"
 
27
# include "libgnuintl.h"
84
28
#endif
85
 
#include "hash-string.h"
86
29
 
87
30
/* @@ end of prolog @@ */
88
31
 
89
 
#ifdef _LIBC
90
 
/* Rename the non ANSI C functions.  This is required by the standard
91
 
   because some ANSI C functions will require linking with this object
92
 
   file and the name space must not be polluted.  */
93
 
# define getcwd __getcwd
94
 
# ifndef stpcpy
95
 
#  define stpcpy __stpcpy
96
 
# endif
97
 
#else
98
 
# if !defined HAVE_GETCWD
99
 
char *getwd ();
100
 
#  define getcwd(buf, max) getwd (buf)
101
 
# else
102
 
char *getcwd ();
103
 
# endif
104
 
# ifndef HAVE_STPCPY
105
 
static char *stpcpy PARAMS ((char *dest, const char *src));
106
 
# endif
107
 
#endif
108
 
 
109
 
/* Amount to increase buffer size by in each try.  */
110
 
#define PATH_INCR 32
111
 
 
112
 
/* The following is from pathmax.h.  */
113
 
/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
114
 
   PATH_MAX but might cause redefinition warnings when sys/param.h is
115
 
   later included (as on MORE/BSD 4.3).  */
116
 
#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
117
 
# include <limits.h>
118
 
#endif
119
 
 
120
 
#ifndef _POSIX_PATH_MAX
121
 
# define _POSIX_PATH_MAX 255
122
 
#endif
123
 
 
124
 
#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
125
 
# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
126
 
#endif
127
 
 
128
 
/* Don't include sys/param.h if it already has been.  */
129
 
#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
130
 
# include <sys/param.h>
131
 
#endif
132
 
 
133
 
#if !defined(PATH_MAX) && defined(MAXPATHLEN)
134
 
# define PATH_MAX MAXPATHLEN
135
 
#endif
136
 
 
137
 
#ifndef PATH_MAX
138
 
# define PATH_MAX _POSIX_PATH_MAX
139
 
#endif
140
 
 
141
 
/* XPG3 defines the result of `setlocale (category, NULL)' as:
142
 
   ``Directs `setlocale()' to query `category' and return the current
143
 
     setting of `local'.''
144
 
   However it does not specify the exact format.  And even worse: POSIX
145
 
   defines this not at all.  So we can use this feature only on selected
146
 
   system (e.g. those using GNU C Library).  */
147
 
#ifdef _LIBC
148
 
# define HAVE_LOCALE_NULL
149
 
#endif
150
 
 
151
 
/* Name of the default domain used for gettext(3) prior any call to
152
 
   textdomain(3).  The default value for this is "messages".  */
153
 
const char _nl_default_default_domain[] = "messages";
154
 
 
155
 
/* Value used as the default domain for gettext(3).  */
156
 
const char *_nl_current_default_domain = _nl_default_default_domain;
157
 
 
158
 
/* Contains the default location of the message catalogs.  */
159
 
const char _nl_default_dirname[] = GNULOCALEDIR;
160
 
 
161
 
/* List with bindings of specific domains created by bindtextdomain()
162
 
   calls.  */
163
 
struct binding *_nl_domain_bindings;
164
 
 
165
 
/* Prototypes for local functions.  */
166
 
static char *find_msg PARAMS ((struct loaded_l10nfile *domain_file,
167
 
                               const char *msgid)) internal_function;
168
 
static const char *category_to_name PARAMS ((int category)) internal_function;
169
 
static const char *guess_category_value PARAMS ((int category,
170
 
                                                 const char *categoryname))
171
 
     internal_function;
172
 
 
173
 
 
174
 
/* For those loosing systems which don't have `alloca' we have to add
175
 
   some additional code emulating it.  */
176
 
#ifdef HAVE_ALLOCA
177
 
/* Nothing has to be done.  */
178
 
# define ADD_BLOCK(list, address) /* nothing */
179
 
# define FREE_BLOCKS(list) /* nothing */
180
 
#else
181
 
struct block_list
182
 
{
183
 
  void *address;
184
 
  struct block_list *next;
185
 
};
186
 
# define ADD_BLOCK(list, addr)                                                \
187
 
  do {                                                                        \
188
 
    struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
189
 
    /* If we cannot get a free block we cannot add the new element to         \
190
 
       the list.  */                                                          \
191
 
    if (newp != NULL) {                                                       \
192
 
      newp->address = (addr);                                                 \
193
 
      newp->next = (list);                                                    \
194
 
      (list) = newp;                                                          \
195
 
    }                                                                         \
196
 
  } while (0)
197
 
# define FREE_BLOCKS(list)                                                    \
198
 
  do {                                                                        \
199
 
    while (list != NULL) {                                                    \
200
 
      struct block_list *old = list;                                          \
201
 
      list = list->next;                                                      \
202
 
      free (old);                                                             \
203
 
    }                                                                         \
204
 
  } while (0)
205
 
# undef alloca
206
 
# define alloca(size) (malloc (size))
207
 
#endif  /* have alloca */
208
 
 
209
 
 
210
32
/* Names for the libintl functions are a problem.  They must not clash
211
33
   with existing names and they should follow ANSI C.  But this source
212
34
   code is also used in GNU C Library where the names have a __
213
35
   prefix.  So we have to make a difference here.  */
214
36
#ifdef _LIBC
215
37
# define DCGETTEXT __dcgettext
 
38
# define DCIGETTEXT __dcigettext
216
39
#else
217
 
# define DCGETTEXT dcgettext__
 
40
# define DCGETTEXT libintl_dcgettext
 
41
# define DCIGETTEXT libintl_dcigettext
218
42
#endif
219
43
 
220
44
/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
225
49
     const char *msgid;
226
50
     int category;
227
51
{
228
 
#ifndef HAVE_ALLOCA
229
 
  struct block_list *block_list = NULL;
230
 
#endif
231
 
  struct loaded_l10nfile *domain;
232
 
  struct binding *binding;
233
 
  const char *categoryname;
234
 
  const char *categoryvalue;
235
 
  char *dirname, *xdomainname;
236
 
  char *single_locale;
237
 
  char *retval;
238
 
  int saved_errno = errno;
239
 
 
240
 
  /* If no real MSGID is given return NULL.  */
241
 
  if (msgid == NULL)
242
 
    return NULL;
243
 
 
244
 
  /* If DOMAINNAME is NULL, we are interested in the default domain.  If
245
 
     CATEGORY is not LC_MESSAGES this might not make much sense but the
246
 
     defintion left this undefined.  */
247
 
  if (domainname == NULL)
248
 
    domainname = _nl_current_default_domain;
249
 
 
250
 
  /* First find matching binding.  */
251
 
  for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
252
 
    {
253
 
      int compare = strcmp (domainname, binding->domainname);
254
 
      if (compare == 0)
255
 
        /* We found it!  */
256
 
        break;
257
 
      if (compare < 0)
258
 
        {
259
 
          /* It is not in the list.  */
260
 
          binding = NULL;
261
 
          break;
262
 
        }
263
 
    }
264
 
 
265
 
  if (binding == NULL)
266
 
    dirname = (char *) _nl_default_dirname;
267
 
  else if (binding->dirname[0] == '/')
268
 
    dirname = binding->dirname;
269
 
  else
270
 
    {
271
 
      /* We have a relative path.  Make it absolute now.  */
272
 
      size_t dirname_len = strlen (binding->dirname) + 1;
273
 
      size_t path_max;
274
 
      char *ret;
275
 
 
276
 
      path_max = (unsigned) PATH_MAX;
277
 
      path_max += 2;            /* The getcwd docs say to do this.  */
278
 
 
279
 
      dirname = (char *) alloca (path_max + dirname_len);
280
 
      ADD_BLOCK (block_list, dirname);
281
 
 
282
 
      __set_errno (0);
283
 
      while ((ret = getcwd (dirname, path_max)) == NULL && errno == ERANGE)
284
 
        {
285
 
          path_max += PATH_INCR;
286
 
          dirname = (char *) alloca (path_max + dirname_len);
287
 
          ADD_BLOCK (block_list, dirname);
288
 
          __set_errno (0);
289
 
        }
290
 
 
291
 
      if (ret == NULL)
292
 
        {
293
 
          /* We cannot get the current working directory.  Don't signal an
294
 
             error but simply return the default string.  */
295
 
          FREE_BLOCKS (block_list);
296
 
          __set_errno (saved_errno);
297
 
          return (char *) msgid;
298
 
        }
299
 
 
300
 
      stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
301
 
    }
302
 
 
303
 
  /* Now determine the symbolic name of CATEGORY and its value.  */
304
 
  categoryname = category_to_name (category);
305
 
  categoryvalue = guess_category_value (category, categoryname);
306
 
 
307
 
  xdomainname = (char *) alloca (strlen (categoryname)
308
 
                                 + strlen (domainname) + 5);
309
 
  ADD_BLOCK (block_list, xdomainname);
310
 
 
311
 
  stpcpy (stpcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
312
 
                  domainname),
313
 
          ".mo");
314
 
 
315
 
  /* Creating working area.  */
316
 
  single_locale = (char *) alloca (strlen (categoryvalue) + 1);
317
 
  ADD_BLOCK (block_list, single_locale);
318
 
 
319
 
 
320
 
  /* Search for the given string.  This is a loop because we perhaps
321
 
     got an ordered list of languages to consider for th translation.  */
322
 
  while (1)
323
 
    {
324
 
      /* Make CATEGORYVALUE point to the next element of the list.  */
325
 
      while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
326
 
        ++categoryvalue;
327
 
      if (categoryvalue[0] == '\0')
328
 
        {
329
 
          /* The whole contents of CATEGORYVALUE has been searched but
330
 
             no valid entry has been found.  We solve this situation
331
 
             by implicitly appending a "C" entry, i.e. no translation
332
 
             will take place.  */
333
 
          single_locale[0] = 'C';
334
 
          single_locale[1] = '\0';
335
 
        }
336
 
      else
337
 
        {
338
 
          char *cp = single_locale;
339
 
          while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
340
 
            *cp++ = *categoryvalue++;
341
 
          *cp = '\0';
342
 
        }
343
 
 
344
 
      /* If the current locale value is C (or POSIX) we don't load a
345
 
         domain.  Return the MSGID.  */
346
 
      if (strcmp (single_locale, "C") == 0
347
 
          || strcmp (single_locale, "POSIX") == 0)
348
 
        {
349
 
          FREE_BLOCKS (block_list);
350
 
          __set_errno (saved_errno);
351
 
          return (char *) msgid;
352
 
        }
353
 
 
354
 
 
355
 
      /* Find structure describing the message catalog matching the
356
 
         DOMAINNAME and CATEGORY.  */
357
 
      domain = _nl_find_domain (dirname, single_locale, xdomainname);
358
 
 
359
 
      if (domain != NULL)
360
 
        {
361
 
          retval = find_msg (domain, msgid);
362
 
 
363
 
          if (retval == NULL)
364
 
            {
365
 
              int cnt;
366
 
 
367
 
              for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
368
 
                {
369
 
                  retval = find_msg (domain->successor[cnt], msgid);
370
 
 
371
 
                  if (retval != NULL)
372
 
                    break;
373
 
                }
374
 
            }
375
 
 
376
 
          if (retval != NULL)
377
 
            {
378
 
              FREE_BLOCKS (block_list);
379
 
              __set_errno (saved_errno);
380
 
              return retval;
381
 
            }
382
 
        }
383
 
    }
384
 
  /* NOTREACHED */
 
52
  return DCIGETTEXT (domainname, msgid, NULL, 0, 0, category);
385
53
}
386
54
 
387
55
#ifdef _LIBC
388
56
/* Alias for function name in GNU C Library.  */
 
57
INTDEF(__dcgettext)
389
58
weak_alias (__dcgettext, dcgettext);
390
59
#endif
391
 
 
392
 
 
393
 
static char *
394
 
internal_function
395
 
find_msg (domain_file, msgid)
396
 
     struct loaded_l10nfile *domain_file;
397
 
     const char *msgid;
398
 
{
399
 
  size_t top, act, bottom;
400
 
  struct loaded_domain *domain;
401
 
 
402
 
  if (domain_file->decided == 0)
403
 
    _nl_load_domain (domain_file);
404
 
 
405
 
  if (domain_file->data == NULL)
406
 
    return NULL;
407
 
 
408
 
  domain = (struct loaded_domain *) domain_file->data;
409
 
 
410
 
  /* Locate the MSGID and its translation.  */
411
 
  if (domain->hash_size > 2 && domain->hash_tab != NULL)
412
 
    {
413
 
      /* Use the hashing table.  */
414
 
      nls_uint32 len = strlen (msgid);
415
 
      nls_uint32 hash_val = hash_string (msgid);
416
 
      nls_uint32 idx = hash_val % domain->hash_size;
417
 
      nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
418
 
      nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
419
 
 
420
 
      if (nstr == 0)
421
 
        /* Hash table entry is empty.  */
422
 
        return NULL;
423
 
 
424
 
      if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
425
 
          && strcmp (msgid,
426
 
                     domain->data + W (domain->must_swap,
427
 
                                       domain->orig_tab[nstr - 1].offset)) == 0)
428
 
        return (char *) domain->data + W (domain->must_swap,
429
 
                                          domain->trans_tab[nstr - 1].offset);
430
 
 
431
 
      while (1)
432
 
        {
433
 
          if (idx >= domain->hash_size - incr)
434
 
            idx -= domain->hash_size - incr;
435
 
          else
436
 
            idx += incr;
437
 
 
438
 
          nstr = W (domain->must_swap, domain->hash_tab[idx]);
439
 
          if (nstr == 0)
440
 
            /* Hash table entry is empty.  */
441
 
            return NULL;
442
 
 
443
 
          if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
444
 
              && strcmp (msgid,
445
 
                         domain->data + W (domain->must_swap,
446
 
                                           domain->orig_tab[nstr - 1].offset))
447
 
                 == 0)
448
 
            return (char *) domain->data
449
 
              + W (domain->must_swap, domain->trans_tab[nstr - 1].offset);
450
 
        }
451
 
      /* NOTREACHED */
452
 
    }
453
 
 
454
 
  /* Now we try the default method:  binary search in the sorted
455
 
     array of messages.  */
456
 
  bottom = 0;
457
 
  top = domain->nstrings;
458
 
  while (bottom < top)
459
 
    {
460
 
      int cmp_val;
461
 
 
462
 
      act = (bottom + top) / 2;
463
 
      cmp_val = strcmp (msgid, domain->data
464
 
                               + W (domain->must_swap,
465
 
                                    domain->orig_tab[act].offset));
466
 
      if (cmp_val < 0)
467
 
        top = act;
468
 
      else if (cmp_val > 0)
469
 
        bottom = act + 1;
470
 
      else
471
 
        break;
472
 
    }
473
 
 
474
 
  /* If an translation is found return this.  */
475
 
  return bottom >= top ? NULL : (char *) domain->data
476
 
                                + W (domain->must_swap,
477
 
                                     domain->trans_tab[act].offset);
478
 
}
479
 
 
480
 
 
481
 
/* Return string representation of locale CATEGORY.  */
482
 
static const char *
483
 
internal_function
484
 
category_to_name (category)
485
 
     int category;
486
 
{
487
 
  const char *retval;
488
 
 
489
 
  switch (category)
490
 
  {
491
 
#ifdef LC_COLLATE
492
 
  case LC_COLLATE:
493
 
    retval = "LC_COLLATE";
494
 
    break;
495
 
#endif
496
 
#ifdef LC_CTYPE
497
 
  case LC_CTYPE:
498
 
    retval = "LC_CTYPE";
499
 
    break;
500
 
#endif
501
 
#ifdef LC_MONETARY
502
 
  case LC_MONETARY:
503
 
    retval = "LC_MONETARY";
504
 
    break;
505
 
#endif
506
 
#ifdef LC_NUMERIC
507
 
  case LC_NUMERIC:
508
 
    retval = "LC_NUMERIC";
509
 
    break;
510
 
#endif
511
 
#ifdef LC_TIME
512
 
  case LC_TIME:
513
 
    retval = "LC_TIME";
514
 
    break;
515
 
#endif
516
 
#ifdef LC_MESSAGES
517
 
  case LC_MESSAGES:
518
 
    retval = "LC_MESSAGES";
519
 
    break;
520
 
#endif
521
 
#ifdef LC_RESPONSE
522
 
  case LC_RESPONSE:
523
 
    retval = "LC_RESPONSE";
524
 
    break;
525
 
#endif
526
 
#ifdef LC_ALL
527
 
  case LC_ALL:
528
 
    /* This might not make sense but is perhaps better than any other
529
 
       value.  */
530
 
    retval = "LC_ALL";
531
 
    break;
532
 
#endif
533
 
  default:
534
 
    /* If you have a better idea for a default value let me know.  */
535
 
    retval = "LC_XXX";
536
 
  }
537
 
 
538
 
  return retval;
539
 
}
540
 
 
541
 
/* Guess value of current locale from value of the environment variables.  */
542
 
static const char *
543
 
internal_function
544
 
guess_category_value (category, categoryname)
545
 
     int category;
546
 
     const char *categoryname;
547
 
{
548
 
  const char *retval;
549
 
 
550
 
  /* The highest priority value is the `LANGUAGE' environment
551
 
     variable.  This is a GNU extension.  */
552
 
  retval = getenv ("LANGUAGE");
553
 
  if (retval != NULL && retval[0] != '\0')
554
 
    return retval;
555
 
 
556
 
  /* `LANGUAGE' is not set.  So we have to proceed with the POSIX
557
 
     methods of looking to `LC_ALL', `LC_xxx', and `LANG'.  On some
558
 
     systems this can be done by the `setlocale' function itself.  */
559
 
#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
560
 
  return setlocale (category, NULL);
561
 
#else
562
 
  /* Setting of LC_ALL overwrites all other.  */
563
 
  retval = getenv ("LC_ALL");
564
 
  if (retval != NULL && retval[0] != '\0')
565
 
    return retval;
566
 
 
567
 
  /* Next comes the name of the desired category.  */
568
 
  retval = getenv (categoryname);
569
 
  if (retval != NULL && retval[0] != '\0')
570
 
    return retval;
571
 
 
572
 
  /* Last possibility is the LANG environment variable.  */
573
 
  retval = getenv ("LANG");
574
 
  if (retval != NULL && retval[0] != '\0')
575
 
    return retval;
576
 
 
577
 
  /* We use C as the default domain.  POSIX says this is implementation
578
 
     defined.  */
579
 
  return "C";
580
 
#endif
581
 
}
582
 
 
583
 
/* @@ begin of epilog @@ */
584
 
 
585
 
/* We don't want libintl.a to depend on any other library.  So we
586
 
   avoid the non-standard function stpcpy.  In GNU C Library this
587
 
   function is available, though.  Also allow the symbol HAVE_STPCPY
588
 
   to be defined.  */
589
 
#if !_LIBC && !HAVE_STPCPY
590
 
static char *
591
 
stpcpy (dest, src)
592
 
     char *dest;
593
 
     const char *src;
594
 
{
595
 
  while ((*dest++ = *src++) != '\0')
596
 
    /* Do nothing. */ ;
597
 
  return dest - 1;
598
 
}
599
 
#endif
600
 
 
601
 
 
602
 
#ifdef _LIBC
603
 
/* If we want to free all resources we have to do some work at
604
 
   program's end.  */
605
 
static void __attribute__ ((unused))
606
 
free_mem (void)
607
 
{
608
 
  struct binding *runp;
609
 
 
610
 
  for (runp = _nl_domain_bindings; runp != NULL; runp = runp->next)
611
 
    {
612
 
      free (runp->domainname);
613
 
      if (runp->dirname != _nl_default_dirname)
614
 
        /* Yes, this is a pointer comparison.  */
615
 
        free (runp->dirname);
616
 
    }
617
 
 
618
 
  if (_nl_current_default_domain != _nl_default_default_domain)
619
 
    /* Yes, again a pointer comparison.  */
620
 
    free ((char *) _nl_current_default_domain);
621
 
}
622
 
 
623
 
text_set_element (__libc_subfreeres, free_mem);
624
 
#endif