2005-03-22 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/glibc.git] / intl / dcigettext.c
index 84d72a7..75762ea 100644 (file)
@@ -1,5 +1,5 @@
 /* Implementation of the internal dcigettext function.
 /* Implementation of the internal dcigettext function.
-   Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1995-2002,2003,2004,2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -103,10 +103,10 @@ extern int errno;
    names than the internal variables in GNU libc, otherwise programs
    using libintl.a cannot be linked statically.  */
 #if !defined _LIBC
    names than the internal variables in GNU libc, otherwise programs
    using libintl.a cannot be linked statically.  */
 #if !defined _LIBC
-# define _nl_default_default_domain _nl_default_default_domain__
-# define _nl_current_default_domain _nl_current_default_domain__
-# define _nl_default_dirname _nl_default_dirname__
-# define _nl_domain_bindings _nl_domain_bindings__
+# define _nl_default_default_domain libintl_nl_default_default_domain
+# define _nl_current_default_domain libintl_nl_current_default_domain
+# define _nl_default_dirname libintl_nl_default_dirname
+# define _nl_domain_bindings libintl_nl_domain_bindings
 #endif
 
 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
 #endif
 
 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
@@ -238,13 +238,22 @@ transcmp (p1, p2)
 
 /* Name of the default domain used for gettext(3) prior any call to
    textdomain(3).  The default value for this is "messages".  */
 
 /* Name of the default domain used for gettext(3) prior any call to
    textdomain(3).  The default value for this is "messages".  */
-const char _nl_default_default_domain[] = "messages";
+const char _nl_default_default_domain[] attribute_hidden = "messages";
 
 /* Value used as the default domain for gettext(3).  */
 
 /* Value used as the default domain for gettext(3).  */
-const char *_nl_current_default_domain = _nl_default_default_domain;
+const char *_nl_current_default_domain attribute_hidden
+     = _nl_default_default_domain;
 
 /* Contains the default location of the message catalogs.  */
 
 /* Contains the default location of the message catalogs.  */
+
+#ifdef _LIBC
+extern const char _nl_default_dirname[];
+libc_hidden_proto (_nl_default_dirname)
+#endif
 const char _nl_default_dirname[] = LOCALEDIR;
 const char _nl_default_dirname[] = LOCALEDIR;
+#ifdef _LIBC
+libc_hidden_data_def (_nl_default_dirname)
+#endif
 
 /* List with bindings of specific domains created by bindtextdomain()
    calls.  */
 
 /* List with bindings of specific domains created by bindtextdomain()
    calls.  */
@@ -256,16 +265,22 @@ static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
                                    const char *translation,
                                    size_t translation_len))
      internal_function;
                                    const char *translation,
                                    size_t translation_len))
      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))
      internal_function;
 static const char *guess_category_value PARAMS ((int category,
                                                 const char *categoryname))
      internal_function;
+#ifdef _LIBC
+# include "../locale/localeinfo.h"
+# define category_to_name(category)    _nl_category_names[category]
+#else
+static const char *category_to_name PARAMS ((int category)) internal_function;
+#endif
 
 
 /* For those loosing systems which don't have `alloca' we have to add
    some additional code emulating it.  */
 #ifdef HAVE_ALLOCA
 /* Nothing has to be done.  */
 
 
 /* For those loosing systems which don't have `alloca' we have to add
    some additional code emulating it.  */
 #ifdef HAVE_ALLOCA
 /* Nothing has to be done.  */
+# define freea(p) /* nothing */
 # define ADD_BLOCK(list, address) /* nothing */
 # define FREE_BLOCKS(list) /* nothing */
 #else
 # define ADD_BLOCK(list, address) /* nothing */
 # define FREE_BLOCKS(list) /* nothing */
 #else
@@ -290,11 +305,13 @@ struct block_list
     while (list != NULL) {                                                   \
       struct block_list *old = list;                                         \
       list = list->next;                                                     \
     while (list != NULL) {                                                   \
       struct block_list *old = list;                                         \
       list = list->next;                                                     \
+      free (old->address);                                                   \
       free (old);                                                            \
     }                                                                        \
   } while (0)
 # undef alloca
 # define alloca(size) (malloc (size))
       free (old);                                                            \
     }                                                                        \
   } while (0)
 # undef alloca
 # define alloca(size) (malloc (size))
+# define freea(p) free (p)
 #endif /* have alloca */
 
 
 #endif /* have alloca */
 
 
@@ -318,12 +335,12 @@ typedef unsigned char transmem_block_t;
 #ifdef _LIBC
 # define DCIGETTEXT __dcigettext
 #else
 #ifdef _LIBC
 # define DCIGETTEXT __dcigettext
 #else
-# define DCIGETTEXT dcigettext__
+# define DCIGETTEXT libintl_dcigettext
 #endif
 
 /* Lock variable to protect the global data in the gettext implementation.  */
 #ifdef _LIBC
 #endif
 
 /* Lock variable to protect the global data in the gettext implementation.  */
 #ifdef _LIBC
-__libc_rwlock_define_initialized (, _nl_state_lock)
+__libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
 #endif
 
 /* Checking whether the binaries runs SUID must be done and glibc provides
 #endif
 
 /* Checking whether the binaries runs SUID must be done and glibc provides
@@ -332,6 +349,18 @@ __libc_rwlock_define_initialized (, _nl_state_lock)
 # define ENABLE_SECURE __libc_enable_secure
 # define DETERMINE_SECURE
 #else
 # define ENABLE_SECURE __libc_enable_secure
 # define DETERMINE_SECURE
 #else
+# ifndef HAVE_GETUID
+#  define getuid() 0
+# endif
+# ifndef HAVE_GETGID
+#  define getgid() 0
+# endif
+# ifndef HAVE_GETEUID
+#  define geteuid() getuid()
+# endif
+# ifndef HAVE_GETEGID
+#  define getegid() getgid()
+# endif
 static int enable_secure;
 # define ENABLE_SECURE (enable_secure == 1)
 # define DETERMINE_SECURE \
 static int enable_secure;
 # define ENABLE_SECURE (enable_secure == 1)
 # define DETERMINE_SECURE \
@@ -382,6 +411,15 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
   if (msgid1 == NULL)
     return NULL;
 
   if (msgid1 == NULL)
     return NULL;
 
+#ifdef _LIBC
+  if (category < 0 || category >= __LC_LAST || category == LC_ALL)
+    /* Bogus.  */
+    return (plural == 0
+           ? (char *) msgid1
+           /* Use the Germanic plural rule.  */
+           : n == 1 ? (char *) msgid1 : (char *) msgid2);
+#endif
+
   __libc_rwlock_rdlock (_nl_state_lock);
 
   /* If DOMAINNAME is NULL, we are interested in the default domain.  If
   __libc_rwlock_rdlock (_nl_state_lock);
 
   /* If DOMAINNAME is NULL, we are interested in the default domain.  If
@@ -401,7 +439,16 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
   search->domainname = (char *) domainname;
   search->category = category;
 
   search->domainname = (char *) domainname;
   search->category = category;
 
+  /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
+     tsearch calls can be fatal.  */
+  __libc_rwlock_define_initialized (static, tree_lock);
+  __libc_rwlock_rdlock (tree_lock);
+
   foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
   foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
+
+  __libc_rwlock_unlock (tree_lock);
+
+  freea (search);
   if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
     {
       /* Now deal with plural.  */
   if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
     {
       /* Now deal with plural.  */
@@ -451,16 +498,18 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
       path_max = (unsigned int) PATH_MAX;
       path_max += 2;           /* The getcwd docs say to do this.  */
 
       path_max = (unsigned int) PATH_MAX;
       path_max += 2;           /* The getcwd docs say to do this.  */
 
-      dirname = (char *) alloca (path_max + dirname_len);
-      ADD_BLOCK (block_list, dirname);
-
-      __set_errno (0);
-      while ((ret = getcwd (dirname, path_max)) == NULL && errno == ERANGE)
+      for (;;)
        {
        {
-         path_max += PATH_INCR;
          dirname = (char *) alloca (path_max + dirname_len);
          ADD_BLOCK (block_list, dirname);
          dirname = (char *) alloca (path_max + dirname_len);
          ADD_BLOCK (block_list, dirname);
+
          __set_errno (0);
          __set_errno (0);
+         ret = getcwd (dirname, path_max);
+         if (ret != NULL || errno != ERANGE)
+           break;
+
+         path_max += path_max / 2;
+         path_max += PATH_INCR;
        }
 
       if (ret == NULL)
        }
 
       if (ret == NULL)
@@ -572,7 +621,6 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
              /* Found the translation of MSGID1 in domain DOMAIN:
                 starting at RETVAL, RETLEN bytes.  */
              FREE_BLOCKS (block_list);
              /* Found the translation of MSGID1 in domain DOMAIN:
                 starting at RETVAL, RETLEN bytes.  */
              FREE_BLOCKS (block_list);
-             __set_errno (saved_errno);
 #if defined HAVE_TSEARCH || defined _LIBC
              if (foundp == NULL)
                {
 #if defined HAVE_TSEARCH || defined _LIBC
              if (foundp == NULL)
                {
@@ -593,9 +641,14 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
                      newp->translation = retval;
                      newp->translation_length = retlen;
 
                      newp->translation = retval;
                      newp->translation_length = retlen;
 
+                     __libc_rwlock_wrlock (tree_lock);
+
                      /* Insert the entry in the search tree.  */
                      foundp = (struct known_translation_t **)
                        tsearch (newp, &root, transcmp);
                      /* Insert the entry in the search tree.  */
                      foundp = (struct known_translation_t **)
                        tsearch (newp, &root, transcmp);
+
+                     __libc_rwlock_unlock (tree_lock);
+
                      if (foundp == NULL
                          || __builtin_expect (*foundp != newp, 0))
                        /* The insert failed.  */
                      if (foundp == NULL
                          || __builtin_expect (*foundp != newp, 0))
                        /* The insert failed.  */
@@ -611,6 +664,8 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
                  (*foundp)->translation_length = retlen;
                }
 #endif
                  (*foundp)->translation_length = retlen;
                }
 #endif
+             __set_errno (saved_errno);
+
              /* Now deal with plural.  */
              if (plural)
                retval = plural_lookup (domain, n, retval, retlen);
              /* Now deal with plural.  */
              if (plural)
                retval = plural_lookup (domain, n, retval, retlen);
@@ -633,11 +688,12 @@ _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
      size_t *lengthp;
 {
   struct loaded_domain *domain;
      size_t *lengthp;
 {
   struct loaded_domain *domain;
+  nls_uint32 nstrings;
   size_t act;
   char *result;
   size_t resultlen;
 
   size_t act;
   char *result;
   size_t resultlen;
 
-  if (domain_file->decided == 0)
+  if (domain_file->decided <= 0)
     _nl_load_domain (domain_file, domainbinding);
 
   if (domain_file->data == NULL)
     _nl_load_domain (domain_file, domainbinding);
 
   if (domain_file->data == NULL)
@@ -645,33 +701,43 @@ _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
 
   domain = (struct loaded_domain *) domain_file->data;
 
 
   domain = (struct loaded_domain *) domain_file->data;
 
+  nstrings = domain->nstrings;
+
   /* Locate the MSGID and its translation.  */
   /* Locate the MSGID and its translation.  */
-  if (domain->hash_size > 2 && domain->hash_tab != NULL)
+  if (domain->hash_tab != NULL)
     {
       /* Use the hashing table.  */
       nls_uint32 len = strlen (msgid);
     {
       /* Use the hashing table.  */
       nls_uint32 len = strlen (msgid);
-      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));
 
       while (1)
        {
       nls_uint32 idx = hash_val % domain->hash_size;
       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
 
       while (1)
        {
-         nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
+         nls_uint32 nstr =
+           W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
 
          if (nstr == 0)
            /* Hash table entry is empty.  */
            return NULL;
 
 
          if (nstr == 0)
            /* Hash table entry is empty.  */
            return NULL;
 
-         /* Compare msgid with the original string at index nstr-1.
+         nstr--;
+
+         /* Compare msgid with the original string at index nstr.
             We compare the lengths with >=, not ==, because plural entries
             are represented by strings with an embedded NUL.  */
             We compare the lengths with >=, not ==, because plural entries
             are represented by strings with an embedded NUL.  */
-         if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len
-             && (strcmp (msgid,
-                         domain->data + W (domain->must_swap,
-                                           domain->orig_tab[nstr - 1].offset))
-                 == 0))
+         if (nstr < nstrings
+             ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
+               && (strcmp (msgid,
+                           domain->data + W (domain->must_swap,
+                                             domain->orig_tab[nstr].offset))
+                   == 0)
+             : domain->orig_sysdep_tab[nstr - nstrings].length > len
+               && (strcmp (msgid,
+                           domain->orig_sysdep_tab[nstr - nstrings].pointer)
+                   == 0))
            {
            {
-             act = nstr - 1;
+             act = nstr;
              goto found;
            }
 
              goto found;
            }
 
@@ -689,7 +755,7 @@ _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
       size_t top, bottom;
 
       bottom = 0;
       size_t top, bottom;
 
       bottom = 0;
-      top = domain->nstrings;
+      top = nstrings;
       while (bottom < top)
        {
          int cmp_val;
       while (bottom < top)
        {
          int cmp_val;
@@ -712,9 +778,17 @@ _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
  found:
   /* The translation was found at index ACT.  If we have to convert the
      string to use a different character set, this is the time.  */
  found:
   /* The translation was found at index ACT.  If we have to convert the
      string to use a different character set, this is the time.  */
-  result = ((char *) domain->data
-           + W (domain->must_swap, domain->trans_tab[act].offset));
-  resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
+  if (act < nstrings)
+    {
+      result = (char *)
+       (domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
+      resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
+    }
+  else
+    {
+      result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
+      resultlen = domain->trans_sysdep_tab[act - nstrings].length;
+    }
 
 #if defined _LIBC || HAVE_ICONV
   if (domain->codeset_cntr
 
 #if defined _LIBC || HAVE_ICONV
   if (domain->codeset_cntr
@@ -747,8 +821,9 @@ _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
         NULs.  */
 
       if (domain->conv_tab == NULL
         NULs.  */
 
       if (domain->conv_tab == NULL
-         && ((domain->conv_tab = (char **) calloc (domain->nstrings,
-                                                   sizeof (char *)))
+         && ((domain->conv_tab =
+                (char **) calloc (nstrings + domain->n_sysdep_strings,
+                                  sizeof (char *)))
              == NULL))
        /* Mark that we didn't succeed allocating a table.  */
        domain->conv_tab = (char **) -1;
              == NULL))
        /* Mark that we didn't succeed allocating a table.  */
        domain->conv_tab = (char **) -1;
@@ -807,7 +882,7 @@ _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
                  goto converted;
                }
 
                  goto converted;
                }
 
-             inbuf = result;
+             inbuf = (const unsigned char *) result;
 # else
 #  if HAVE_ICONV
              const char *inptr = (const char *) inbuf;
 # else
 #  if HAVE_ICONV
              const char *inptr = (const char *) inbuf;
@@ -875,7 +950,7 @@ _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
              newmem->next = transmem_list;
              transmem_list = newmem;
 
              newmem->next = transmem_list;
              transmem_list = newmem;
 
-             freemem = newmem->data;
+             freemem = (unsigned char *) newmem->data;
              freemem_size -= offsetof (struct transmem_list, data);
 # else
              transmem_list = newmem;
              freemem_size -= offsetof (struct transmem_list, data);
 # else
              transmem_list = newmem;
@@ -954,7 +1029,7 @@ plural_lookup (domain, n, translation, translation_len)
   return (char *) p;
 }
 
   return (char *) p;
 }
 
-
+#ifndef _LIBC
 /* Return string representation of locale CATEGORY.  */
 static const char *
 internal_function
 /* Return string representation of locale CATEGORY.  */
 static const char *
 internal_function
@@ -1014,6 +1089,7 @@ category_to_name (category)
 
   return retval;
 }
 
   return retval;
 }
+#endif
 
 /* Guess value of current locale from value of the environment variables.  */
 static const char *
 
 /* Guess value of current locale from value of the environment variables.  */
 static const char *
@@ -1036,7 +1112,7 @@ guess_category_value (category, categoryname)
      `LC_xxx', and `LANG'.  On some systems this can be done by the
      `setlocale' function itself.  */
 #ifdef _LIBC
      `LC_xxx', and `LANG'.  On some systems this can be done by the
      `setlocale' function itself.  */
 #ifdef _LIBC
-  retval = setlocale (category, NULL);
+  retval = __current_locale_name (category);
 #else
   retval = _nl_locale_name (category, categoryname);
 #endif
 #else
   retval = _nl_locale_name (category, categoryname);
 #endif
@@ -1077,8 +1153,7 @@ mempcpy (dest, src, n)
 #ifdef _LIBC
 /* If we want to free all resources we have to do some work at
    program's end.  */
 #ifdef _LIBC
 /* If we want to free all resources we have to do some work at
    program's end.  */
-static void __attribute__ ((unused))
-free_mem (void)
+libc_freeres_fn (free_mem)
 {
   void *old;
 
 {
   void *old;
 
@@ -1108,6 +1183,4 @@ free_mem (void)
       free (old);
     }
 }
       free (old);
     }
 }
-
-text_set_element (__libc_subfreeres, free_mem);
 #endif
 #endif