1 /* Implementation of the internal dcigettext function.
2 Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
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)
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.
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,
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. */
23 # define _GNU_SOURCE 1
30 #include <sys/types.h>
33 # define alloca __builtin_alloca
34 # define HAVE_ALLOCA 1
36 # if defined HAVE_ALLOCA_H || defined _LIBC
54 # define __set_errno(val) errno = (val)
61 #if !HAVE_STRCHR && !defined _LIBC
67 #if defined HAVE_UNISTD_H || defined _LIBC
73 #if defined HAVE_SYS_PARAM_H || defined _LIBC
74 # include <sys/param.h>
81 # include "libgnuintl.h"
83 #include "hash-string.h"
85 /* Thread safetyness. */
87 # include <bits/libc-lock.h>
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)
98 /* Alignment of types. */
99 #if defined __GNUC__ && __GNUC__ >= 2
100 # define alignof(TYPE) __alignof__ (TYPE)
102 # define alignof(TYPE) \
103 ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
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. */
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__
116 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
118 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
121 /* @@ end of prolog @@ */
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
130 # define stpcpy __stpcpy
132 # define tfind __tfind
134 # if !defined HAVE_GETCWD
136 # define getcwd(buf, max) getwd (buf)
138 # if !defined HAVE_DECL_GETCWD
143 static char *stpcpy
PARAMS ((char *dest
, const char *src
));
145 # ifndef HAVE_MEMPCPY
146 static void *mempcpy
PARAMS ((void *dest
, const void *src
, size_t n
));
150 /* Amount to increase buffer size by in each try. */
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__)
161 #ifndef _POSIX_PATH_MAX
162 # define _POSIX_PATH_MAX 255
165 #if !defined PATH_MAX && defined _PC_PATH_MAX
166 # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
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>
174 #if !defined PATH_MAX && defined MAXPATHLEN
175 # define PATH_MAX MAXPATHLEN
179 # define PATH_MAX _POSIX_PATH_MAX
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.
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')) \
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))
199 # define ISSLASH(C) ((C) == '/')
200 # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
201 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
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
214 /* This is the type used for the search tree where known translations
216 struct known_translation_t
218 /* Domain in which to search. */
224 /* State of the catalog counter at the point the string was found. */
227 /* Catalog where the string was found. */
228 struct loaded_l10nfile
*domain
;
230 /* And finally the translation. */
231 const char *translation
;
232 size_t translation_length
;
234 /* Pointer to the string in question. */
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
246 # define tsearch __tsearch
249 /* Function to compare two entries in the table of known translations. */
250 static int transcmp
PARAMS ((const void *p1
, const void *p2
));
256 const struct known_translation_t
*s1
;
257 const struct known_translation_t
*s2
;
260 s1
= (const struct known_translation_t
*) p1
;
261 s2
= (const struct known_translation_t
*) p2
;
263 result
= strcmp (s1
->msgid
, s2
->msgid
);
266 result
= strcmp (s1
->domainname
, s2
->domainname
);
268 /* We compare the category last (though this is the cheapest
269 operation) since it is hopefully always the same (namely
271 result
= s1
->category
- s2
->category
;
278 /* Name of the default domain used for gettext(3) prior any call to
279 textdomain(3). The default value for this is "messages". */
280 const char _nl_default_default_domain
[] = "messages";
282 /* Value used as the default domain for gettext(3). */
283 const char *_nl_current_default_domain
= _nl_default_default_domain
;
285 /* Contains the default location of the message catalogs. */
286 const char _nl_default_dirname
[] = LOCALEDIR
;
288 /* List with bindings of specific domains created by bindtextdomain()
290 struct binding
*_nl_domain_bindings
;
292 /* Prototypes for local functions. */
293 static char *plural_lookup
PARAMS ((struct loaded_l10nfile
*domain
,
295 const char *translation
,
296 size_t translation_len
))
298 static unsigned long int plural_eval
PARAMS ((struct expression
*pexp
,
299 unsigned long int n
))
301 static const char *category_to_name
PARAMS ((int category
)) internal_function
;
302 static const char *guess_category_value
PARAMS ((int category
,
303 const char *categoryname
))
307 /* For those loosing systems which don't have `alloca' we have to add
308 some additional code emulating it. */
310 /* Nothing has to be done. */
311 # define ADD_BLOCK(list, address) /* nothing */
312 # define FREE_BLOCKS(list) /* nothing */
317 struct block_list
*next
;
319 # define ADD_BLOCK(list, addr) \
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 \
324 if (newp != NULL) { \
325 newp->address = (addr); \
326 newp->next = (list); \
330 # define FREE_BLOCKS(list) \
332 while (list != NULL) { \
333 struct block_list *old = list; \
339 # define alloca(size) (malloc (size))
340 #endif /* have alloca */
344 /* List of blocks allocated for translations. */
345 typedef struct transmem_list
347 struct transmem_list
*next
;
350 static struct transmem_list
*transmem_list
;
352 typedef unsigned char transmem_block_t
;
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. */
361 # define DCIGETTEXT __dcigettext
363 # define DCIGETTEXT dcigettext__
366 /* Lock variable to protect the global data in the gettext implementation. */
368 __libc_rwlock_define_initialized (, _nl_state_lock
)
371 /* Checking whether the binaries runs SUID must be done and glibc provides
372 easier methods therefore we make a difference here. */
374 # define ENABLE_SECURE __libc_enable_secure
375 # define DETERMINE_SECURE
383 # ifndef HAVE_GETEUID
384 # define geteuid() getuid()
386 # ifndef HAVE_GETEGID
387 # define getegid() getgid()
389 static int enable_secure
;
390 # define ENABLE_SECURE (enable_secure == 1)
391 # define DETERMINE_SECURE \
392 if (enable_secure == 0) \
394 if (getuid () != geteuid () || getgid () != getegid ()) \
397 enable_secure = -1; \
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. */
405 DCIGETTEXT (domainname
, msgid1
, msgid2
, plural
, n
, category
)
406 const char *domainname
;
414 struct block_list
*block_list
= NULL
;
416 struct loaded_l10nfile
*domain
;
417 struct binding
*binding
;
418 const char *categoryname
;
419 const char *categoryvalue
;
420 char *dirname
, *xdomainname
;
425 #if defined HAVE_TSEARCH || defined _LIBC
426 struct known_translation_t
*search
;
427 struct known_translation_t
**foundp
= NULL
;
430 size_t domainname_len
;
432 /* If no real MSGID is given return NULL. */
436 __libc_rwlock_rdlock (_nl_state_lock
);
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
;
444 #if defined HAVE_TSEARCH || defined _LIBC
445 msgid_len
= strlen (msgid1
) + 1;
447 /* Try to find the translation among those which we found at
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
;
455 foundp
= (struct known_translation_t
**) tfind (search
, &root
, transcmp
);
456 if (foundp
!= NULL
&& (*foundp
)->counter
== _nl_msg_cat_cntr
)
458 /* Now deal with plural. */
460 retval
= plural_lookup ((*foundp
)->domain
, n
, (*foundp
)->translation
,
461 (*foundp
)->translation_length
);
463 retval
= (char *) (*foundp
)->translation
;
465 __libc_rwlock_unlock (_nl_state_lock
);
470 /* Preserve the `errno' value. */
473 /* See whether this is a SUID binary or not. */
476 /* First find matching binding. */
477 for (binding
= _nl_domain_bindings
; binding
!= NULL
; binding
= binding
->next
)
479 int compare
= strcmp (domainname
, binding
->domainname
);
485 /* It is not in the list. */
492 dirname
= (char *) _nl_default_dirname
;
493 else if (IS_ABSOLUTE_PATH (binding
->dirname
))
494 dirname
= binding
->dirname
;
497 /* We have a relative path. Make it absolute now. */
498 size_t dirname_len
= strlen (binding
->dirname
) + 1;
502 path_max
= (unsigned int) PATH_MAX
;
503 path_max
+= 2; /* The getcwd docs say to do this. */
507 dirname
= (char *) alloca (path_max
+ dirname_len
);
508 ADD_BLOCK (block_list
, dirname
);
511 ret
= getcwd (dirname
, path_max
);
512 if (ret
!= NULL
|| errno
!= ERANGE
)
515 path_max
+= path_max
/ 2;
516 path_max
+= PATH_INCR
;
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
);
528 /* Use the Germanic plural rule. */
529 : n
== 1 ? (char *) msgid1
: (char *) msgid2
);
532 stpcpy (stpcpy (strchr (dirname
, '\0'), "/"), binding
->dirname
);
535 /* Now determine the symbolic name of CATEGORY and its value. */
536 categoryname
= category_to_name (category
);
537 categoryvalue
= guess_category_value (category
, categoryname
);
539 domainname_len
= strlen (domainname
);
540 xdomainname
= (char *) alloca (strlen (categoryname
)
541 + domainname_len
+ 5);
542 ADD_BLOCK (block_list
, xdomainname
);
544 stpcpy (mempcpy (stpcpy (stpcpy (xdomainname
, categoryname
), "/"),
545 domainname
, domainname_len
),
548 /* Creating working area. */
549 single_locale
= (char *) alloca (strlen (categoryvalue
) + 1);
550 ADD_BLOCK (block_list
, single_locale
);
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. */
557 /* Make CATEGORYVALUE point to the next element of the list. */
558 while (categoryvalue
[0] != '\0' && categoryvalue
[0] == ':')
560 if (categoryvalue
[0] == '\0')
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
566 single_locale
[0] = 'C';
567 single_locale
[1] = '\0';
571 char *cp
= single_locale
;
572 while (categoryvalue
[0] != '\0' && categoryvalue
[0] != ':')
573 *cp
++ = *categoryvalue
++;
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. */
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)
588 FREE_BLOCKS (block_list
);
589 __libc_rwlock_unlock (_nl_state_lock
);
590 __set_errno (saved_errno
);
593 /* Use the Germanic plural rule. */
594 : n
== 1 ? (char *) msgid1
: (char *) msgid2
);
598 /* Find structure describing the message catalog matching the
599 DOMAINNAME and CATEGORY. */
600 domain
= _nl_find_domain (dirname
, single_locale
, xdomainname
, binding
);
604 retval
= _nl_find_msg (domain
, binding
, msgid1
, &retlen
);
610 for (cnt
= 0; domain
->successor
[cnt
] != NULL
; ++cnt
)
612 retval
= _nl_find_msg (domain
->successor
[cnt
], binding
,
617 domain
= domain
->successor
[cnt
];
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
632 /* Create a new entry and add it to the search tree. */
633 struct known_translation_t
*newp
;
635 newp
= (struct known_translation_t
*)
636 malloc (offsetof (struct known_translation_t
, msgid
)
637 + msgid_len
+ domainname_len
+ 1);
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
;
649 /* Insert the entry in the search tree. */
650 foundp
= (struct known_translation_t
**)
651 tsearch (newp
, &root
, transcmp
);
653 || __builtin_expect (*foundp
!= newp
, 0))
654 /* The insert failed. */
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
;
667 /* Now deal with plural. */
669 retval
= plural_lookup (domain
, n
, retval
, retlen
);
671 __libc_rwlock_unlock (_nl_state_lock
);
682 _nl_find_msg (domain_file
, domainbinding
, msgid
, lengthp
)
683 struct loaded_l10nfile
*domain_file
;
684 struct binding
*domainbinding
;
688 struct loaded_domain
*domain
;
693 if (domain_file
->decided
== 0)
694 _nl_load_domain (domain_file
, domainbinding
);
696 if (domain_file
->data
== NULL
)
699 domain
= (struct loaded_domain
*) domain_file
->data
;
701 /* Locate the MSGID and its translation. */
702 if (domain
->hash_size
> 2 && domain
->hash_tab
!= NULL
)
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));
712 nls_uint32 nstr
= W (domain
->must_swap
, domain
->hash_tab
[idx
]);
715 /* Hash table entry is empty. */
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
723 domain
->data
+ W (domain
->must_swap
,
724 domain
->orig_tab
[nstr
- 1].offset
))
731 if (idx
>= domain
->hash_size
- incr
)
732 idx
-= domain
->hash_size
- incr
;
740 /* Try the default method: binary search in the sorted array of
746 top
= domain
->nstrings
;
751 act
= (bottom
+ top
) / 2;
752 cmp_val
= strcmp (msgid
, (domain
->data
753 + W (domain
->must_swap
,
754 domain
->orig_tab
[act
].offset
)));
757 else if (cmp_val
> 0)
762 /* No translation was 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;
773 #if defined _LIBC || HAVE_ICONV
774 if (domain
->codeset_cntr
775 != (domainbinding
!= NULL
? domainbinding
->codeset_cntr
: 0))
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
);
786 domain
->conv
!= (__gconv_t
) -1
789 domain
->conv
!= (iconv_t
) -1
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
803 if (domain
->conv_tab
== NULL
804 && ((domain
->conv_tab
= (char **) calloc (domain
->nstrings
,
807 /* Mark that we didn't succeed allocating a table. */
808 domain
->conv_tab
= (char **) -1;
810 if (__builtin_expect (domain
->conv_tab
== (char **) -1, 0))
811 /* Nothing we can do, no more memory. */
814 if (domain
->conv_tab
[act
] == NULL
)
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
;
826 const unsigned char *inbuf
;
827 unsigned char *outbuf
;
830 transmem_block_t
*transmem_list
= NULL
;
833 __libc_lock_lock (lock
);
835 inbuf
= (const unsigned char *) result
;
836 outbuf
= freemem
+ sizeof (size_t);
841 transmem_block_t
*newmem
;
843 size_t non_reversible
;
846 if (freemem_size
< sizeof (size_t))
849 res
= __gconv (domain
->conv
,
850 &inbuf
, inbuf
+ resultlen
,
852 outbuf
+ freemem_size
- sizeof (size_t),
855 if (res
== __GCONV_OK
|| res
== __GCONV_EMPTY_INPUT
)
858 if (res
!= __GCONV_FULL_OUTPUT
)
860 __libc_lock_unlock (lock
);
867 const char *inptr
= (const char *) inbuf
;
868 size_t inleft
= resultlen
;
869 char *outptr
= (char *) outbuf
;
872 if (freemem_size
< sizeof (size_t))
875 outleft
= freemem_size
- sizeof (size_t);
876 if (iconv (domain
->conv
,
877 (ICONV_CONST
char **) &inptr
, &inleft
,
881 outbuf
= (unsigned char *) outptr
;
886 __libc_lock_unlock (lock
);
893 /* We must allocate a new buffer or resize the old one. */
894 if (malloc_count
> 0)
897 freemem_size
= malloc_count
* INITIAL_BLOCK_SIZE
;
898 newmem
= (transmem_block_t
*) realloc (transmem_list
,
902 transmem_list
= transmem_list
->next
;
905 struct transmem_list
*old
= transmem_list
;
907 transmem_list
= transmem_list
->next
;
915 freemem_size
= INITIAL_BLOCK_SIZE
;
916 newmem
= (transmem_block_t
*) malloc (freemem_size
);
918 if (__builtin_expect (newmem
== NULL
, 0))
922 __libc_lock_unlock (lock
);
927 /* Add the block to the list of blocks we have to free
929 newmem
->next
= transmem_list
;
930 transmem_list
= newmem
;
932 freemem
= newmem
->data
;
933 freemem_size
-= offsetof (struct transmem_list
, data
);
935 transmem_list
= newmem
;
939 outbuf
= freemem
+ sizeof (size_t);
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
;
949 freemem
+= freemem_size
& (alignof (size_t) - 1);
950 freemem_size
= freemem_size
& ~ (alignof (size_t) - 1);
952 __libc_lock_unlock (lock
);
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
];
962 /* The result string is converted. */
964 #endif /* _LIBC || HAVE_ICONV */
966 *lengthp
= resultlen
;
971 /* Look up a plural variant. */
974 plural_lookup (domain
, n
, translation
, translation_len
)
975 struct loaded_l10nfile
*domain
;
977 const char *translation
;
978 size_t translation_len
;
980 struct loaded_domain
*domaindata
= (struct loaded_domain
*) domain
->data
;
981 unsigned long int index
;
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. */
990 /* Skip INDEX strings at TRANSLATION. */
995 p
= __rawmemchr (p
, '\0');
997 p
= strchr (p
, '\0');
999 /* And skip over the NUL byte. */
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
;
1012 /* Function to evaluate the plural expression and return an index value. */
1013 static unsigned long int
1015 plural_eval (pexp
, n
)
1016 struct expression
*pexp
;
1017 unsigned long int n
;
1019 switch (pexp
->nargs
)
1022 switch (pexp
->operation
)
1027 return pexp
->val
.num
;
1035 /* pexp->operation must be lnot. */
1036 unsigned long int arg
= plural_eval (pexp
->val
.args
[0], n
);
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
);
1048 unsigned long int rightarg
= plural_eval (pexp
->val
.args
[1], n
);
1050 switch (pexp
->operation
)
1053 return leftarg
* rightarg
;
1055 return leftarg
/ rightarg
;
1057 return leftarg
% rightarg
;
1059 return leftarg
+ rightarg
;
1061 return leftarg
- rightarg
;
1063 return leftarg
< rightarg
;
1065 return leftarg
> rightarg
;
1067 return leftarg
<= rightarg
;
1068 case greater_or_equal
:
1069 return leftarg
>= rightarg
;
1071 return leftarg
== rightarg
;
1073 return leftarg
!= rightarg
;
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
);
1093 /* Return string representation of locale CATEGORY. */
1096 category_to_name (category
)
1105 retval
= "LC_COLLATE";
1110 retval
= "LC_CTYPE";
1115 retval
= "LC_MONETARY";
1120 retval
= "LC_NUMERIC";
1130 retval
= "LC_MESSAGES";
1135 retval
= "LC_RESPONSE";
1140 /* This might not make sense but is perhaps better than any other
1146 /* If you have a better idea for a default value let me know. */
1153 /* Guess value of current locale from value of the environment variables. */
1156 guess_category_value (category
, categoryname
)
1158 const char *categoryname
;
1160 const char *language
;
1162 (void) category
; /* shut up compiler */
1163 (void) categoryname
; /* ditto */
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')
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
);
1178 /* Setting of LC_ALL overwrites all other. */
1179 retval
= getenv ("LC_ALL");
1180 if (retval
== NULL
|| retval
[0] == '\0')
1182 /* Next comes the name of the desired category. */
1183 retval
= getenv (categoryname
);
1184 if (retval
== NULL
|| retval
[0] == '\0')
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. */
1196 return language
!= NULL
&& strcmp (retval
, "C") != 0 ? language
: retval
;
1199 /* @@ begin of epilog @@ */
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
1205 #if !_LIBC && !HAVE_STPCPY
1211 while ((*dest
++ = *src
++) != '\0')
1217 #if !_LIBC && !HAVE_MEMPCPY
1219 mempcpy (dest
, src
, n
)
1224 return (void *) ((char *) memcpy (dest
, src
, n
) + n
);
1230 /* If we want to free all resources we have to do some work at
1232 static void __attribute__ ((unused
))
1237 while (_nl_domain_bindings
!= NULL
)
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
);
1248 if (_nl_current_default_domain
!= _nl_default_default_domain
)
1249 /* Yes, again a pointer comparison. */
1250 free ((char *) _nl_current_default_domain
);
1252 /* Remove the search tree with the known translations. */
1253 __tdestroy (root
, free
);
1256 while (transmem_list
!= NULL
)
1258 old
= transmem_list
;
1259 transmem_list
= transmem_list
->next
;
1264 text_set_element (__libc_subfreeres
, free_mem
);