]> git.deb.at Git - pkg/abook.git/blobdiff - intl/loadmsgcat.c
Merge remote-tracking branch 'upstream/master' into upstream
[pkg/abook.git] / intl / loadmsgcat.c
index bf883a37efafd7a26977c40bd688670b1faef289..99c51b4c5c2f69e719926ea311093738be42e563 100644 (file)
@@ -1,5 +1,5 @@
 /* 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
@@ -13,7 +13,7 @@
 
    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().
@@ -91,14 +91,6 @@ char *alloca ();
 
 #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>.
@@ -465,12 +457,11 @@ char *alloca ();
 /* 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
@@ -773,6 +764,144 @@ get_sysdep_segment_value (const char *name)
   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
@@ -780,8 +909,7 @@ internal_function
 _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;
@@ -793,24 +921,8 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
   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
@@ -822,12 +934,12 @@ _nl_load_domain (struct loaded_l10nfile *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 (
@@ -838,8 +950,11 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
 #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
@@ -851,7 +966,6 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
     {
       /* mmap() call was successful.  */
       close (fd);
-      fd = -1;
       use_mmap = 1;
     }
 #endif
@@ -865,7 +979,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
 
       data = (struct mo_file_header *) malloc (size);
       if (data == NULL)
-       goto out;
+       return;
 
       to_read = size;
       read_ptr = (char *) data;
@@ -878,7 +992,8 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
              if (nb == -1 && errno == EINTR)
                continue;
 #endif
-             goto out;
+             close (fd);
+             return;
            }
          read_ptr += nb;
          to_read -= nb;
@@ -886,7 +1001,6 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
       while (to_read > 0);
 
       close (fd);
-      fd = -1;
     }
 
   /* Using the magic number we can test whether it really is a message
@@ -901,12 +1015,12 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
       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;
@@ -976,7 +1090,6 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
                  ((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++)
                  {
@@ -1208,7 +1321,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
                    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));
@@ -1259,7 +1372,8 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
       /* 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);
@@ -1268,58 +1382,31 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
        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)