/[zanavi_public1]/navit/intl/dcigettext.c
ZANavi

Contents of /navit/intl/dcigettext.c

Parent Directory Parent Directory | Revision Log Revision Log


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

   
Visit the ZANavi Wiki