~ubuntu-branches/ubuntu/natty/hello-debhelper/natty

« back to all changes in this revision

Viewing changes to intl/dcigettext.c

  • Committer: Bazaar Package Importer
  • Author(s): Santiago Vila
  • Date: 2006-12-09 17:00:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209170014-817qbpd8jsc3g5xh
Tags: 2.2-1
* New upstream release.
* Repackaged source taken from hello package.
* Removed prerm and postinst, as info files are missing now.

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