1 /* dcigettext.c - Implementation of the internal dcigettext function. */
3 /* Copyright (C) 1995-1999, 2000-2003, 2006-2009 Free Software Foundation, Inc.
5 This file is part of GNU Bush.
7 Bush is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bush is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bush. If not, see <http://www.gnu.org/licenses/>.
21 /* Tell glibc's <string.h> to provide a prototype for mempcpy().
22 This must come before <config.h> because <config.h> may include
23 <features.h>, and once <features.h> has been included, it's too late. */
25 # define _GNU_SOURCE 1
32 #include <sys/types.h>
35 # define alloca __builtin_alloca
36 # define HAVE_ALLOCA 1
40 # define alloca _alloca
42 # if defined HAVE_ALLOCA_H || defined _LIBC
61 # define __set_errno(val) errno = (val)
68 #if defined HAVE_UNISTD_H || defined _LIBC
75 /* Guess whether integer division by zero raises signal SIGFPE.
76 Set to 1 only if you know for sure. In case of doubt, set to 0. */
77 # if defined __alpha__ || defined __arm__ || defined __i386__ \
78 || defined __m68k__ || defined __s390__
79 # define INTDIV0_RAISES_SIGFPE 1
81 # define INTDIV0_RAISES_SIGFPE 0
84 #if !INTDIV0_RAISES_SIGFPE
88 #if defined HAVE_SYS_PARAM_H || defined _LIBC
89 # include <sys/param.h>
93 #include "plural-exp.h"
97 # include "libgnuintl.h"
99 #include "hash-string.h"
101 /* Thread safetyness. */
103 # include <bits/libc-lock.h>
105 /* Provide dummy implementation if this is outside glibc. */
106 # define __libc_lock_define_initialized(CLASS, NAME)
107 # define __libc_lock_lock(NAME)
108 # define __libc_lock_unlock(NAME)
109 # define __libc_rwlock_define_initialized(CLASS, NAME)
110 # define __libc_rwlock_rdlock(NAME)
111 # define __libc_rwlock_unlock(NAME)
114 /* Alignment of types. */
115 #if defined __GNUC__ && __GNUC__ >= 2
116 # define alignof(TYPE) __alignof__ (TYPE)
118 # define alignof(TYPE) \
119 ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
122 /* The internal variables in the standalone libintl.a must have different
123 names than the internal variables in GNU libc, otherwise programs
124 using libintl.a cannot be linked statically. */
126 # define _nl_default_default_domain libintl_nl_default_default_domain
127 # define _nl_current_default_domain libintl_nl_current_default_domain
128 # define _nl_default_dirname libintl_nl_default_dirname
129 # define _nl_domain_bindings libintl_nl_domain_bindings
132 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
134 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
137 /* @@ end of prolog @@ */
139 #if defined (SHELL) && !defined (HAVE_GETCWD)
144 /* Rename the non ANSI C functions. This is required by the standard
145 because some ANSI C functions will require linking with this object
146 file and the name space must not be polluted. */
147 # define getcwd __getcwd
149 # define stpcpy __stpcpy
151 # define tfind __tfind
153 # if !defined HAVE_GETCWD
155 # define getcwd(buf, max) getwd (buf)
160 static char *stpcpy
PARAMS ((char *dest
, const char *src
));
162 # ifndef HAVE_MEMPCPY
163 static void *mempcpy
PARAMS ((void *dest
, const void *src
, size_t n
));
167 /* Amount to increase buffer size by in each try. */
170 /* The following is from pathmax.h. */
171 /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
172 PATH_MAX but might cause redefinition warnings when sys/param.h is
173 later included (as on MORE/BSD 4.3). */
174 #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
178 #ifndef _POSIX_PATH_MAX
179 # define _POSIX_PATH_MAX 255
182 #if !defined PATH_MAX && defined _PC_PATH_MAX
183 # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
186 /* Don't include sys/param.h if it already has been. */
187 #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
188 # include <sys/param.h>
191 #if !defined PATH_MAX && defined MAXPATHLEN
192 # define PATH_MAX MAXPATHLEN
196 # define PATH_MAX _POSIX_PATH_MAX
200 ISSLASH(C) tests whether C is a directory separator character.
201 IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
202 it may be concatenated to a directory pathname.
203 IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
205 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
206 /* Win32, OS/2, DOS */
207 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
208 # define HAS_DEVICE(P) \
209 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
211 # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
212 # define IS_PATH_WITH_DIR(P) \
213 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
216 # define ISSLASH(C) ((C) == '/')
217 # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
218 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
221 /* This is the type used for the search tree where known translations
223 struct known_translation_t
225 /* Domain in which to search. */
231 /* State of the catalog counter at the point the string was found. */
234 /* Catalog where the string was found. */
235 struct loaded_l10nfile
*domain
;
237 /* And finally the translation. */
238 const char *translation
;
239 size_t translation_length
;
241 /* Pointer to the string in question. */
245 /* Root of the search tree with known translations. We can use this
246 only if the system provides the `tsearch' function family. */
247 #if defined HAVE_TSEARCH || defined _LIBC
253 # define tsearch __tsearch
256 /* Function to compare two entries in the table of known translations. */
257 static int transcmp
PARAMS ((const void *p1
, const void *p2
));
263 const struct known_translation_t
*s1
;
264 const struct known_translation_t
*s2
;
267 s1
= (const struct known_translation_t
*) p1
;
268 s2
= (const struct known_translation_t
*) p2
;
270 result
= strcmp (s1
->msgid
, s2
->msgid
);
273 result
= strcmp (s1
->domainname
, s2
->domainname
);
275 /* We compare the category last (though this is the cheapest
276 operation) since it is hopefully always the same (namely
278 result
= s1
->category
- s2
->category
;
286 # define INTVARDEF(name)
289 # define INTUSE(name) name
292 /* Name of the default domain used for gettext(3) prior any call to
293 textdomain(3). The default value for this is "messages". */
294 const char _nl_default_default_domain
[] attribute_hidden
= "messages";
296 /* Value used as the default domain for gettext(3). */
297 const char *_nl_current_default_domain attribute_hidden
298 = _nl_default_default_domain
;
300 /* Contains the default location of the message catalogs. */
302 extern const char _nl_default_dirname
[];
304 const char _nl_default_dirname
[] = LOCALEDIR
;
305 INTVARDEF (_nl_default_dirname
)
308 /* List with bindings of specific domains created by bindtextdomain()
310 struct binding
*_nl_domain_bindings
;
312 /* Prototypes for local functions. */
313 static char *plural_lookup
PARAMS ((struct loaded_l10nfile
*domain
,
315 const char *translation
,
316 size_t translation_len
))
318 static const char *guess_category_value
PARAMS ((int category
,
319 const char *categoryname
))
322 # include "../locale/localeinfo.h"
323 # define category_to_name(category) _nl_category_names[category]
325 static const char *category_to_name
PARAMS ((int category
)) internal_function
;
329 /* For those loosing systems which don't have `alloca' we have to add
330 some additional code emulating it. */
332 /* Nothing has to be done. */
333 # define freea(p) /* nothing */
334 # define ADD_BLOCK(list, address) /* nothing */
335 # define FREE_BLOCKS(list) /* nothing */
340 struct block_list
*next
;
342 # define ADD_BLOCK(list, addr) \
344 struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
345 /* If we cannot get a free block we cannot add the new element to \
347 if (newp != NULL) { \
348 newp->address = (addr); \
349 newp->next = (list); \
353 # define FREE_BLOCKS(list) \
355 while (list != NULL) { \
356 struct block_list *old = list; \
358 free (old->address); \
363 # define alloca(size) (malloc (size))
364 # define freea(p) free (p)
365 #endif /* have alloca */
369 /* List of blocks allocated for translations. */
370 typedef struct transmem_list
372 struct transmem_list
*next
;
375 static struct transmem_list
*transmem_list
;
377 typedef unsigned char transmem_block_t
;
381 /* Names for the libintl functions are a problem. They must not clash
382 with existing names and they should follow ANSI C. But this source
383 code is also used in GNU C Library where the names have a __
384 prefix. So we have to make a difference here. */
386 # define DCIGETTEXT __dcigettext
388 # define DCIGETTEXT libintl_dcigettext
391 /* Lock variable to protect the global data in the gettext implementation. */
393 __libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden
)
396 /* Checking whether the binaries runs SUID must be done and glibc provides
397 easier methods therefore we make a difference here. */
399 # define ENABLE_SECURE __libc_enable_secure
400 # define DETERMINE_SECURE
408 # ifndef HAVE_GETEUID
409 # define geteuid() getuid()
411 # ifndef HAVE_GETEGID
412 # define getegid() getgid()
414 static int enable_secure
;
415 # define ENABLE_SECURE (enable_secure == 1)
416 # define DETERMINE_SECURE \
417 if (enable_secure == 0) \
419 if (getuid () != geteuid () || getgid () != getegid ()) \
422 enable_secure = -1; \
427 # define raise(x) kill (getpid (), (x))
430 /* Get the function to evaluate the plural expression. */
431 #include "eval-plural.h"
433 /* Look up MSGID in the DOMAINNAME message catalog for the current
434 CATEGORY locale and, if PLURAL is nonzero, search over string
435 depending on the plural form determined by N. */
437 DCIGETTEXT (domainname
, msgid1
, msgid2
, plural
, n
, category
)
438 const char *domainname
;
446 struct block_list
*block_list
= NULL
;
448 struct loaded_l10nfile
*domain
;
449 struct binding
*binding
;
450 const char *categoryname
;
451 const char *categoryvalue
;
452 char *dirname
, *xdomainname
;
457 #if defined HAVE_TSEARCH || defined _LIBC
458 struct known_translation_t
*search
;
459 struct known_translation_t
**foundp
= NULL
;
462 size_t domainname_len
;
464 /* If no real MSGID is given return NULL. */
469 if (category
< 0 || category
>= __LC_LAST
|| category
== LC_ALL
)
473 /* Use the Germanic plural rule. */
474 : n
== 1 ? (char *) msgid1
: (char *) msgid2
);
477 __libc_rwlock_rdlock (_nl_state_lock
);
479 /* If DOMAINNAME is NULL, we are interested in the default domain. If
480 CATEGORY is not LC_MESSAGES this might not make much sense but the
481 definition left this undefined. */
482 if (domainname
== NULL
)
483 domainname
= _nl_current_default_domain
;
485 /* OS/2 specific: backward compatibility with older libintl versions */
486 #ifdef LC_MESSAGES_COMPAT
487 if (category
== LC_MESSAGES_COMPAT
)
488 category
= LC_MESSAGES
;
491 #if defined HAVE_TSEARCH || defined _LIBC
492 msgid_len
= strlen (msgid1
) + 1;
494 /* Try to find the translation among those which we found at
496 search
= (struct known_translation_t
*)
497 alloca (offsetof (struct known_translation_t
, msgid
) + msgid_len
);
498 memcpy (search
->msgid
, msgid1
, msgid_len
);
499 search
->domainname
= (char *) domainname
;
500 search
->category
= category
;
502 foundp
= (struct known_translation_t
**) tfind (search
, &root
, transcmp
);
504 if (foundp
!= NULL
&& (*foundp
)->counter
== _nl_msg_cat_cntr
)
506 /* Now deal with plural. */
508 retval
= plural_lookup ((*foundp
)->domain
, n
, (*foundp
)->translation
,
509 (*foundp
)->translation_length
);
511 retval
= (char *) (*foundp
)->translation
;
513 __libc_rwlock_unlock (_nl_state_lock
);
518 /* Preserve the `errno' value. */
521 /* See whether this is a SUID binary or not. */
524 /* First find matching binding. */
525 for (binding
= _nl_domain_bindings
; binding
!= NULL
; binding
= binding
->next
)
527 int compare
= strcmp (domainname
, binding
->domainname
);
533 /* It is not in the list. */
540 dirname
= (char *) INTUSE(_nl_default_dirname
);
541 else if (IS_ABSOLUTE_PATH (binding
->dirname
))
542 dirname
= binding
->dirname
;
545 /* We have a relative path. Make it absolute now. */
546 size_t dirname_len
= strlen (binding
->dirname
) + 1;
550 path_max
= (unsigned int) PATH_MAX
;
551 path_max
+= 2; /* The getcwd docs say to do this. */
555 dirname
= (char *) alloca (path_max
+ dirname_len
);
556 ADD_BLOCK (block_list
, dirname
);
559 ret
= getcwd (dirname
, path_max
);
560 if (ret
!= NULL
|| errno
!= ERANGE
)
563 path_max
+= path_max
/ 2;
564 path_max
+= PATH_INCR
;
568 /* We cannot get the current working directory. Don't signal an
569 error but simply return the default string. */
570 goto return_untranslated
;
572 stpcpy (stpcpy (strchr (dirname
, '\0'), "/"), binding
->dirname
);
575 /* Now determine the symbolic name of CATEGORY and its value. */
576 categoryname
= category_to_name (category
);
577 categoryvalue
= guess_category_value (category
, categoryname
);
579 domainname_len
= strlen (domainname
);
580 xdomainname
= (char *) alloca (strlen (categoryname
)
581 + domainname_len
+ 5);
582 ADD_BLOCK (block_list
, xdomainname
);
584 stpcpy (mempcpy (stpcpy (stpcpy (xdomainname
, categoryname
), "/"),
585 domainname
, domainname_len
),
588 /* Creating working area. */
589 single_locale
= (char *) alloca (strlen (categoryvalue
) + 1);
590 ADD_BLOCK (block_list
, single_locale
);
593 /* Search for the given string. This is a loop because we perhaps
594 got an ordered list of languages to consider for the translation. */
597 /* Make CATEGORYVALUE point to the next element of the list. */
598 while (categoryvalue
[0] != '\0' && categoryvalue
[0] == ':')
600 if (categoryvalue
[0] == '\0')
602 /* The whole contents of CATEGORYVALUE has been searched but
603 no valid entry has been found. We solve this situation
604 by implicitly appending a "C" entry, i.e. no translation
606 single_locale
[0] = 'C';
607 single_locale
[1] = '\0';
611 char *cp
= single_locale
;
612 while (categoryvalue
[0] != '\0' && categoryvalue
[0] != ':')
613 *cp
++ = *categoryvalue
++;
616 /* When this is a SUID binary we must not allow accessing files
617 outside the dedicated directories. */
618 if (ENABLE_SECURE
&& IS_PATH_WITH_DIR (single_locale
))
619 /* Ingore this entry. */
623 /* If the current locale value is C (or POSIX) we don't load a
624 domain. Return the MSGID. */
625 if (strcmp (single_locale
, "C") == 0
626 || strcmp (single_locale
, "POSIX") == 0)
629 /* Find structure describing the message catalog matching the
630 DOMAINNAME and CATEGORY. */
631 domain
= _nl_find_domain (dirname
, single_locale
, xdomainname
, binding
);
635 retval
= _nl_find_msg (domain
, binding
, msgid1
, &retlen
);
641 for (cnt
= 0; domain
->successor
[cnt
] != NULL
; ++cnt
)
643 retval
= _nl_find_msg (domain
->successor
[cnt
], binding
,
648 domain
= domain
->successor
[cnt
];
656 /* Found the translation of MSGID1 in domain DOMAIN:
657 starting at RETVAL, RETLEN bytes. */
658 FREE_BLOCKS (block_list
);
659 #if defined HAVE_TSEARCH || defined _LIBC
662 /* Create a new entry and add it to the search tree. */
663 struct known_translation_t
*newp
;
665 newp
= (struct known_translation_t
*)
666 malloc (offsetof (struct known_translation_t
, msgid
)
667 + msgid_len
+ domainname_len
+ 1);
671 mempcpy (newp
->msgid
, msgid1
, msgid_len
);
672 memcpy (newp
->domainname
, domainname
, domainname_len
+ 1);
673 newp
->category
= category
;
674 newp
->counter
= _nl_msg_cat_cntr
;
675 newp
->domain
= domain
;
676 newp
->translation
= retval
;
677 newp
->translation_length
= retlen
;
679 /* Insert the entry in the search tree. */
680 foundp
= (struct known_translation_t
**)
681 tsearch (newp
, &root
, transcmp
);
683 || __builtin_expect (*foundp
!= newp
, 0))
684 /* The insert failed. */
690 /* We can update the existing entry. */
691 (*foundp
)->counter
= _nl_msg_cat_cntr
;
692 (*foundp
)->domain
= domain
;
693 (*foundp
)->translation
= retval
;
694 (*foundp
)->translation_length
= retlen
;
697 __set_errno (saved_errno
);
699 /* Now deal with plural. */
701 retval
= plural_lookup (domain
, n
, retval
, retlen
);
703 __libc_rwlock_unlock (_nl_state_lock
);
710 /* Return the untranslated MSGID. */
711 FREE_BLOCKS (block_list
);
712 __libc_rwlock_unlock (_nl_state_lock
);
716 extern void _nl_log_untranslated
PARAMS ((const char *logfilename
,
717 const char *domainname
,
721 const char *logfilename
= getenv ("GETTEXT_LOG_UNTRANSLATED");
723 if (logfilename
!= NULL
&& logfilename
[0] != '\0')
724 _nl_log_untranslated (logfilename
, domainname
, msgid1
, msgid2
, plural
);
727 __set_errno (saved_errno
);
730 /* Use the Germanic plural rule. */
731 : n
== 1 ? (char *) msgid1
: (char *) msgid2
);
737 _nl_find_msg (domain_file
, domainbinding
, msgid
, lengthp
)
738 struct loaded_l10nfile
*domain_file
;
739 struct binding
*domainbinding
;
743 struct loaded_domain
*domain
;
749 if (domain_file
->decided
== 0)
750 _nl_load_domain (domain_file
, domainbinding
);
752 if (domain_file
->data
== NULL
)
755 domain
= (struct loaded_domain
*) domain_file
->data
;
757 nstrings
= domain
->nstrings
;
759 /* Locate the MSGID and its translation. */
760 if (domain
->hash_tab
!= NULL
)
762 /* Use the hashing table. */
763 nls_uint32 len
= strlen (msgid
);
764 nls_uint32 hash_val
= hash_string (msgid
);
765 nls_uint32 idx
= hash_val
% domain
->hash_size
;
766 nls_uint32 incr
= 1 + (hash_val
% (domain
->hash_size
- 2));
771 W (domain
->must_swap_hash_tab
, domain
->hash_tab
[idx
]);
774 /* Hash table entry is empty. */
779 /* Compare msgid with the original string at index nstr.
780 We compare the lengths with >=, not ==, because plural entries
781 are represented by strings with an embedded NUL. */
783 ? W (domain
->must_swap
, domain
->orig_tab
[nstr
].length
) >= len
785 domain
->data
+ W (domain
->must_swap
,
786 domain
->orig_tab
[nstr
].offset
))
788 : domain
->orig_sysdep_tab
[nstr
- nstrings
].length
> len
790 domain
->orig_sysdep_tab
[nstr
- nstrings
].pointer
)
797 if (idx
>= domain
->hash_size
- incr
)
798 idx
-= domain
->hash_size
- incr
;
806 /* Try the default method: binary search in the sorted array of
816 act
= (bottom
+ top
) / 2;
817 cmp_val
= strcmp (msgid
, (domain
->data
818 + W (domain
->must_swap
,
819 domain
->orig_tab
[act
].offset
)));
822 else if (cmp_val
> 0)
827 /* No translation was found. */
832 /* The translation was found at index ACT. If we have to convert the
833 string to use a different character set, this is the time. */
837 (domain
->data
+ W (domain
->must_swap
, domain
->trans_tab
[act
].offset
));
838 resultlen
= W (domain
->must_swap
, domain
->trans_tab
[act
].length
) + 1;
842 result
= (char *) domain
->trans_sysdep_tab
[act
- nstrings
].pointer
;
843 resultlen
= domain
->trans_sysdep_tab
[act
- nstrings
].length
;
846 #if defined _LIBC || HAVE_ICONV
847 if (domain
->codeset_cntr
848 != (domainbinding
!= NULL
? domainbinding
->codeset_cntr
: 0))
850 /* The domain's codeset has changed through bind_textdomain_codeset()
851 since the message catalog was initialized or last accessed. We
852 have to reinitialize the converter. */
853 _nl_free_domain_conv (domain
);
854 _nl_init_domain_conv (domain_file
, domain
, domainbinding
);
859 domain
->conv
!= (__gconv_t
) -1
862 domain
->conv
!= (iconv_t
) -1
867 /* We are supposed to do a conversion. First allocate an
868 appropriate table with the same structure as the table
869 of translations in the file, where we can put the pointers
870 to the converted strings in.
871 There is a slight complication with plural entries. They
872 are represented by consecutive NUL terminated strings. We
873 handle this case by converting RESULTLEN bytes, including
876 if (domain
->conv_tab
== NULL
877 && ((domain
->conv_tab
=
878 (char **) calloc (nstrings
+ domain
->n_sysdep_strings
,
881 /* Mark that we didn't succeed allocating a table. */
882 domain
->conv_tab
= (char **) -1;
884 if (__builtin_expect (domain
->conv_tab
== (char **) -1, 0))
885 /* Nothing we can do, no more memory. */
888 if (domain
->conv_tab
[act
] == NULL
)
890 /* We haven't used this string so far, so it is not
891 translated yet. Do this now. */
892 /* We use a bit more efficient memory handling.
893 We allocate always larger blocks which get used over
894 time. This is faster than many small allocations. */
895 __libc_lock_define_initialized (static, lock
)
896 # define INITIAL_BLOCK_SIZE 4080
897 static unsigned char *freemem
;
898 static size_t freemem_size
;
900 const unsigned char *inbuf
;
901 unsigned char *outbuf
;
904 transmem_block_t
*transmem_list
= NULL
;
907 __libc_lock_lock (lock
);
909 inbuf
= (const unsigned char *) result
;
910 outbuf
= freemem
+ sizeof (size_t);
915 transmem_block_t
*newmem
;
917 size_t non_reversible
;
920 if (freemem_size
< sizeof (size_t))
923 res
= __gconv (domain
->conv
,
924 &inbuf
, inbuf
+ resultlen
,
926 outbuf
+ freemem_size
- sizeof (size_t),
929 if (res
== __GCONV_OK
|| res
== __GCONV_EMPTY_INPUT
)
932 if (res
!= __GCONV_FULL_OUTPUT
)
934 __libc_lock_unlock (lock
);
941 const char *inptr
= (const char *) inbuf
;
942 size_t inleft
= resultlen
;
943 char *outptr
= (char *) outbuf
;
946 if (freemem_size
< sizeof (size_t))
949 outleft
= freemem_size
- sizeof (size_t);
950 if (iconv (domain
->conv
,
951 (ICONV_CONST
char **) &inptr
, &inleft
,
955 outbuf
= (unsigned char *) outptr
;
960 __libc_lock_unlock (lock
);
967 /* We must allocate a new buffer or resize the old one. */
968 if (malloc_count
> 0)
971 freemem_size
= malloc_count
* INITIAL_BLOCK_SIZE
;
972 newmem
= (transmem_block_t
*) realloc (transmem_list
,
976 transmem_list
= transmem_list
->next
;
979 struct transmem_list
*old
= transmem_list
;
981 transmem_list
= transmem_list
->next
;
989 freemem_size
= INITIAL_BLOCK_SIZE
;
990 newmem
= (transmem_block_t
*) malloc (freemem_size
);
992 if (__builtin_expect (newmem
== NULL
, 0))
996 __libc_lock_unlock (lock
);
1001 /* Add the block to the list of blocks we have to free
1003 newmem
->next
= transmem_list
;
1004 transmem_list
= newmem
;
1006 freemem
= newmem
->data
;
1007 freemem_size
-= offsetof (struct transmem_list
, data
);
1009 transmem_list
= newmem
;
1013 outbuf
= freemem
+ sizeof (size_t);
1016 /* We have now in our buffer a converted string. Put this
1017 into the table of conversions. */
1018 *(size_t *) freemem
= outbuf
- freemem
- sizeof (size_t);
1019 domain
->conv_tab
[act
] = (char *) freemem
;
1020 /* Shrink freemem, but keep it aligned. */
1021 freemem_size
-= outbuf
- freemem
;
1023 freemem
+= freemem_size
& (alignof (size_t) - 1);
1024 freemem_size
= freemem_size
& ~ (alignof (size_t) - 1);
1026 __libc_lock_unlock (lock
);
1029 /* Now domain->conv_tab[act] contains the translation of all
1030 the plural variants. */
1031 result
= domain
->conv_tab
[act
] + sizeof (size_t);
1032 resultlen
= *(size_t *) domain
->conv_tab
[act
];
1036 /* The result string is converted. */
1038 #endif /* _LIBC || HAVE_ICONV */
1040 *lengthp
= resultlen
;
1045 /* Look up a plural variant. */
1048 plural_lookup (domain
, n
, translation
, translation_len
)
1049 struct loaded_l10nfile
*domain
;
1050 unsigned long int n
;
1051 const char *translation
;
1052 size_t translation_len
;
1054 struct loaded_domain
*domaindata
= (struct loaded_domain
*) domain
->data
;
1055 unsigned long int index
;
1058 index
= plural_eval (domaindata
->plural
, n
);
1059 if (index
>= domaindata
->nplurals
)
1060 /* This should never happen. It means the plural expression and the
1061 given maximum value do not match. */
1064 /* Skip INDEX strings at TRANSLATION. */
1069 p
= __rawmemchr (p
, '\0');
1071 p
= strchr (p
, '\0');
1073 /* And skip over the NUL byte. */
1076 if (p
>= translation
+ translation_len
)
1077 /* This should never happen. It means the plural expression
1078 evaluated to a value larger than the number of variants
1079 available for MSGID1. */
1080 return (char *) translation
;
1086 /* Return string representation of locale CATEGORY. */
1089 category_to_name (category
)
1098 retval
= "LC_COLLATE";
1103 retval
= "LC_CTYPE";
1108 retval
= "LC_MONETARY";
1113 retval
= "LC_NUMERIC";
1123 retval
= "LC_MESSAGES";
1128 retval
= "LC_RESPONSE";
1133 /* This might not make sense but is perhaps better than any other
1139 /* If you have a better idea for a default value let me know. */
1147 /* Guess value of current locale from value of the environment variables. */
1150 guess_category_value (category
, categoryname
)
1152 const char *categoryname
;
1154 const char *language
;
1157 /* The highest priority value is the `LANGUAGE' environment
1158 variable. But we don't use the value if the currently selected
1159 locale is the C locale. This is a GNU extension. */
1160 language
= getenv ("LANGUAGE");
1161 if (language
!= NULL
&& language
[0] == '\0')
1164 /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1165 `LC_xxx', and `LANG'. On some systems this can be done by the
1166 `setlocale' function itself. */
1168 retval
= __current_locale_name (category
);
1170 retval
= _nl_locale_name (category
, categoryname
);
1173 /* Ignore LANGUAGE if the locale is set to "C" because
1174 1. "C" locale usually uses the ASCII encoding, and most international
1175 messages use non-ASCII characters. These characters get displayed
1176 as question marks (if using glibc's iconv()) or as invalid 8-bit
1177 characters (because other iconv()s refuse to convert most non-ASCII
1178 characters to ASCII). In any case, the output is ugly.
1179 2. The precise output of some programs in the "C" locale is specified
1180 by POSIX and should not depend on environment variables like
1181 "LANGUAGE". We allow such programs to use gettext(). */
1182 return language
!= NULL
&& strcmp (retval
, "C") != 0 ? language
: retval
;
1185 /* @@ begin of epilog @@ */
1187 /* We don't want libintl.a to depend on any other library. So we
1188 avoid the non-standard function stpcpy. In GNU C Library this
1189 function is available, though. Also allow the symbol HAVE_STPCPY
1191 #if !_LIBC && !HAVE_STPCPY
1197 while ((*dest
++ = *src
++) != '\0')
1203 #if !_LIBC && !HAVE_MEMPCPY
1205 mempcpy (dest
, src
, n
)
1210 return (void *) ((char *) memcpy (dest
, src
, n
) + n
);
1216 /* If we want to free all resources we have to do some work at
1218 libc_freeres_fn (free_mem
)
1222 while (_nl_domain_bindings
!= NULL
)
1224 struct binding
*oldp
= _nl_domain_bindings
;
1225 _nl_domain_bindings
= _nl_domain_bindings
->next
;
1226 if (oldp
->dirname
!= INTUSE(_nl_default_dirname
))
1227 /* Yes, this is a pointer comparison. */
1228 free (oldp
->dirname
);
1229 free (oldp
->codeset
);
1233 if (_nl_current_default_domain
!= _nl_default_default_domain
)
1234 /* Yes, again a pointer comparison. */
1235 free ((char *) _nl_current_default_domain
);
1237 /* Remove the search tree with the known translations. */
1238 __tdestroy (root
, free
);
1241 while (transmem_list
!= NULL
)
1243 old
= transmem_list
;
1244 transmem_list
= transmem_list
->next
;