OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [newlib-1.18.0/] [newlib/] [libc/] [sys/] [linux/] [intl/] [dcigettext.c] - Blame information for rev 207

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.