/* Load needed message catalogs.
- Copyright (C) 1995-1999, 2000-2008 Free Software Foundation, Inc.
+ Copyright (C) 1995-1999, 2000-2004 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
/* Tell glibc's <string.h> to provide a prototype for mempcpy().
#ifdef _LIBC
# include "../locale/localeinfo.h"
-# include <not-cancel.h>
-#endif
-
-/* Handle multi-threaded applications. */
-#ifdef _LIBC
-# include <bits/libc-lock.h>
-#else
-# include "lock.h"
#endif
/* Provide fallback values for macros that ought to be defined in <inttypes.h>.
/* Rename the non ISO C functions. This is required by the standard
because some ISO C functions will require linking with this object
file and the name space must not be polluted. */
-# define open(name, flags) open_not_cancel_2 (name, flags)
-# define close(fd) close_not_cancel_no_status (fd)
-# define read(fd, buf, n) read_not_cancel (fd, buf, n)
-# define mmap(addr, len, prot, flags, fd, offset) \
- __mmap (addr, len, prot, flags, fd, offset)
-# define munmap(addr, len) __munmap (addr, len)
+# define open __open
+# define close __close
+# define read __read
+# define mmap __mmap
+# define munmap __munmap
#endif
/* For those losing systems which don't have `alloca' we have to add
return NULL;
}
+/* Initialize the codeset dependent parts of an opened message catalog.
+ Return the header entry. */
+const char *
+internal_function
+_nl_init_domain_conv (struct loaded_l10nfile *domain_file,
+ struct loaded_domain *domain,
+ struct binding *domainbinding)
+{
+ /* 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. */
+ char *nullentry;
+ size_t nullentrylen;
+
+ /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
+ domain->codeset_cntr =
+ (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
+#ifdef _LIBC
+ domain->conv = (__gconv_t) -1;
+#else
+# if HAVE_ICONV
+ domain->conv = (iconv_t) -1;
+# endif
+#endif
+ domain->conv_tab = NULL;
+
+ /* Get the header entry. */
+ nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
+
+ if (nullentry != NULL)
+ {
+#if defined _LIBC || HAVE_ICONV
+ const char *charsetstr;
+
+ charsetstr = strstr (nullentry, "charset=");
+ if (charsetstr != NULL)
+ {
+ size_t len;
+ char *charset;
+ const char *outcharset;
+
+ 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
+
+ /* The output charset should normally be determined by the
+ locale. But sometimes the locale is not used or not correctly
+ set up, so we provide a possibility for the user to override
+ this. Moreover, the value specified through
+ bind_textdomain_codeset overrides both. */
+ if (domainbinding != NULL && domainbinding->codeset != NULL)
+ outcharset = domainbinding->codeset;
+ else
+ {
+ outcharset = getenv ("OUTPUT_CHARSET");
+ if (outcharset == NULL || outcharset[0] == '\0')
+ {
+# ifdef _LIBC
+ outcharset = _NL_CURRENT (LC_CTYPE, CODESET);
+# else
+# if HAVE_ICONV
+ extern const char *locale_charset (void);
+ outcharset = locale_charset ();
+# endif
+# endif
+ }
+ }
+
+# ifdef _LIBC
+ /* We always want to use transliteration. */
+ outcharset = norm_add_slashes (outcharset, "TRANSLIT");
+ charset = norm_add_slashes (charset, NULL);
+ if (__gconv_open (outcharset, charset, &domain->conv,
+ GCONV_AVOID_NOCONV)
+ != __GCONV_OK)
+ domain->conv = (__gconv_t) -1;
+# else
+# if HAVE_ICONV
+ /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
+ we want to use transliteration. */
+# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
+ || _LIBICONV_VERSION >= 0x0105
+ if (strchr (outcharset, '/') == NULL)
+ {
+ char *tmp;
+
+ len = strlen (outcharset);
+ tmp = (char *) alloca (len + 10 + 1);
+ memcpy (tmp, outcharset, len);
+ memcpy (tmp + len, "//TRANSLIT", 10 + 1);
+ outcharset = tmp;
+
+ domain->conv = iconv_open (outcharset, charset);
+
+ freea (outcharset);
+ }
+ else
+# endif
+ domain->conv = iconv_open (outcharset, charset);
+# endif
+# endif
+
+ freea (charset);
+ }
+#endif /* _LIBC || HAVE_ICONV */
+ }
+
+ return nullentry;
+}
+
+/* Frees the codeset dependent parts of an opened message catalog. */
+void
+internal_function
+_nl_free_domain_conv (struct loaded_domain *domain)
+{
+ if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
+ free (domain->conv_tab);
+
+#ifdef _LIBC
+ if (domain->conv != (__gconv_t) -1)
+ __gconv_close (domain->conv);
+#else
+# if HAVE_ICONV
+ if (domain->conv != (iconv_t) -1)
+ iconv_close (domain->conv);
+# endif
+#endif
+}
+
/* Load the message catalogs specified by FILENAME. If it is no valid
message catalog do nothing. */
void
_nl_load_domain (struct loaded_l10nfile *domain_file,
struct binding *domainbinding)
{
- __libc_lock_define_initialized_recursive (static, lock)
- int fd = -1;
+ int fd;
size_t size;
#ifdef _LIBC
struct stat64 st;
struct loaded_domain *domain;
int revision;
const char *nullentry;
- size_t nullentrylen;
-
- __libc_lock_lock_recursive (lock);
- if (domain_file->decided != 0)
- {
- /* There are two possibilities:
-
- + this is the same thread calling again during this initialization
- via _nl_find_msg. We have initialized everything this call needs.
- + this is another thread which tried to initialize this object.
- Not necessary anymore since if the lock is available this
- is finished.
- */
- goto done;
- }
-
- domain_file->decided = -1;
+ domain_file->decided = 1;
domain_file->data = NULL;
/* Note that it would be useless to store domainbinding in domain_file
specification the locale file name is different for XPG and CEN
syntax. */
if (domain_file->filename == NULL)
- goto out;
+ return;
/* Try to open the addressed file. */
fd = open (domain_file->filename, O_RDONLY | O_BINARY);
if (fd == -1)
- goto out;
+ return;
/* We must know about the size of the file. */
if (
#endif
|| __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
|| __builtin_expect (size < sizeof (struct mo_file_header), 0))
- /* Something went wrong. */
- goto out;
+ {
+ /* Something went wrong. */
+ close (fd);
+ return;
+ }
#ifdef HAVE_MMAP
/* Now we are ready to load the file. If mmap() is available we try
{
/* mmap() call was successful. */
close (fd);
- fd = -1;
use_mmap = 1;
}
#endif
data = (struct mo_file_header *) malloc (size);
if (data == NULL)
- goto out;
+ return;
to_read = size;
read_ptr = (char *) data;
if (nb == -1 && errno == EINTR)
continue;
#endif
- goto out;
+ close (fd);
+ return;
}
read_ptr += nb;
to_read -= nb;
while (to_read > 0);
close (fd);
- fd = -1;
}
/* Using the magic number we can test whether it really is a message
else
#endif
free (data);
- goto out;
+ return;
}
domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
if (domain == NULL)
- goto out;
+ return;
domain_file->data = domain;
domain->data = (char *) data;
((char *) data
+ W (domain->must_swap, data->sysdep_segments_offset));
sysdep_segment_values =
- (const char **)
alloca (n_sysdep_segments * sizeof (const char *));
for (i = 0; i < n_sysdep_segments; i++)
{
for (i = 0; i < n_inmem_sysdep_strings; i++)
{
const char *msgid = inmem_orig_sysdep_tab[i].pointer;
- nls_uint32 hash_val = __hash_string (msgid);
+ nls_uint32 hash_val = hash_string (msgid);
nls_uint32 idx = hash_val % domain->hash_size;
nls_uint32 incr =
1 + (hash_val % (domain->hash_size - 2));
/* This is an invalid revision. */
invalid:
/* This is an invalid .mo file. */
- free (domain->malloced);
+ if (domain->malloced)
+ free (domain->malloced);
#ifdef HAVE_MMAP
if (use_mmap)
munmap ((caddr_t) data, size);
free (data);
free (domain);
domain_file->data = NULL;
- goto out;
+ return;
}
- /* No caches of converted translations so far. */
- domain->conversions = NULL;
- domain->nconversions = 0;
- gl_rwlock_init (domain->conversions_lock);
+ /* Now initialize the character set converter from the character set
+ the file is encoded with (found in the header entry) to the domain's
+ specified character set or the locale's character set. */
+ nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
- /* Get the header entry and look for a plural specification. */
-#ifdef IN_LIBGLOCALE
- nullentry =
- _nl_find_msg (domain_file, domainbinding, NULL, "", &nullentrylen);
-#else
- nullentry = _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
-#endif
+ /* Also look for a plural specification. */
EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
-
- out:
- if (fd != -1)
- close (fd);
-
- domain_file->decided = 1;
-
- done:
- __libc_lock_unlock_recursive (lock);
}
#ifdef _LIBC
void
-internal_function __libc_freeres_fn_section
+internal_function
_nl_unload_domain (struct loaded_domain *domain)
{
- size_t i;
-
if (domain->plural != &__gettext_germanic_plural)
- __gettext_free_exp ((struct expression *) domain->plural);
-
- for (i = 0; i < domain->nconversions; i++)
- {
- struct converted_domain *convd = &domain->conversions[i];
+ __gettext_free_exp (domain->plural);
- free (convd->encoding);
- if (convd->conv_tab != NULL && convd->conv_tab != (char **) -1)
- free (convd->conv_tab);
- if (convd->conv != (__gconv_t) -1)
- __gconv_close (convd->conv);
- }
- free (domain->conversions);
- __libc_rwlock_fini (domain->conversions_lock);
+ _nl_free_domain_conv (domain);
- free (domain->malloced);
+ if (domain->malloced)
+ free (domain->malloced);
# ifdef _POSIX_MAPPED_FILES
if (domain->use_mmap)