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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [intl/] [dcgettext.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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