diff options
Diffstat (limited to 'intl')
-rw-r--r-- | intl/dcgettext.c | 103 | ||||
-rw-r--r-- | intl/gettextP.h | 12 | ||||
-rw-r--r-- | intl/loadinfo.h | 12 | ||||
-rw-r--r-- | intl/loadmsgcat.c | 55 |
4 files changed, 168 insertions, 14 deletions
diff --git a/intl/dcgettext.c b/intl/dcgettext.c index cc5299e460..0429cc904e 100644 --- a/intl/dcgettext.c +++ b/intl/dcgettext.c @@ -83,6 +83,10 @@ void free (); # include <locale.h> #endif +#if defined HAVE_SYS_PARAM_H || defined _LIBC +# include <sys/param.h> +#endif + #include "gettext.h" #include "gettextP.h" #ifdef _LIBC @@ -92,6 +96,11 @@ void free (); #endif #include "hash-string.h" +/* Thread safetyness. */ +#ifdef _LIBC +# include <bits/libc-lock.h> +#endif + /* @@ end of prolog @@ */ #ifdef _LIBC @@ -171,8 +180,6 @@ const char _nl_default_dirname[] = GNULOCALEDIR; struct binding *_nl_domain_bindings; /* Prototypes for local functions. */ -static char *find_msg PARAMS ((struct loaded_l10nfile *domain_file, - const char *msgid)) internal_function; static const char *category_to_name PARAMS ((int category)) internal_function; static const char *guess_category_value PARAMS ((int category, const char *categoryname)) @@ -396,7 +403,7 @@ DCGETTEXT (domainname, msgid, category) if (domain != NULL) { - retval = find_msg (domain, msgid); + retval = _nl_find_msg (domain, msgid); if (retval == NULL) { @@ -404,7 +411,7 @@ DCGETTEXT (domainname, msgid, category) for (cnt = 0; domain->successor[cnt] != NULL; ++cnt) { - retval = find_msg (domain->successor[cnt], msgid); + retval = _nl_find_msg (domain->successor[cnt], msgid); if (retval != NULL) break; @@ -428,9 +435,9 @@ weak_alias (__dcgettext, dcgettext); #endif -static char * +char * internal_function -find_msg (domain_file, msgid) +_nl_find_msg (domain_file, msgid) struct loaded_l10nfile *domain_file; const char *msgid; { @@ -464,8 +471,88 @@ find_msg (domain_file, msgid) && strcmp (msgid, domain->data + W (domain->must_swap, domain->orig_tab[nstr - 1].offset)) == 0) - return (char *) domain->data + W (domain->must_swap, - domain->trans_tab[nstr - 1].offset); + { + /* We found an entry. If we have to convert the string to use + a different character set this is the time. */ + char *result = + (char *) domain->data + W (domain->must_swap, + domain->trans_tab[nstr - 1].offset); + + if ( +#if HAVE_ICONV || defined _LIBC + domain->conv != (iconv_t) -1 +#endif + ) + { + /* We are supposed to do a conversion. First allocate an + appropriate table with the same structure as the hash + table in the file where we can put the pointers to the + converted strings in. */ + if (domain->conv_tab == NULL + && ((domain->conv_tab = (char **) calloc (domain->hash_size, + sizeof (char *))) + == NULL)) + /* Mark that we didn't succeed allocating a table. */ + domain->conv_tab = (char **) -1; + + if (domain->conv_tab == (char **) -1) + /* Nothing we can do, no more memory. */ + return NULL; + + if (domain->conv_tab[idx] == NULL) + { + /* We haven't used this string so far, so it is not + translated yet. Do this now. */ +#ifdef _LIBC + /* For glibc we use a bit more efficient memory handling. + We allocate always larger blocks which get used over + time. This is faster than many small allocations. */ + __libc_lock_define_initialized (static, lock) + static char *freemem; + static size_t freemem_size; + /* Note that we include the NUL byte. */ + size_t resultlen = strlen (result) + 1; + const char *inbuf = result; + size_t inbytesleft = resultlen; + char *outbuf = freemem; + size_t outbytesleft = freemem_size; + + __libc_lock_lock (lock); + + while (iconv (domain->conv, &inbuf, &inbytesleft, &outbuf, + &outbytesleft) == (size_t) -1L) + { + if (errno != E2BIG) + goto out; + + /* We must resize the buffer. */ + freemem_size = MAX (2 * freemem_size, 4064); + freemem = (char *) malloc (freemem_size); + if (freemem == NULL) + goto out; + + inbuf = result; + inbytesleft = resultlen; + outbuf = freemem; + outbytesleft = freemem_size; + } + + /* We have now in our buffer a converted string. Put this + in the hash table */ + domain->conv_tab[idx] = freemem; + freemem = outbuf; + freemem_size = outbytesleft; + + out: + __libc_lock_unlock (lock); +#endif + } + + result = domain->conv_tab[idx]; + } + + return result; + } while (1) { diff --git a/intl/gettextP.h b/intl/gettextP.h index bcbe2720a7..bea4404167 100644 --- a/intl/gettextP.h +++ b/intl/gettextP.h @@ -1,6 +1,6 @@ /* Header describing internals of gettext library - Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. - Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. + Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + Written by Ulrich Drepper <drepper@cygnus.com>, 1995. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -20,6 +20,10 @@ #ifndef _GETTEXTP_H #define _GETTEXTP_H +#if defined HAVE_ICONV || defined _LIBC +# include <iconv.h> +#endif + #include "loadinfo.h" /* @@ end of prolog @@ */ @@ -67,6 +71,10 @@ struct loaded_domain struct string_desc *trans_tab; nls_uint32 hash_size; nls_uint32 *hash_tab; +#if defined HAVE_ICONV || defined _LIBC + iconv_t conv; +#endif + char **conv_tab; }; struct binding diff --git a/intl/loadinfo.h b/intl/loadinfo.h index 35d98f0d9b..ea1bf05806 100644 --- a/intl/loadinfo.h +++ b/intl/loadinfo.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. @@ -17,6 +17,9 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef _LOADINFO_H +#define _LOADINFO_H 1 + #ifndef PARAMS # if __STDC__ # define PARAMS(args) args @@ -77,3 +80,10 @@ extern int _nl_explode_name PARAMS ((char *name, const char **language, const char **revision)); extern char *_nl_find_language PARAMS ((const char *name)); + + +extern char *_nl_find_msg PARAMS ((struct loaded_l10nfile *domain_file, + const char *msgid)) + internal_function; + +#endif /* loadinfo.h */ diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c index 76887e8b4f..23d738882b 100644 --- a/intl/loadmsgcat.c +++ b/intl/loadmsgcat.c @@ -31,10 +31,23 @@ # include <stdlib.h> #endif +#if defined HAVE_STRING_H || defined _LIBC +# ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +# endif +# include <string.h> +#else +# include <strings.h> +#endif + #if defined HAVE_UNISTD_H || defined _LIBC # include <unistd.h> #endif +#ifdef _LIBC +# include <langinfo.h> +#endif + #if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \ || (defined _LIBC && defined _POSIX_MAPPED_FILES) # include <sys/mman.h> @@ -47,6 +60,10 @@ #include "gettext.h" #include "gettextP.h" +#ifdef _LIBC +# include "../locale/localeinfo.h" +#endif + /* @@ end of prolog @@ */ #ifdef _LIBC @@ -79,6 +96,7 @@ _nl_load_domain (domain_file) struct mo_file_header *data = (struct mo_file_header *) -1; int use_mmap = 0; struct loaded_domain *domain; + char *nullentry; domain_file->decided = 1; domain_file->data = NULL; @@ -200,9 +218,40 @@ _nl_load_domain (domain_file) return; } - /* Show that one domain is changed. This might make some cached - translations invalid. */ - ++_nl_msg_cat_cntr; + /* Now find out about the character set the file is encoded with. + This can be found (in textual form) in the entry "". If this + entry does not exist or if this does not contain the `charset=' + information, we will assume the charset matches the one the + current locale and we don't have to perform any conversion. */ +#if HAVE_ICONV || defined _LIBC + domain->conv = (iconv_t) -1; +#endif + nullentry = _nl_find_msg (domain_file, ""); + if (nullentry != NULL) + { + char *charsetstr = strstr (nullentry, "charset="); + + if (charsetstr != NULL) + { + size_t len; + char *charset; + + charsetstr += strlen ("charset="); + len = strcspn (charsetstr, " \t\n"); + + charset = (char *) alloca (len + 1); +#if defined _LIBC || HAVE_MEMPCPY + *((char *) mempcpy (charset, charsetstr, len)) = '\0'; +#else + memcpy (charset, charsetstr, len); + charset[len] = '\0'; +#endif + +#if HAVE_ICONV || defined _LIBC + domain->conv = iconv_open ((*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string, charset); +#endif + } + } } |