~ubuntu-branches/ubuntu/jaunty/groundhog/jaunty

« back to all changes in this revision

Viewing changes to intl/dcigettext.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen M Moraco
  • Date: 2004-08-20 23:12:32 UTC
  • mfrom: (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20040820231232-18s0op2f9g21ag1z
Tags: 1.4-6
Update Policy Version

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