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