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