1 /* 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
transcmp(p1,p2)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
_nl_find_msg(domain_file,domainbinding,msgid,lengthp)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
plural_lookup(domain,n,translation,translation_len)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
plural_eval(pexp,n)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
category_to_name(category)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
guess_category_value(category,categoryname)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 *
stpcpy(dest,src)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 *
mempcpy(dest,src,n)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))
free_mem(void)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 */
1289