bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

localename: Add support for per-thread locales on Solaris 11.4


From: Bruno Haible
Subject: localename: Add support for per-thread locales on Solaris 11.4
Date: Sun, 14 Oct 2018 17:17:03 +0200
User-agent: KMail/5.1.3 (Linux/4.4.0-137-generic; KDE/5.18.0; x86_64; ; )

Solaris 11.4 has added uselocale(), newlocale(), etc.
However, the data structure of locale_t does not contain the locale category
names. But this is essential for gettext() to work, when a per-thread
locale has been set! gettext() relies on the gnulib 'localename' module
for fetching the name of the LC_MESSAGES category. The way the Solaris
implementors designed it, the LC_MESSAGES category can *only* be used
to fetch the 'yesexpr' and 'noexpr' strings, *and nothing else*.

That's a design for minimum extensibility, when nowadays maximum
extensibility ought to be commonplace in programmers' thinking.

In order to overcome this, the 'localename' module has to keep its own
hash table (locale_t -> set of names, one per category). This, in turn,
requires overriding 'newlocale', 'duplocale', and 'freelocale'.

With this patch, test-localename passes on Solaris 11.4. Also tested on
all other platforms that have 'uselocale'.


2018-10-14  Bruno Haible  <address@hidden>

        localename: Add support for per-thread locales on Solaris 11.4.
        * lib/locale.in.h (newlocale, freelocale): New declarations.
        (duplocale): Declare also when the 'localename' module requests it.
        * lib/localename.c (struniq_hash_node): Renamed from hash_node.
        (STRUNIQ_HASH_TABLE_SIZE): Renamed from HASH_TABLE_SIZE.
        (struniq): Update.
        (struct locale_categories_names, struct locale_hash_node): New types.
        (LOCALE_HASH_TABLE_SIZE): New constant.
        (locale_hash_table, locale_lock): New variables.
        (pointer_hash, get_locale_t_name): New functions.
        (newlocale, duplocale, freelocale): New overridden functions.
        (gl_locale_name_thread_unsafe): Use get_locale_t_name.
        * m4/intlsolaris.m4: New file.
        * m4/localename.m4 (gl_LOCALENAME): Require gl_LOCALE_H_DEFAULTS. Invoke
        gt_INTL_SOLARIS. Set HAVE_NEWLOCALE, HAVE_DUPLOCALE, HAVE_FREELOCALE,
        REPLACE_NEWLOCALE, REPLACE_DUPLOCALE, REPLACE_FREELOCALE.
        * m4/locale_h.m4 (gl_LOCALE_H): Test whether newlocale, freelocale are
        declared.
        (gl_LOCALE_H_DEFAULTS): Initialize GNULIB_LOCALENAME, HAVE_NEWLOCALE,
        HAVE_FREELOCALE, REPLACE_NEWLOCALE, REPLACE_FREELOCALE.
        * modules/locale (Makefile.am): Substitute GNULIB_LOCALENAME,
        HAVE_NEWLOCALE, HAVE_FREELOCALE, REPLACE_NEWLOCALE, REPLACE_FREELOCALE.
        * modules/localename (Files): Add intlsolaris.m4.
        (Depends-on): Add 'locale'.
        (configure.ac): Invoke gl_LOCALE_MODULE_INDICATOR.
        * tests/test-locale-c++.cc (newlocale, freelocale): Prepare for checking
        the signatures.

diff --git a/lib/locale.in.h b/lib/locale.in.h
index 804261d..be11cee 100644
--- a/lib/locale.in.h
+++ b/lib/locale.in.h
@@ -190,7 +190,34 @@ _GL_WARN_ON_USE (setlocale, "setlocale works differently 
on native Windows - "
 # endif
 #endif
 
-#if @GNULIB_DUPLOCALE@
+#if /address@hidden@ ||*/ (@GNULIB_LOCALENAME@ && @HAVE_NEWLOCALE@)
+# if @REPLACE_NEWLOCALE@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef newlocale
+#   define newlocale rpl_newlocale
+#  endif
+_GL_FUNCDECL_RPL (newlocale, locale_t,
+                  (int category_mask, const char *name, locale_t base)
+                  _GL_ARG_NONNULL ((2)));
+_GL_CXXALIAS_RPL (newlocale, locale_t,
+                  (int category_mask, const char *name, locale_t base));
+# else
+#  if @HAVE_NEWLOCALE@
+_GL_CXXALIAS_SYS (newlocale, locale_t,
+                  (int category_mask, const char *name, locale_t base));
+#  endif
+# endif
+# if @HAVE_NEWLOCALE@
+_GL_CXXALIASWARN (newlocale);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef newlocale
+# if HAVE_RAW_DECL_NEWLOCALE
+_GL_WARN_ON_USE (newlocale, "newlocale is not portable");
+# endif
+#endif
+
+#if @GNULIB_DUPLOCALE@ || (@GNULIB_LOCALENAME@ && @HAVE_DUPLOCALE@)
 # if @REPLACE_DUPLOCALE@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   undef duplocale
@@ -214,6 +241,29 @@ _GL_WARN_ON_USE (duplocale, "duplocale is buggy on some 
glibc systems - "
 # endif
 #endif
 
+#if /address@hidden@ ||*/ (@GNULIB_LOCALENAME@ && @HAVE_FREELOCALE@)
+# if @REPLACE_FREELOCALE@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef freelocale
+#   define freelocale rpl_freelocale
+#  endif
+_GL_FUNCDECL_RPL (freelocale, void, (locale_t locale) _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (freelocale, void, (locale_t locale));
+# else
+#  if @HAVE_FREELOCALE@
+_GL_CXXALIAS_SYS (freelocale, void, (locale_t locale));
+#  endif
+# endif
+# if @HAVE_FREELOCALE@
+_GL_CXXALIASWARN (freelocale);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef freelocale
+# if HAVE_RAW_DECL_FREELOCALE
+_GL_WARN_ON_USE (freelocale, "freelocale is not portable");
+# endif
+#endif
+
 #endif /* address@hidden@_LOCALE_H */
 #endif /* address@hidden@_LOCALE_H */
 #endif /* !(__need_locale_t || _GL_ALREADY_INCLUDING_LOCALE_H) */
diff --git a/lib/localename.c b/lib/localename.c
index f9f9cc9..93fee9b 100644
--- a/lib/localename.c
+++ b/lib/localename.c
@@ -50,6 +50,10 @@
 /* Solaris >= 12.  */
 extern char * getlocalename_l(int, locale_t);
 # endif
+# if HAVE_NAMELESS_LOCALES
+#  include <errno.h>
+#  include <stdint.h>
+# endif
 #endif
 
 #if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
@@ -2615,7 +2619,7 @@ get_lcid (const char *locale_name)
 #endif
 
 
-#if HAVE_USELOCALE /* glibc, Mac OS X, Solaris 11 OpenIndiana, or Solaris 12  
*/
+#if HAVE_USELOCALE /* glibc, Mac OS X, Solaris 11 OpenIndiana, or Solaris >= 
11.4  */
 
 /* Simple hash set of strings.  We don't want to drag in lots of hash table
    code here.  */
@@ -2641,14 +2645,14 @@ string_hash (const void *x)
    simultaneously, but only one thread can insert into it at the same time.  */
 
 /* A node in a hash bucket collision list.  */
-struct hash_node
+struct struniq_hash_node
   {
-    struct hash_node * volatile next;
+    struct struniq_hash_node * volatile next;
     char contents[FLEXIBLE_ARRAY_MEMBER];
   };
 
-# define HASH_TABLE_SIZE 257
-static struct hash_node * volatile struniq_hash_table[HASH_TABLE_SIZE]
+# define STRUNIQ_HASH_TABLE_SIZE 257
+static struct struniq_hash_node * volatile 
struniq_hash_table[STRUNIQ_HASH_TABLE_SIZE]
   /* = { NULL, ..., NULL } */;
 
 /* This lock protects the struniq_hash_table against multiple simultaneous
@@ -2661,17 +2665,17 @@ static const char *
 struniq (const char *string)
 {
   size_t hashcode = string_hash (string);
-  size_t slot = hashcode % HASH_TABLE_SIZE;
+  size_t slot = hashcode % STRUNIQ_HASH_TABLE_SIZE;
   size_t size;
-  struct hash_node *new_node;
-  struct hash_node *p;
+  struct struniq_hash_node *new_node;
+  struct struniq_hash_node *p;
   for (p = struniq_hash_table[slot]; p != NULL; p = p->next)
     if (strcmp (p->contents, string) == 0)
       return p->contents;
   size = strlen (string) + 1;
   new_node =
-    (struct hash_node *)
-    malloc (FLEXSIZEOF (struct hash_node, contents, size));
+    (struct struniq_hash_node *)
+    malloc (FLEXSIZEOF (struct struniq_hash_node, contents, size));
   if (new_node == NULL)
     /* Out of memory.  Return a statically allocated string.  */
     return "C";
@@ -2700,6 +2704,421 @@ struniq (const char *string)
 #endif
 
 
+#if HAVE_USELOCALE && HAVE_NAMELESS_LOCALES /* Solaris >= 11.4 */
+
+/* The 'locale_t' object does not contain the names of the locale categories.
+   We have to associate them with the object through a hash table.  */
+
+struct locale_categories_names
+  {
+    /* Locale category -> name (allocated with indefinite extent).  */
+    const char *category_name[6];
+  };
+
+/* A hash function for pointers.  */
+static size_t _GL_ATTRIBUTE_CONST
+pointer_hash (const void *x)
+{
+  uintptr_t p = (uintptr_t) x;
+  size_t h = ((p % 4177) << 12) + ((p % 79) << 6) + (p % 61);
+  return h;
+}
+
+/* A hash table of fixed size.  Multiple threads can access it read-only
+   simultaneously, but only one thread can insert into it or remove from it
+   at the same time.  */
+
+/* A node in a hash bucket collision list.  */
+struct locale_hash_node
+  {
+    struct locale_hash_node *next;
+    locale_t locale;
+    struct locale_categories_names names;
+  };
+
+# define LOCALE_HASH_TABLE_SIZE 101
+static struct locale_hash_node * locale_hash_table[LOCALE_HASH_TABLE_SIZE]
+  /* = { NULL, ..., NULL } */;
+
+/* This lock protects the locale_hash_table against multiple simultaneous
+   accesses (except that multiple simultaneous read accesses are allowed).  */
+
+gl_rwlock_define_initialized(static, locale_lock)
+
+/* Returns the name of a given locale category in a given locale_t object,
+   allocated as a string with indefinite extent.  */
+static const char *
+get_locale_t_name (int category, locale_t locale)
+{
+  if (locale == LC_GLOBAL_LOCALE)
+    {
+      /* Query the global locale.  */
+      const char *name = setlocale (category, NULL);
+      if (name != NULL)
+        return struniq (name);
+      else
+        /* Should normally not happen.  */
+        return "";
+    }
+  else
+    {
+      /* Look up the names in the hash table.  */
+      size_t hashcode = pointer_hash (locale);
+      size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE;
+      /* If the locale was not found in the table, return "".  This can
+         happen if the application uses the original newlocale()/duplocale()
+         functions instead of the overridden ones.  */
+      const char *name = "";
+      struct locale_hash_node *p;
+      /* Lock while looking up the hash node.  */
+      gl_rwlock_rdlock (locale_lock);
+      for (p = locale_hash_table[slot]; p != NULL; p = p->next)
+        if (p->locale == locale)
+          {
+            name = p->names.category_name[category];
+            break;
+          }
+      gl_rwlock_unlock (locale_lock);
+      return name;
+    }
+}
+
+# if !(defined newlocale && defined duplocale && defined freelocale)
+#  error "newlocale, duplocale, freelocale not being replaced as expected!"
+# endif
+
+/* newlocale() override.  */
+locale_t
+newlocale (int category_mask, const char *name, locale_t base)
+#undef newlocale
+{
+  struct locale_categories_names names;
+  struct locale_hash_node *node;
+  locale_t result;
+
+  /* Make sure name has indefinite extent.  */
+  if (((LC_CTYPE_MASK | LC_NUMERIC_MASK | LC_TIME_MASK | LC_COLLATE_MASK
+        | LC_MONETARY_MASK | LC_MESSAGES_MASK)
+       & category_mask) != 0)
+    name = struniq (name);
+
+  /* Determine the category names of the result.  */
+  if (((LC_CTYPE_MASK | LC_NUMERIC_MASK | LC_TIME_MASK | LC_COLLATE_MASK
+        | LC_MONETARY_MASK | LC_MESSAGES_MASK)
+       & ~category_mask) == 0)
+    {
+      /* Use name, ignore base.  */
+      int category;
+
+      name = struniq (name);
+      for (category = 0; category < 6; category++)
+        names.category_name[category] = name;
+    }
+  else
+    {
+      /* Use base, possibly also name.  */
+      if (base == NULL)
+        {
+          int category;
+
+          for (category = 0; category < 6; category++)
+            {
+              int mask;
+
+              switch (category)
+                {
+                case LC_CTYPE:
+                  mask = LC_CTYPE_MASK;
+                  break;
+                case LC_NUMERIC:
+                  mask = LC_NUMERIC_MASK;
+                  break;
+                case LC_TIME:
+                  mask = LC_TIME_MASK;
+                  break;
+                case LC_COLLATE:
+                  mask = LC_COLLATE_MASK;
+                  break;
+                case LC_MONETARY:
+                  mask = LC_MONETARY_MASK;
+                  break;
+                case LC_MESSAGES:
+                  mask = LC_MESSAGES_MASK;
+                  break;
+                default:
+                  abort ();
+                }
+              names.category_name[category] =
+                ((mask & category_mask) != 0 ? name : "C");
+            }
+        }
+      else if (base == LC_GLOBAL_LOCALE)
+        {
+          int category;
+
+          for (category = 0; category < 6; category++)
+            {
+              int mask;
+
+              switch (category)
+                {
+                case LC_CTYPE:
+                  mask = LC_CTYPE_MASK;
+                  break;
+                case LC_NUMERIC:
+                  mask = LC_NUMERIC_MASK;
+                  break;
+                case LC_TIME:
+                  mask = LC_TIME_MASK;
+                  break;
+                case LC_COLLATE:
+                  mask = LC_COLLATE_MASK;
+                  break;
+                case LC_MONETARY:
+                  mask = LC_MONETARY_MASK;
+                  break;
+                case LC_MESSAGES:
+                  mask = LC_MESSAGES_MASK;
+                  break;
+                default:
+                  abort ();
+                }
+              names.category_name[category] =
+                ((mask & category_mask) != 0
+                 ? name
+                 : get_locale_t_name (category, LC_GLOBAL_LOCALE));
+            }
+        }
+      else
+        {
+          /* Look up the names of base in the hash table.  Like multiple calls
+             of get_locale_t_name, but locking only once.  */
+          struct locale_hash_node *p;
+          int category;
+
+          /* Lock while looking up the hash node.  */
+          gl_rwlock_rdlock (locale_lock);
+          for (p = locale_hash_table[pointer_hash (base) % 
LOCALE_HASH_TABLE_SIZE];
+               p != NULL;
+               p = p->next)
+            if (p->locale == base)
+              break;
+
+          for (category = 0; category < 6; category++)
+            {
+              int mask;
+
+              switch (category)
+                {
+                case LC_CTYPE:
+                  mask = LC_CTYPE_MASK;
+                  break;
+                case LC_NUMERIC:
+                  mask = LC_NUMERIC_MASK;
+                  break;
+                case LC_TIME:
+                  mask = LC_TIME_MASK;
+                  break;
+                case LC_COLLATE:
+                  mask = LC_COLLATE_MASK;
+                  break;
+                case LC_MONETARY:
+                  mask = LC_MONETARY_MASK;
+                  break;
+                case LC_MESSAGES:
+                  mask = LC_MESSAGES_MASK;
+                  break;
+                default:
+                  abort ();
+                }
+              names.category_name[category] =
+                ((mask & category_mask) != 0
+                 ? name
+                 : (p != NULL ? p->names.category_name[category] : ""));
+            }
+
+          gl_rwlock_unlock (locale_lock);
+        }
+    }
+
+  node = (struct locale_hash_node *) malloc (sizeof (struct locale_hash_node));
+  if (node == NULL)
+    /* errno is set to ENOMEM.  */
+    return NULL;
+
+  result = newlocale (category_mask, name, base);
+  if (result == NULL)
+    {
+      int saved_errno = errno;
+      free (node);
+      errno = saved_errno;
+      return NULL;
+    }
+
+  /* Fill the hash node.  */
+  node->locale = result;
+  node->names = names;
+
+  /* Insert it in the hash table.  */
+  {
+    size_t hashcode = pointer_hash (result);
+    size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE;
+    struct locale_hash_node *p;
+
+    /* Lock while inserting the new node.  */
+    gl_rwlock_wrlock (locale_lock);
+    for (p = locale_hash_table[slot]; p != NULL; p = p->next)
+      if (p->locale == result)
+        {
+          /* This can happen if the application uses the original freelocale()
+             function instead of the overridden one.  */
+          p->names = node->names;
+          break;
+        }
+    if (p == NULL)
+      {
+        node->next = locale_hash_table[slot];
+        locale_hash_table[slot] = node;
+      }
+
+    gl_rwlock_unlock (locale_lock);
+
+    if (p != NULL)
+      free (node);
+  }
+
+  return result;
+}
+
+/* duplocale() override.  */
+locale_t
+duplocale (locale_t locale)
+#undef duplocale
+{
+  struct locale_hash_node *node;
+  locale_t result;
+
+  if (locale == NULL)
+    /* Invalid argument.  */
+    abort ();
+
+  node = (struct locale_hash_node *) malloc (sizeof (struct locale_hash_node));
+  if (node == NULL)
+    /* errno is set to ENOMEM.  */
+    return NULL;
+
+  result = duplocale (locale);
+  if (result == NULL)
+    {
+      int saved_errno = errno;
+      free (node);
+      errno = saved_errno;
+      return NULL;
+    }
+
+  /* Fill the hash node.  */
+  node->locale = result;
+  if (locale == LC_GLOBAL_LOCALE)
+    {
+      int category;
+
+      for (category = 0; category < 6; category++)
+        node->names.category_name[category] =
+          get_locale_t_name (category, LC_GLOBAL_LOCALE);
+
+      /* Lock before inserting the new node.  */
+      gl_rwlock_wrlock (locale_lock);
+    }
+  else
+    {
+      struct locale_hash_node *p;
+
+      /* Lock once, for the lookup and the insertion.  */
+      gl_rwlock_wrlock (locale_lock);
+
+      for (p = locale_hash_table[pointer_hash (locale) % 
LOCALE_HASH_TABLE_SIZE];
+           p != NULL;
+           p = p->next)
+        if (p->locale == locale)
+          break;
+      if (p != NULL)
+        node->names = p->names;
+      else
+        {
+          /* This can happen if the application uses the original
+             newlocale()/duplocale() functions instead of the overridden
+             ones.  */
+          int category;
+
+          for (category = 0; category < 6; category++)
+            node->names.category_name[category] = "";
+        }
+    }
+
+  /* Insert it in the hash table.  */
+  {
+    size_t hashcode = pointer_hash (result);
+    size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE;
+    struct locale_hash_node *p;
+
+    for (p = locale_hash_table[slot]; p != NULL; p = p->next)
+      if (p->locale == result)
+        {
+          /* This can happen if the application uses the original freelocale()
+             function instead of the overridden one.  */
+          p->names = node->names;
+          break;
+        }
+    if (p == NULL)
+      {
+        node->next = locale_hash_table[slot];
+        locale_hash_table[slot] = node;
+      }
+
+    gl_rwlock_unlock (locale_lock);
+
+    if (p != NULL)
+      free (node);
+  }
+
+  return result;
+}
+
+/* freelocale() override.  */
+void
+freelocale (locale_t locale)
+#undef freelocale
+{
+  if (locale == NULL || locale == LC_GLOBAL_LOCALE)
+    /* Invalid argument.  */
+    abort ();
+
+  {
+    size_t hashcode = pointer_hash (locale);
+    size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE;
+    struct locale_hash_node *found;
+    struct locale_hash_node **p;
+
+    found = NULL;
+    /* Lock while removing the hash node.  */
+    gl_rwlock_wrlock (locale_lock);
+    for (p = &locale_hash_table[slot]; *p != NULL; p = &(*p)->next)
+      if ((*p)->locale == locale)
+        {
+          found = *p;
+          *p = (*p)->next;
+          break;
+        }
+    gl_rwlock_unlock (locale_lock);
+    free (found);
+  }
+
+  freelocale (locale);
+}
+
+#endif
+
+
 #if defined IN_LIBINTL || HAVE_USELOCALE
 
 /* Like gl_locale_name_thread, except that the result is not in storage of
@@ -2761,6 +3180,8 @@ gl_locale_name_thread_unsafe (int category, const char 
*categoryname)
 #   if HAVE_GETLOCALENAME_L
         /* Solaris >= 12.  */
         return getlocalename_l (category, thread_locale);
+#   elif HAVE_NAMELESS_LOCALES
+        return get_locale_t_name (category, thread_locale);
 #   else
         /* Solaris 11 OpenIndiana.
            For the internal structure of locale objects, see
diff --git a/m4/intlsolaris.m4 b/m4/intlsolaris.m4
new file mode 100644
index 0000000..2e3db7f
--- /dev/null
+++ b/m4/intlsolaris.m4
@@ -0,0 +1,53 @@
+# intlsolaris.m4 serial 1
+dnl Copyright (C) 2015-2018 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Checks for special localename support needed on Solaris.
+dnl Sets gt_nameless_locales.
+AC_DEFUN([gt_INTL_SOLARIS],
+[
+  dnl Persuade Solaris <locale.h> to define 'locale_t'.
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  AC_CHECK_FUNCS_ONCE([uselocale])
+
+  gt_nameless_locales=no
+  dnl Solaris 12 provides getlocalename_l, while Illumos doesn't have
+  dnl it nor the equivalent.
+  if test $ac_cv_func_uselocale = yes; then
+    AC_CHECK_FUNCS([getlocalename_l])
+    if test $ac_cv_func_getlocalename_l != yes; then
+      AC_CACHE_CHECK([for Solaris 11.4 locale system],
+        [gt_cv_locale_solaris114],
+        [dnl Test whether <locale.h> defines locale_t as a typedef of
+         dnl 'struct _LC_locale_t **' (whereas Illumos defines it as a
+         dnl typedef of 'struct _locale *').
+         AC_COMPILE_IFELSE(
+           [AC_LANG_PROGRAM([[
+              #include <locale.h>
+              struct _LC_locale_t *x;
+              locale_t y;
+            ]],
+            [[*y = x;]])],
+           [gt_cv_locale_solaris114=yes],
+           [gt_cv_locale_solaris114=no])
+        ])
+      if test $gt_cv_locale_solaris114 = yes; then
+        gt_nameless_locales=yes
+        AC_DEFINE([HAVE_NAMELESS_LOCALES], [1],
+          [Define if the locale_t type does not contain the name of each 
locale category.])
+      fi
+    fi
+  fi
+])
diff --git a/m4/locale_h.m4 b/m4/locale_h.m4
index 4bd9e57..e619dcd 100644
--- a/m4/locale_h.m4
+++ b/m4/locale_h.m4
@@ -1,4 +1,4 @@
-# locale_h.m4 serial 20
+# locale_h.m4 serial 21
 dnl Copyright (C) 2007, 2009-2018 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -96,7 +96,7 @@ AC_DEFUN([gl_LOCALE_H],
 # include <xlocale.h>
 #endif
     ]],
-    [setlocale duplocale])
+    [setlocale newlocale duplocale freelocale])
 ])
 
 AC_DEFUN([gl_LOCALE_MODULE_INDICATOR],
@@ -113,10 +113,15 @@ AC_DEFUN([gl_LOCALE_H_DEFAULTS],
   GNULIB_LOCALECONV=0; AC_SUBST([GNULIB_LOCALECONV])
   GNULIB_SETLOCALE=0;  AC_SUBST([GNULIB_SETLOCALE])
   GNULIB_DUPLOCALE=0;  AC_SUBST([GNULIB_DUPLOCALE])
+  GNULIB_LOCALENAME=0; AC_SUBST([GNULIB_LOCALENAME])
   dnl Assume proper GNU behavior unless another module says otherwise.
+  HAVE_NEWLOCALE=1;       AC_SUBST([HAVE_NEWLOCALE])
   HAVE_DUPLOCALE=1;       AC_SUBST([HAVE_DUPLOCALE])
+  HAVE_FREELOCALE=1;      AC_SUBST([HAVE_FREELOCALE])
   REPLACE_LOCALECONV=0;   AC_SUBST([REPLACE_LOCALECONV])
   REPLACE_SETLOCALE=0;    AC_SUBST([REPLACE_SETLOCALE])
+  REPLACE_NEWLOCALE=0;    AC_SUBST([REPLACE_NEWLOCALE])
   REPLACE_DUPLOCALE=0;    AC_SUBST([REPLACE_DUPLOCALE])
+  REPLACE_FREELOCALE=0;   AC_SUBST([REPLACE_FREELOCALE])
   REPLACE_STRUCT_LCONV=0; AC_SUBST([REPLACE_STRUCT_LCONV])
 ])
diff --git a/m4/localename.m4 b/m4/localename.m4
index a0e1367..3d8418a 100644
--- a/m4/localename.m4
+++ b/m4/localename.m4
@@ -1,4 +1,4 @@
-# localename.m4 serial 3
+# localename.m4 serial 4
 dnl Copyright (C) 2007, 2009-2018 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -6,13 +6,25 @@ dnl with or without modifications, as long as this notice is 
preserved.
 
 AC_DEFUN([gl_LOCALENAME],
 [
+  AC_REQUIRE([gl_LOCALE_H_DEFAULTS])
   AC_REQUIRE([gt_LC_MESSAGES])
   AC_REQUIRE([gt_INTL_MACOSX])
   AC_CHECK_HEADERS_ONCE([langinfo.h])
-  AC_CHECK_FUNCS([setlocale uselocale])
-  dnl Solaris 12 provides getlocalename_l, while Illumos doesn't have
-  dnl it nor the equivalent.
-  if test $ac_cv_func_uselocale = yes; then
-    AC_CHECK_FUNCS([getlocalename_l])
+  AC_CHECK_FUNCS([setlocale])
+  AC_CHECK_FUNCS_ONCE([uselocale newlocale duplocale freelocale])
+  if test $ac_cv_func_newlocale != yes; then
+    HAVE_NEWLOCALE=0
+  fi
+  if test $ac_cv_func_duplocale != yes; then
+    HAVE_DUPLOCALE=0
+  fi
+  if test $ac_cv_func_freelocale != yes; then
+    HAVE_FREELOCALE=0
+  fi
+  gt_INTL_SOLARIS
+  if test $gt_nameless_locales = yes; then
+    REPLACE_NEWLOCALE=1
+    REPLACE_DUPLOCALE=1
+    REPLACE_FREELOCALE=1
   fi
 ])
diff --git a/modules/locale b/modules/locale
index acb54c0..488e437 100644
--- a/modules/locale
+++ b/modules/locale
@@ -32,11 +32,16 @@ locale.h: locale.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's/@''GNULIB_LOCALECONV''@/$(GNULIB_LOCALECONV)/g' \
              -e 's/@''GNULIB_SETLOCALE''@/$(GNULIB_SETLOCALE)/g' \
              -e 's/@''GNULIB_DUPLOCALE''@/$(GNULIB_DUPLOCALE)/g' \
+             -e 's/@''GNULIB_LOCALENAME''@/$(GNULIB_LOCALENAME)/g' \
+             -e 's|@''HAVE_NEWLOCALE''@|$(HAVE_NEWLOCALE)|g' \
              -e 's|@''HAVE_DUPLOCALE''@|$(HAVE_DUPLOCALE)|g' \
+             -e 's|@''HAVE_FREELOCALE''@|$(HAVE_FREELOCALE)|g' \
              -e 's|@''HAVE_XLOCALE_H''@|$(HAVE_XLOCALE_H)|g' \
              -e 's|@''REPLACE_LOCALECONV''@|$(REPLACE_LOCALECONV)|g' \
              -e 's|@''REPLACE_SETLOCALE''@|$(REPLACE_SETLOCALE)|g' \
+             -e 's|@''REPLACE_NEWLOCALE''@|$(REPLACE_NEWLOCALE)|g' \
              -e 's|@''REPLACE_DUPLOCALE''@|$(REPLACE_DUPLOCALE)|g' \
+             -e 's|@''REPLACE_FREELOCALE''@|$(REPLACE_FREELOCALE)|g' \
              -e 's|@''REPLACE_STRUCT_LCONV''@|$(REPLACE_STRUCT_LCONV)|g' \
              -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
              -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
diff --git a/modules/localename b/modules/localename
index ec6cd1c..29c4321 100644
--- a/modules/localename
+++ b/modules/localename
@@ -6,10 +6,12 @@ lib/localename.h
 lib/localename.c
 m4/localename.m4
 m4/intlmacosx.m4
+m4/intlsolaris.m4
 m4/lcmessage.m4
 
 Depends-on:
 extensions
+locale
 flexmember
 strdup
 lock
@@ -17,6 +19,7 @@ langinfo
 
 configure.ac:
 gl_LOCALENAME
+gl_LOCALE_MODULE_INDICATOR([localename])
 
 Makefile.am:
 lib_SOURCES += localename.c
diff --git a/tests/test-locale-c++.cc b/tests/test-locale-c++.cc
index 066cdd8..410c84c 100644
--- a/tests/test-locale-c++.cc
+++ b/tests/test-locale-c++.cc
@@ -32,10 +32,18 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::localeconv, struct lconv 
*, (void));
 SIGNATURE_CHECK (GNULIB_NAMESPACE::setlocale, char *, (int, const char *));
 #endif
 
+#if 0
+SIGNATURE_CHECK (GNULIB_NAMESPACE::newlocale, locale_t, (int const char *, 
locale_t));
+#endif
+
 #if GNULIB_TEST_DUPLOCALE && HAVE_DUPLOCALE
 SIGNATURE_CHECK (GNULIB_NAMESPACE::duplocale, locale_t, (locale_t));
 #endif
 
+#if 0
+SIGNATURE_CHECK (GNULIB_NAMESPACE::freelocale, void, (locale_t));
+#endif
+
 
 int
 main ()




reply via email to

[Prev in Thread] Current Thread [Next in Thread]