00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef _GNU_SOURCE
00023 # define _GNU_SOURCE 1
00024 #endif
00025
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029
00030 #include <sys/types.h>
00031
00032 #ifdef __GNUC__
00033 # define alloca __builtin_alloca
00034 # define HAVE_ALLOCA 1
00035 #else
00036 # if defined HAVE_ALLOCA_H || defined _LIBC
00037 # include <alloca.h>
00038 # else
00039 # ifdef _AIX
00040 #pragma alloca
00041 # else
00042 # ifndef alloca
00043 char *alloca ();
00044 # endif
00045 # endif
00046 # endif
00047 #endif
00048
00049 #include <errno.h>
00050 #ifndef errno
00051 extern int errno;
00052 #endif
00053 #ifndef __set_errno
00054 # define __set_errno(val) errno = (val)
00055 #endif
00056
00057 #include <stddef.h>
00058 #include <stdlib.h>
00059
00060 #include <string.h>
00061 #if !HAVE_STRCHR && !defined _LIBC
00062 # ifndef strchr
00063 # define strchr index
00064 # endif
00065 #endif
00066
00067 #if defined HAVE_UNISTD_H || defined _LIBC
00068 # include <unistd.h>
00069 #endif
00070
00071 #include <locale.h>
00072
00073 #if defined HAVE_SYS_PARAM_H || defined _LIBC
00074 # include <sys/param.h>
00075 #endif
00076
00077 #include "gettextP.h"
00078 #ifdef _LIBC
00079 # include <libintl.h>
00080 #else
00081 # include "libgnuintl.h"
00082 #endif
00083 #include "hash-string.h"
00084
00085
00086 #ifdef _LIBC
00087 # include <bits/libc-lock.h>
00088 #else
00089
00090 # define __libc_lock_define_initialized(CLASS, NAME)
00091 # define __libc_lock_lock(NAME)
00092 # define __libc_lock_unlock(NAME)
00093 # define __libc_rwlock_define_initialized(CLASS, NAME)
00094 # define __libc_rwlock_rdlock(NAME)
00095 # define __libc_rwlock_unlock(NAME)
00096 #endif
00097
00098
00099 #if defined __GNUC__ && __GNUC__ >= 2
00100 # define alignof(TYPE) __alignof__ (TYPE)
00101 #else
00102 # define alignof(TYPE) \
00103 ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
00104 #endif
00105
00106
00107
00108
00109 #if !defined _LIBC
00110 # define _nl_default_default_domain _nl_default_default_domain__
00111 # define _nl_current_default_domain _nl_current_default_domain__
00112 # define _nl_default_dirname _nl_default_dirname__
00113 # define _nl_domain_bindings _nl_domain_bindings__
00114 #endif
00115
00116
00117 #ifndef offsetof
00118 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
00119 #endif
00120
00121
00122
00123 #ifdef _LIBC
00124
00125
00126
00127
00128 # define getcwd __getcwd
00129 # ifndef stpcpy
00130 # define stpcpy __stpcpy
00131 # endif
00132 # define tfind __tfind
00133 #else
00134 # if !defined HAVE_GETCWD
00135 char *getwd ();
00136 # define getcwd(buf, max) getwd (buf)
00137 # else
00138 # if !defined HAVE_DECL_GETCWD
00139 char *getcwd ();
00140 # endif
00141 # endif
00142 # ifndef HAVE_STPCPY
00143 static char *stpcpy PARAMS ((char *dest, const char *src));
00144 # endif
00145 # ifndef HAVE_MEMPCPY
00146 static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
00147 # endif
00148 #endif
00149
00150
00151 #define PATH_INCR 32
00152
00153
00154
00155
00156
00157 #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
00158 # include <limits.h>
00159 #endif
00160
00161 #ifndef _POSIX_PATH_MAX
00162 # define _POSIX_PATH_MAX 255
00163 #endif
00164
00165 #if !defined PATH_MAX && defined _PC_PATH_MAX
00166 # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
00167 #endif
00168
00169
00170 #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
00171 # include <sys/param.h>
00172 #endif
00173
00174 #if !defined PATH_MAX && defined MAXPATHLEN
00175 # define PATH_MAX MAXPATHLEN
00176 #endif
00177
00178 #ifndef PATH_MAX
00179 # define PATH_MAX _POSIX_PATH_MAX
00180 #endif
00181
00182
00183
00184
00185
00186
00187
00188 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
00189
00190 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
00191 # define HAS_DEVICE(P) \
00192 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
00193 && (P)[1] == ':')
00194 # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
00195 # define IS_PATH_WITH_DIR(P) \
00196 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
00197 #else
00198
00199 # define ISSLASH(C) ((C) == '/')
00200 # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
00201 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
00202 #endif
00203
00204
00205
00206
00207
00208
00209
00210 #if defined _LIBC || (defined __GNU_LIBRARY__ && __GNU_LIBRARY__ >= 2)
00211 # define HAVE_LOCALE_NULL
00212 #endif
00213
00214
00215
00216 struct known_translation_t
00217 {
00218
00219 char *domainname;
00220
00221
00222 int category;
00223
00224
00225 int counter;
00226
00227
00228 struct loaded_l10nfile *domain;
00229
00230
00231 const char *translation;
00232 size_t translation_length;
00233
00234
00235 char msgid[ZERO];
00236 };
00237
00238
00239
00240 #if defined HAVE_TSEARCH || defined _LIBC
00241 # include <search.h>
00242
00243 static void *root;
00244
00245 # ifdef _LIBC
00246 # define tsearch __tsearch
00247 # endif
00248
00249
00250 static int transcmp PARAMS ((const void *p1, const void *p2));
00251 static int
00252 transcmp (p1, p2)
00253 const void *p1;
00254 const void *p2;
00255 {
00256 const struct known_translation_t *s1;
00257 const struct known_translation_t *s2;
00258 int result;
00259
00260 s1 = (const struct known_translation_t *) p1;
00261 s2 = (const struct known_translation_t *) p2;
00262
00263 result = strcmp (s1->msgid, s2->msgid);
00264 if (result == 0)
00265 {
00266 result = strcmp (s1->domainname, s2->domainname);
00267 if (result == 0)
00268
00269
00270
00271 result = s1->category - s2->category;
00272 }
00273
00274 return result;
00275 }
00276 #endif
00277
00278
00279
00280 const char _nl_default_default_domain[] = "messages";
00281
00282
00283 const char *_nl_current_default_domain = _nl_default_default_domain;
00284
00285
00286 const char _nl_default_dirname[] = LOCALEDIR;
00287
00288
00289
00290 struct binding *_nl_domain_bindings;
00291
00292
00293 static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
00294 unsigned long int n,
00295 const char *translation,
00296 size_t translation_len))
00297 internal_function;
00298 static unsigned long int plural_eval PARAMS ((struct expression *pexp,
00299 unsigned long int n))
00300 internal_function;
00301 static const char *category_to_name PARAMS ((int category)) internal_function;
00302 static const char *guess_category_value PARAMS ((int category,
00303 const char *categoryname))
00304 internal_function;
00305
00306
00307
00308
00309 #ifdef HAVE_ALLOCA
00310
00311 # define ADD_BLOCK(list, address)
00312 # define FREE_BLOCKS(list)
00313 #else
00314 struct block_list
00315 {
00316 void *address;
00317 struct block_list *next;
00318 };
00319 # define ADD_BLOCK(list, addr) \
00320 do { \
00321 struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
00322
00323 \
00324 if (newp != NULL) { \
00325 newp->address = (addr); \
00326 newp->next = (list); \
00327 (list) = newp; \
00328 } \
00329 } while (0)
00330 # define FREE_BLOCKS(list) \
00331 do { \
00332 while (list != NULL) { \
00333 struct block_list *old = list; \
00334 list = list->next; \
00335 free (old); \
00336 } \
00337 } while (0)
00338 # undef alloca
00339 # define alloca(size) (malloc (size))
00340 #endif
00341
00342
00343 #ifdef _LIBC
00344
00345 typedef struct transmem_list
00346 {
00347 struct transmem_list *next;
00348 char data[ZERO];
00349 } transmem_block_t;
00350 static struct transmem_list *transmem_list;
00351 #else
00352 typedef unsigned char transmem_block_t;
00353 #endif
00354
00355
00356
00357
00358
00359
00360 #ifdef _LIBC
00361 # define DCIGETTEXT __dcigettext
00362 #else
00363 # define DCIGETTEXT dcigettext__
00364 #endif
00365
00366
00367 #ifdef _LIBC
00368 __libc_rwlock_define_initialized (, _nl_state_lock)
00369 #endif
00370
00371
00372
00373 #ifdef _LIBC
00374 # define ENABLE_SECURE __libc_enable_secure
00375 # define DETERMINE_SECURE
00376 #else
00377 # ifndef HAVE_GETUID
00378 # define getuid() 0
00379 # endif
00380 # ifndef HAVE_GETGID
00381 # define getgid() 0
00382 # endif
00383 # ifndef HAVE_GETEUID
00384 # define geteuid() getuid()
00385 # endif
00386 # ifndef HAVE_GETEGID
00387 # define getegid() getgid()
00388 # endif
00389 static int enable_secure;
00390 # define ENABLE_SECURE (enable_secure == 1)
00391 # define DETERMINE_SECURE \
00392 if (enable_secure == 0) \
00393 { \
00394 if (getuid () != geteuid () || getgid () != getegid ()) \
00395 enable_secure = 1; \
00396 else \
00397 enable_secure = -1; \
00398 }
00399 #endif
00400
00401
00402
00403
00404 char *
00405 DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
00406 const char *domainname;
00407 const char *msgid1;
00408 const char *msgid2;
00409 int plural;
00410 unsigned long int n;
00411 int category;
00412 {
00413 #ifndef HAVE_ALLOCA
00414 struct block_list *block_list = NULL;
00415 #endif
00416 struct loaded_l10nfile *domain;
00417 struct binding *binding;
00418 const char *categoryname;
00419 const char *categoryvalue;
00420 char *dirname, *xdomainname;
00421 char *single_locale;
00422 char *retval;
00423 size_t retlen;
00424 int saved_errno;
00425 #if defined HAVE_TSEARCH || defined _LIBC
00426 struct known_translation_t *search;
00427 struct known_translation_t **foundp = NULL;
00428 size_t msgid_len;
00429 #endif
00430 size_t domainname_len;
00431
00432
00433 if (msgid1 == NULL)
00434 return NULL;
00435
00436 __libc_rwlock_rdlock (_nl_state_lock);
00437
00438
00439
00440
00441 if (domainname == NULL)
00442 domainname = _nl_current_default_domain;
00443
00444 #if defined HAVE_TSEARCH || defined _LIBC
00445 msgid_len = strlen (msgid1) + 1;
00446
00447
00448
00449 search = (struct known_translation_t *)
00450 alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
00451 memcpy (search->msgid, msgid1, msgid_len);
00452 search->domainname = (char *) domainname;
00453 search->category = category;
00454
00455 foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
00456 if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
00457 {
00458
00459 if (plural)
00460 retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
00461 (*foundp)->translation_length);
00462 else
00463 retval = (char *) (*foundp)->translation;
00464
00465 __libc_rwlock_unlock (_nl_state_lock);
00466 return retval;
00467 }
00468 #endif
00469
00470
00471 saved_errno = errno;
00472
00473
00474 DETERMINE_SECURE;
00475
00476
00477 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
00478 {
00479 int compare = strcmp (domainname, binding->domainname);
00480 if (compare == 0)
00481
00482 break;
00483 if (compare < 0)
00484 {
00485
00486 binding = NULL;
00487 break;
00488 }
00489 }
00490
00491 if (binding == NULL)
00492 dirname = (char *) _nl_default_dirname;
00493 else if (IS_ABSOLUTE_PATH (binding->dirname))
00494 dirname = binding->dirname;
00495 else
00496 {
00497
00498 size_t dirname_len = strlen (binding->dirname) + 1;
00499 size_t path_max;
00500 char *ret;
00501
00502 path_max = (unsigned int) PATH_MAX;
00503 path_max += 2;
00504
00505 for (;;)
00506 {
00507 dirname = (char *) alloca (path_max + dirname_len);
00508 ADD_BLOCK (block_list, dirname);
00509
00510 __set_errno (0);
00511 ret = getcwd (dirname, path_max);
00512 if (ret != NULL || errno != ERANGE)
00513 break;
00514
00515 path_max += path_max / 2;
00516 path_max += PATH_INCR;
00517 }
00518
00519 if (ret == NULL)
00520 {
00521
00522
00523 FREE_BLOCKS (block_list);
00524 __libc_rwlock_unlock (_nl_state_lock);
00525 __set_errno (saved_errno);
00526 return (plural == 0
00527 ? (char *) msgid1
00528
00529 : n == 1 ? (char *) msgid1 : (char *) msgid2);
00530 }
00531
00532 stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
00533 }
00534
00535
00536 categoryname = category_to_name (category);
00537 categoryvalue = guess_category_value (category, categoryname);
00538
00539 domainname_len = strlen (domainname);
00540 xdomainname = (char *) alloca (strlen (categoryname)
00541 + domainname_len + 5);
00542 ADD_BLOCK (block_list, xdomainname);
00543
00544 stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
00545 domainname, domainname_len),
00546 ".mo");
00547
00548
00549 single_locale = (char *) alloca (strlen (categoryvalue) + 1);
00550 ADD_BLOCK (block_list, single_locale);
00551
00552
00553
00554
00555 while (1)
00556 {
00557
00558 while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
00559 ++categoryvalue;
00560 if (categoryvalue[0] == '\0')
00561 {
00562
00563
00564
00565
00566 single_locale[0] = 'C';
00567 single_locale[1] = '\0';
00568 }
00569 else
00570 {
00571 char *cp = single_locale;
00572 while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
00573 *cp++ = *categoryvalue++;
00574 *cp = '\0';
00575
00576
00577
00578 if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
00579
00580 continue;
00581 }
00582
00583
00584
00585 if (strcmp (single_locale, "C") == 0
00586 || strcmp (single_locale, "POSIX") == 0)
00587 {
00588 FREE_BLOCKS (block_list);
00589 __libc_rwlock_unlock (_nl_state_lock);
00590 __set_errno (saved_errno);
00591 return (plural == 0
00592 ? (char *) msgid1
00593
00594 : n == 1 ? (char *) msgid1 : (char *) msgid2);
00595 }
00596
00597
00598
00599
00600 domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
00601
00602 if (domain != NULL)
00603 {
00604 retval = _nl_find_msg (domain, binding, msgid1, &retlen);
00605
00606 if (retval == NULL)
00607 {
00608 int cnt;
00609
00610 for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
00611 {
00612 retval = _nl_find_msg (domain->successor[cnt], binding,
00613 msgid1, &retlen);
00614
00615 if (retval != NULL)
00616 {
00617 domain = domain->successor[cnt];
00618 break;
00619 }
00620 }
00621 }
00622
00623 if (retval != NULL)
00624 {
00625
00626
00627 FREE_BLOCKS (block_list);
00628 __set_errno (saved_errno);
00629 #if defined HAVE_TSEARCH || defined _LIBC
00630 if (foundp == NULL)
00631 {
00632
00633 struct known_translation_t *newp;
00634
00635 newp = (struct known_translation_t *)
00636 malloc (offsetof (struct known_translation_t, msgid)
00637 + msgid_len + domainname_len + 1);
00638 if (newp != NULL)
00639 {
00640 newp->domainname =
00641 mempcpy (newp->msgid, msgid1, msgid_len);
00642 memcpy (newp->domainname, domainname, domainname_len + 1);
00643 newp->category = category;
00644 newp->counter = _nl_msg_cat_cntr;
00645 newp->domain = domain;
00646 newp->translation = retval;
00647 newp->translation_length = retlen;
00648
00649
00650 foundp = (struct known_translation_t **)
00651 tsearch (newp, &root, transcmp);
00652 if (foundp == NULL
00653 || __builtin_expect (*foundp != newp, 0))
00654
00655 free (newp);
00656 }
00657 }
00658 else
00659 {
00660
00661 (*foundp)->counter = _nl_msg_cat_cntr;
00662 (*foundp)->domain = domain;
00663 (*foundp)->translation = retval;
00664 (*foundp)->translation_length = retlen;
00665 }
00666 #endif
00667
00668 if (plural)
00669 retval = plural_lookup (domain, n, retval, retlen);
00670
00671 __libc_rwlock_unlock (_nl_state_lock);
00672 return retval;
00673 }
00674 }
00675 }
00676
00677 }
00678
00679
00680 char *
00681 internal_function
00682 _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
00683 struct loaded_l10nfile *domain_file;
00684 struct binding *domainbinding;
00685 const char *msgid;
00686 size_t *lengthp;
00687 {
00688 struct loaded_domain *domain;
00689 size_t act;
00690 char *result;
00691 size_t resultlen;
00692
00693 if (domain_file->decided == 0)
00694 _nl_load_domain (domain_file, domainbinding);
00695
00696 if (domain_file->data == NULL)
00697 return NULL;
00698
00699 domain = (struct loaded_domain *) domain_file->data;
00700
00701
00702 if (domain->hash_size > 2 && domain->hash_tab != NULL)
00703 {
00704
00705 nls_uint32 len = strlen (msgid);
00706 nls_uint32 hash_val = hash_string (msgid);
00707 nls_uint32 idx = hash_val % domain->hash_size;
00708 nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
00709
00710 while (1)
00711 {
00712 nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
00713
00714 if (nstr == 0)
00715
00716 return NULL;
00717
00718
00719
00720
00721 if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
00722 && (strcmp (msgid,
00723 domain->data + W (domain->must_swap,
00724 domain->orig_tab[nstr - 1].offset))
00725 == 0))
00726 {
00727 act = nstr - 1;
00728 goto found;
00729 }
00730
00731 if (idx >= domain->hash_size - incr)
00732 idx -= domain->hash_size - incr;
00733 else
00734 idx += incr;
00735 }
00736
00737 }
00738 else
00739 {
00740
00741
00742 size_t top, bottom;
00743
00744 bottom = 0;
00745 act = 0;
00746 top = domain->nstrings;
00747 while (bottom < top)
00748 {
00749 int cmp_val;
00750
00751 act = (bottom + top) / 2;
00752 cmp_val = strcmp (msgid, (domain->data
00753 + W (domain->must_swap,
00754 domain->orig_tab[act].offset)));
00755 if (cmp_val < 0)
00756 top = act;
00757 else if (cmp_val > 0)
00758 bottom = act + 1;
00759 else
00760 goto found;
00761 }
00762
00763 return NULL;
00764 }
00765
00766 found:
00767
00768
00769 result = ((char *) domain->data
00770 + W (domain->must_swap, domain->trans_tab[act].offset));
00771 resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
00772
00773 #if defined _LIBC || HAVE_ICONV
00774 if (domain->codeset_cntr
00775 != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
00776 {
00777
00778
00779
00780 _nl_free_domain_conv (domain);
00781 _nl_init_domain_conv (domain_file, domain, domainbinding);
00782 }
00783
00784 if (
00785 # ifdef _LIBC
00786 domain->conv != (__gconv_t) -1
00787 # else
00788 # if HAVE_ICONV
00789 domain->conv != (iconv_t) -1
00790 # endif
00791 # endif
00792 )
00793 {
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803 if (domain->conv_tab == NULL
00804 && ((domain->conv_tab = (char **) calloc (domain->nstrings,
00805 sizeof (char *)))
00806 == NULL))
00807
00808 domain->conv_tab = (char **) -1;
00809
00810 if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
00811
00812 goto converted;
00813
00814 if (domain->conv_tab[act] == NULL)
00815 {
00816
00817
00818
00819
00820
00821 __libc_lock_define_initialized (static, lock)
00822 # define INITIAL_BLOCK_SIZE 4080
00823 static unsigned char *freemem;
00824 static size_t freemem_size;
00825
00826 const unsigned char *inbuf;
00827 unsigned char *outbuf;
00828 int malloc_count;
00829 # ifndef _LIBC
00830 transmem_block_t *transmem_list = NULL;
00831 # endif
00832
00833 __libc_lock_lock (lock);
00834
00835 inbuf = (const unsigned char *) result;
00836 outbuf = freemem + sizeof (size_t);
00837
00838 malloc_count = 0;
00839 while (1)
00840 {
00841 transmem_block_t *newmem;
00842 # ifdef _LIBC
00843 size_t non_reversible;
00844 int res;
00845
00846 if (freemem_size < sizeof (size_t))
00847 goto resize_freemem;
00848
00849 res = __gconv (domain->conv,
00850 &inbuf, inbuf + resultlen,
00851 &outbuf,
00852 outbuf + freemem_size - sizeof (size_t),
00853 &non_reversible);
00854
00855 if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
00856 break;
00857
00858 if (res != __GCONV_FULL_OUTPUT)
00859 {
00860 __libc_lock_unlock (lock);
00861 goto converted;
00862 }
00863
00864 inbuf = result;
00865 # else
00866 # if HAVE_ICONV
00867 const char *inptr = (const char *) inbuf;
00868 size_t inleft = resultlen;
00869 char *outptr = (char *) outbuf;
00870 size_t outleft;
00871
00872 if (freemem_size < sizeof (size_t))
00873 goto resize_freemem;
00874
00875 outleft = freemem_size - sizeof (size_t);
00876 if (iconv (domain->conv,
00877 (ICONV_CONST char **) &inptr, &inleft,
00878 &outptr, &outleft)
00879 != (size_t) (-1))
00880 {
00881 outbuf = (unsigned char *) outptr;
00882 break;
00883 }
00884 if (errno != E2BIG)
00885 {
00886 __libc_lock_unlock (lock);
00887 goto converted;
00888 }
00889 # endif
00890 # endif
00891
00892 resize_freemem:
00893
00894 if (malloc_count > 0)
00895 {
00896 ++malloc_count;
00897 freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
00898 newmem = (transmem_block_t *) realloc (transmem_list,
00899 freemem_size);
00900 # ifdef _LIBC
00901 if (newmem != NULL)
00902 transmem_list = transmem_list->next;
00903 else
00904 {
00905 struct transmem_list *old = transmem_list;
00906
00907 transmem_list = transmem_list->next;
00908 free (old);
00909 }
00910 # endif
00911 }
00912 else
00913 {
00914 malloc_count = 1;
00915 freemem_size = INITIAL_BLOCK_SIZE;
00916 newmem = (transmem_block_t *) malloc (freemem_size);
00917 }
00918 if (__builtin_expect (newmem == NULL, 0))
00919 {
00920 freemem = NULL;
00921 freemem_size = 0;
00922 __libc_lock_unlock (lock);
00923 goto converted;
00924 }
00925
00926 # ifdef _LIBC
00927
00928
00929 newmem->next = transmem_list;
00930 transmem_list = newmem;
00931
00932 freemem = newmem->data;
00933 freemem_size -= offsetof (struct transmem_list, data);
00934 # else
00935 transmem_list = newmem;
00936 freemem = newmem;
00937 # endif
00938
00939 outbuf = freemem + sizeof (size_t);
00940 }
00941
00942
00943
00944 *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
00945 domain->conv_tab[act] = (char *) freemem;
00946
00947 freemem_size -= outbuf - freemem;
00948 freemem = outbuf;
00949 freemem += freemem_size & (alignof (size_t) - 1);
00950 freemem_size = freemem_size & ~ (alignof (size_t) - 1);
00951
00952 __libc_lock_unlock (lock);
00953 }
00954
00955
00956
00957 result = domain->conv_tab[act] + sizeof (size_t);
00958 resultlen = *(size_t *) domain->conv_tab[act];
00959 }
00960
00961 converted:
00962
00963
00964 #endif
00965
00966 *lengthp = resultlen;
00967 return result;
00968 }
00969
00970
00971
00972 static char *
00973 internal_function
00974 plural_lookup (domain, n, translation, translation_len)
00975 struct loaded_l10nfile *domain;
00976 unsigned long int n;
00977 const char *translation;
00978 size_t translation_len;
00979 {
00980 struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
00981 unsigned long int index;
00982 const char *p;
00983
00984 index = plural_eval (domaindata->plural, n);
00985 if (index >= domaindata->nplurals)
00986
00987
00988 index = 0;
00989
00990
00991 p = translation;
00992 while (index-- > 0)
00993 {
00994 #ifdef _LIBC
00995 p = __rawmemchr (p, '\0');
00996 #else
00997 p = strchr (p, '\0');
00998 #endif
00999
01000 p++;
01001
01002 if (p >= translation + translation_len)
01003
01004
01005
01006 return (char *) translation;
01007 }
01008 return (char *) p;
01009 }
01010
01011
01012
01013 static unsigned long int
01014 internal_function
01015 plural_eval (pexp, n)
01016 struct expression *pexp;
01017 unsigned long int n;
01018 {
01019 switch (pexp->nargs)
01020 {
01021 case 0:
01022 switch (pexp->operation)
01023 {
01024 case var:
01025 return n;
01026 case num:
01027 return pexp->val.num;
01028 default:
01029 break;
01030 }
01031
01032 break;
01033 case 1:
01034 {
01035
01036 unsigned long int arg = plural_eval (pexp->val.args[0], n);
01037 return ! arg;
01038 }
01039 case 2:
01040 {
01041 unsigned long int leftarg = plural_eval (pexp->val.args[0], n);
01042 if (pexp->operation == lor)
01043 return leftarg || plural_eval (pexp->val.args[1], n);
01044 else if (pexp->operation == land)
01045 return leftarg && plural_eval (pexp->val.args[1], n);
01046 else
01047 {
01048 unsigned long int rightarg = plural_eval (pexp->val.args[1], n);
01049
01050 switch (pexp->operation)
01051 {
01052 case mult:
01053 return leftarg * rightarg;
01054 case divide:
01055 return leftarg / rightarg;
01056 case module:
01057 return leftarg % rightarg;
01058 case plus:
01059 return leftarg + rightarg;
01060 case minus:
01061 return leftarg - rightarg;
01062 case less_than:
01063 return leftarg < rightarg;
01064 case greater_than:
01065 return leftarg > rightarg;
01066 case less_or_equal:
01067 return leftarg <= rightarg;
01068 case greater_or_equal:
01069 return leftarg >= rightarg;
01070 case equal:
01071 return leftarg == rightarg;
01072 case not_equal:
01073 return leftarg != rightarg;
01074 default:
01075 break;
01076 }
01077 }
01078
01079 break;
01080 }
01081 case 3:
01082 {
01083
01084 unsigned long int boolarg = plural_eval (pexp->val.args[0], n);
01085 return plural_eval (pexp->val.args[boolarg ? 1 : 2], n);
01086 }
01087 }
01088
01089 return 0;
01090 }
01091
01092
01093
01094 static const char *
01095 internal_function
01096 category_to_name (category)
01097 int category;
01098 {
01099 const char *retval;
01100
01101 switch (category)
01102 {
01103 #ifdef LC_COLLATE
01104 case LC_COLLATE:
01105 retval = "LC_COLLATE";
01106 break;
01107 #endif
01108 #ifdef LC_CTYPE
01109 case LC_CTYPE:
01110 retval = "LC_CTYPE";
01111 break;
01112 #endif
01113 #ifdef LC_MONETARY
01114 case LC_MONETARY:
01115 retval = "LC_MONETARY";
01116 break;
01117 #endif
01118 #ifdef LC_NUMERIC
01119 case LC_NUMERIC:
01120 retval = "LC_NUMERIC";
01121 break;
01122 #endif
01123 #ifdef LC_TIME
01124 case LC_TIME:
01125 retval = "LC_TIME";
01126 break;
01127 #endif
01128 #ifdef LC_MESSAGES
01129 case LC_MESSAGES:
01130 retval = "LC_MESSAGES";
01131 break;
01132 #endif
01133 #ifdef LC_RESPONSE
01134 case LC_RESPONSE:
01135 retval = "LC_RESPONSE";
01136 break;
01137 #endif
01138 #ifdef LC_ALL
01139 case LC_ALL:
01140
01141
01142 retval = "LC_ALL";
01143 break;
01144 #endif
01145 default:
01146
01147 retval = "LC_XXX";
01148 }
01149
01150 return retval;
01151 }
01152
01153
01154 static const char *
01155 internal_function
01156 guess_category_value (category, categoryname)
01157 int category;
01158 const char *categoryname;
01159 {
01160 const char *language;
01161 const char *retval;
01162 (void) category;
01163 (void) categoryname;
01164
01165
01166
01167
01168 language = getenv ("LANGUAGE");
01169 if (language != NULL && language[0] == '\0')
01170 language = NULL;
01171
01172
01173
01174
01175 #if defined _LIBC || (defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL)
01176 retval = setlocale (category, NULL);
01177 #else
01178
01179 retval = getenv ("LC_ALL");
01180 if (retval == NULL || retval[0] == '\0')
01181 {
01182
01183 retval = getenv (categoryname);
01184 if (retval == NULL || retval[0] == '\0')
01185 {
01186
01187 retval = getenv ("LANG");
01188 if (retval == NULL || retval[0] == '\0')
01189
01190
01191 return "C";
01192 }
01193 }
01194 #endif
01195
01196 return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
01197 }
01198
01199
01200
01201
01202
01203
01204
01205 #if !_LIBC && !HAVE_STPCPY
01206 static char *
01207 stpcpy (dest, src)
01208 char *dest;
01209 const char *src;
01210 {
01211 while ((*dest++ = *src++) != '\0')
01212 ;
01213 return dest - 1;
01214 }
01215 #endif
01216
01217 #if !_LIBC && !HAVE_MEMPCPY
01218 static void *
01219 mempcpy (dest, src, n)
01220 void *dest;
01221 const void *src;
01222 size_t n;
01223 {
01224 return (void *) ((char *) memcpy (dest, src, n) + n);
01225 }
01226 #endif
01227
01228
01229 #ifdef _LIBC
01230
01231
01232 static void __attribute__ ((unused))
01233 free_mem (void)
01234 {
01235 void *old;
01236
01237 while (_nl_domain_bindings != NULL)
01238 {
01239 struct binding *oldp = _nl_domain_bindings;
01240 _nl_domain_bindings = _nl_domain_bindings->next;
01241 if (oldp->dirname != _nl_default_dirname)
01242
01243 free (oldp->dirname);
01244 free (oldp->codeset);
01245 free (oldp);
01246 }
01247
01248 if (_nl_current_default_domain != _nl_default_default_domain)
01249
01250 free ((char *) _nl_current_default_domain);
01251
01252
01253 __tdestroy (root, free);
01254 root = NULL;
01255
01256 while (transmem_list != NULL)
01257 {
01258 old = transmem_list;
01259 transmem_list = transmem_list->next;
01260 free (old);
01261 }
01262 }
01263
01264 text_set_element (__libc_subfreeres, free_mem);
01265 #endif