Relies on the recent changes to the 'localename' module in gnulib.
* gettext-runtime/intl/localename.c: Apply changes from gnulib.
* gettext-runtime/intl/localename-table.h: New file, from gnulib.
* gettext-runtime/intl/localename-table.c: New file, from gnulib.
* gettext-runtime/intl/libgnuintl.in.h (newlocale, duplocale, freelocale): New
overriding declarations.
* gettext-runtime/intl/Makefile.in (HEADERS): Add localename-table.h.
(SOURCES): Add localename-table.c.
(OBJECTS): Add localename-table.$lo.
(localename-table.lo): New target.
(libgnuintl.h, libintl.h): Substitute also HAVE_NAMELESS_LOCALES.
* gettext-runtime/m4/intl.m4: Apply changes from gnulib:
(gt_INTL_SUBDIR_CORE): Don't test for 'uselocale' and 'getlocalename_l'.
Instead, invoke gt_INTL_SOLARIS. Set HAVE_NAMELESS_LOCALES.
* gettext-runtime/m4/intlsolaris.m4: New file, from gnulib.
* gettext-runtime/m4/Makefile.am (EXTRA_DIST): Add it.
* gettext-tools/m4/Makefile.am (aclocal_DATA): Add intlsolaris.m4.
* gettext-tools/misc/gettextize.in (m4filelist): Add intlsolaris.m4.
* Makefile.am (distcheck-hook): Verify that intlsolaris.m4 is consistent with
gnulib.
* gettext-tools/doc/gettext.texi (aclocal): Add intlsolaris.m4 to the file list.
* PACKAGING: Add intlsolaris.m4 to the list of installed files.
* NEWS: Mention the change.
cmp -s gettext-runtime/m4/intl.m4 gettext-tools/gnulib-m4/intl.m4
cmp -s gettext-runtime/m4/intldir.m4 gettext-tools/gnulib-m4/intldir.m4
cmp -s gettext-runtime/m4/intlmacosx.m4 gettext-tools/gnulib-m4/intlmacosx.m4
+ cmp -s gettext-runtime/m4/intlsolaris.m4 gettext-tools/gnulib-m4/intlsolaris.m4
cmp -s gettext-runtime/m4/intmax.m4 gettext-tools/gnulib-m4/intmax.m4
cmp -s gettext-runtime/m4/inttypes-pri.m4 gettext-tools/gnulib-m4/inttypes-pri.m4
cmp -s gettext-runtime/m4/inttypes_h.m4 gettext-tools/gnulib-m4/inttypes_h.m4
* Runtime behaviour:
- The interpretation of the language preferences on macOS has been fixed.
+ - Per-thread locales are now also supported on Solaris 11.4.
- The replacements for the printf()/fprintf()/... functions that are
provided through <libintl.h> on native Windows and NetBSD are now POSIX
compliant. There is no conflict any more between these replacements
$prefix/share/aclocal/intl.m4
$prefix/share/aclocal/intldir.m4
$prefix/share/aclocal/intlmacosx.m4
+ $prefix/share/aclocal/intlsolaris.m4
$prefix/share/aclocal/intmax.m4
$prefix/share/aclocal/inttypes_h.m4
$prefix/share/aclocal/inttypes-pri.m4
localcharset.h \
lock.h \
relocatable.h \
+ localename-table.h \
tsearch.h tsearch.c \
verify.h \
xsize.h \
relocatable.c \
langprefs.c \
localename.c \
+ localename-table.c \
flexmember.h \
log.c \
printf.c \
relocatable.$lo \
langprefs.$lo \
localename.$lo \
+ localename-table.$lo \
log.$lo \
printf.$lo \
setlocale.$lo \
$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(COMPILE) $(srcdir)/langprefs.c
localename.lo: $(srcdir)/localename.c
$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(COMPILE) $(srcdir)/localename.c
+localename-table.lo: $(srcdir)/localename-table.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(COMPILE) $(srcdir)/localename-table.c
log.lo: $(srcdir)/log.c
$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC --mode=compile $(COMPILE) $(srcdir)/log.c
printf.lo: $(srcdir)/printf.c
sed -e '/IN_LIBGLOCALE/d' \
-e 's,@''HAVE_POSIX_PRINTF''@,@HAVE_POSIX_PRINTF@,g' \
-e 's,@''HAVE_ASPRINTF''@,@HAVE_ASPRINTF@,g' \
- -e 's,@''HAVE_NEWLOCALE''@,@HAVE_NEWLOCALE@,g' \
-e 's,@''HAVE_SNPRINTF''@,@HAVE_SNPRINTF@,g' \
-e 's,@''HAVE_WPRINTF''@,@HAVE_WPRINTF@,g' \
+ -e 's,@''HAVE_NAMELESS_LOCALES''@,@HAVE_NAMELESS_LOCALES@,g' \
+ -e 's,@''HAVE_NEWLOCALE''@,@HAVE_NEWLOCALE@,g' \
< $(srcdir)/libgnuintl.in.h \
| if test '@WOE32DLL@' = yes; then \
sed -e 's/extern \([^()]*\);/extern __declspec (dllimport) \1;/'; \
sed -e '/IN_LIBGLOCALE/d' \
-e 's,@''HAVE_POSIX_PRINTF''@,@HAVE_POSIX_PRINTF@,g' \
-e 's,@''HAVE_ASPRINTF''@,@HAVE_ASPRINTF@,g' \
- -e 's,@''HAVE_NEWLOCALE''@,@HAVE_NEWLOCALE@,g' \
-e 's,@''HAVE_SNPRINTF''@,@HAVE_SNPRINTF@,g' \
-e 's,@''HAVE_WPRINTF''@,@HAVE_WPRINTF@,g' \
+ -e 's,@''HAVE_NAMELESS_LOCALES''@,@HAVE_NAMELESS_LOCALES@,g' \
+ -e 's,@''HAVE_NEWLOCALE''@,@HAVE_NEWLOCALE@,g' \
< $(srcdir)/libgnuintl.in.h > libintl.h
check: all
$(OBJECTS): ../config.h libgnuintl.h
bindtextdom.$lo dcgettext.$lo dcigettext.$lo dcngettext.$lo dgettext.$lo dngettext.$lo finddomain.$lo gettext.$lo intl-compat.$lo loadmsgcat.$lo localealias.$lo ngettext.$lo setlocale.$lo textdomain.$lo: $(srcdir)/gettextP.h $(srcdir)/gmo.h $(srcdir)/loadinfo.h
localename.$lo: $(srcdir)/gettextP.h
+localename.$lo localename-table.$lo: $(srcdir)/localename-table.h
hash-string.$lo dcigettext.$lo loadmsgcat.$lo: $(srcdir)/hash-string.h
explodename.$lo l10nflist.$lo: $(srcdir)/loadinfo.h
dcigettext.$lo loadmsgcat.$lo $(PLURAL_OBJECT) plural-exp.$lo: $(srcdir)/plural-exp.h
#endif
+/* Support for retrieving the name of a locale_t object. */
+#if @HAVE_NAMELESS_LOCALES@
+
+#ifndef GNULIB_defined_newlocale /* don't override gnulib */
+#undef newlocale
+#define newlocale libintl_newlocale
+extern locale_t newlocale (int, const char *, locale_t);
+#endif
+
+#ifndef GNULIB_defined_duplocale /* don't override gnulib */
+#undef duplocale
+#define duplocale libintl_duplocale
+extern locale_t duplocale (locale_t);
+#endif
+
+#ifndef GNULIB_defined_freelocale /* don't override gnulib */
+#undef freelocale
+#define freelocale libintl_freelocale
+extern void freelocale (locale_t);
+#endif
+
+#endif
+
+
/* Support for the locale chosen by the user. */
#if (defined __APPLE__ && defined __MACH__) || defined _WIN32 || defined __CYGWIN__
--- /dev/null
+/* Table that maps a locale object to the names of the locale categories.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2018. */
+
+#include <config.h>
+
+#if HAVE_USELOCALE && HAVE_NAMELESS_LOCALES /* Solaris >= 11.4 */
+
+/* Specification. */
+#include "localename-table.h"
+
+#include <stdint.h>
+
+/* A hash function for pointers. */
+size_t _GL_ATTRIBUTE_CONST
+locale_hash_function (locale_t x)
+{
+ uintptr_t p = (uintptr_t) x;
+ size_t h = ((p % 4177) << 12) + ((p % 79) << 6) + (p % 61);
+ return h;
+}
+
+struct locale_hash_node * locale_hash_table[LOCALE_HASH_TABLE_SIZE]
+ /* = { NULL, ..., NULL } */;
+
+gl_rwlock_define_initialized(, locale_lock)
+
+#else
+
+/* This declaration is solely to ensure that after preprocessing
+ this file is never empty. */
+typedef int dummy;
+
+#endif
--- /dev/null
+/* Table that maps a locale object to the names of the locale categories.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2018. */
+
+#if HAVE_USELOCALE && HAVE_NAMELESS_LOCALES /* Solaris >= 11.4 */
+
+# include <stddef.h>
+# include <locale.h>
+
+# ifdef IN_LIBINTL
+# include "lock.h"
+# else
+# include "glthread/lock.h"
+# endif
+
+struct locale_categories_names
+ {
+ /* Locale category -> name (allocated with indefinite extent). */
+ const char *category_name[6];
+ };
+
+/* 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.
+ This hash table has global scope, so that when an application uses both
+ GNU libintl and gnulib, the application sees only one hash table. (When
+ linking statically with libintl, the fact that localename-table.c is a
+ separate compilation unit resolves the duplicate symbol conflict. When
+ linking with libintl as a shared library, we rely on ELF and the symbol
+ conflict resolution implemented in the ELF dynamic loader here.)
+ Both the libintl overrides and the gnulib overrides of the functions
+ newlocale, duplocale, freelocale see the same hash table (and the same lock).
+ For this reason, the internal layout of the hash table and the hash function
+ MUST NEVER CHANGE. If you need to change the internal layout or the hash
+ function, introduce versioning by appending a version suffix to the symbols
+ at the linker level. */
+# define locale_hash_function libintl_locale_hash_function
+# define locale_hash_table libintl_locale_hash_table
+# define locale_lock libintl_locale_lock
+
+extern size_t _GL_ATTRIBUTE_CONST locale_hash_function (locale_t x);
+
+/* 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
+extern struct locale_hash_node * locale_hash_table[LOCALE_HASH_TABLE_SIZE];
+
+/* This lock protects the locale_hash_table against multiple simultaneous
+ accesses (except that multiple simultaneous read accesses are allowed). */
+
+gl_rwlock_define(extern, locale_lock)
+
+#endif
/* Solaris >= 12. */
extern char * getlocalename_l(int, locale_t);
# endif
+# if HAVE_NAMELESS_LOCALES
+# include <errno.h>
+# include "localename-table.h"
+# endif
#endif
#if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
#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. */
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
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";
#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.
+ The hash table is defined in localename-table.[hc]. */
+
+/* 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 = locale_hash_function (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[locale_hash_function (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 = locale_hash_function (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[locale_hash_function (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 = locale_hash_function (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 = locale_hash_function (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
# 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
intl.m4 \
intldir.m4 \
intlmacosx.m4 \
+intlsolaris.m4 \
intmax.m4 \
inttypes-pri.m4 \
inttypes_h.m4 \
-# intl.m4 serial 32 (gettext-0.19.9)
+# intl.m4 serial 33 (gettext-0.19.9)
dnl Copyright (C) 1995-2014, 2016-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,
AC_CHECK_HEADERS([argz.h inttypes.h limits.h unistd.h sys/param.h])
AC_CHECK_FUNCS([getcwd getegid geteuid getgid getuid mempcpy munmap \
- stpcpy strcasecmp strdup strtoul tsearch uselocale argz_count \
- argz_stringify argz_next __fsetlocking])
+ stpcpy strcasecmp strdup strtoul tsearch argz_count argz_stringify \
+ argz_next __fsetlocking])
- 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])
+ dnl For Solaris 11.4 and 12.
+ gt_INTL_SOLARIS
+ if test $gt_nameless_locales = yes; then
+ HAVE_NAMELESS_LOCALES=1
+ else
+ HAVE_NAMELESS_LOCALES=0
fi
+ AC_SUBST([HAVE_NAMELESS_LOCALES])
dnl Use the *_unlocked functions only if they are declared.
dnl (because some of them were defined without being declared in Solaris
--- /dev/null
+# intlsolaris.m4 serial 2
+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],
+[
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+
+ dnl Persuade Solaris <locale.h> to define 'locale_t'.
+ AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+ AC_CHECK_FUNCS_ONCE([uselocale])
+
+ gt_nameless_locales=no
+ if test $ac_cv_func_uselocale = yes; then
+ AC_CACHE_CHECK([for Solaris 11.4 locale system],
+ [gt_cv_locale_solaris114],
+ [case "$host_os" in
+ solaris*)
+ 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])
+ ;;
+ *) gt_cv_locale_solaris114=no ;;
+ esac
+ ])
+ fi
+ 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
+
+ dnl Solaris 12 will maybe provide getlocalename_l. If it does, it will
+ dnl simplify the implementation of gl_locale_name_thread(). But the overrides
+ dnl of newlocale, duplocale, freelocale will still be necessary, in order to
+ dnl keep the libintl_locale_hash_table up-to-date, which may be used by
+ dnl libintl or gnulib code that was compiled on Solaris 11.4, before
+ dnl getlocalename_l was introduced.
+ if test $ac_cv_func_uselocale = yes; then
+ AC_CHECK_FUNCS([getlocalename_l])
+ fi
+])
the simplest is to concatenate the files @file{codeset.m4}, @file{fcntl-o.m4},
@file{gettext.m4}, @file{glibc2.m4}, @file{glibc21.m4}, @file{iconv.m4},
@file{intdiv0.m4}, @file{intl.m4}, @file{intldir.m4}, @file{intlmacosx.m4},
-@file{intmax.m4}, @file{inttypes_h.m4}, @file{inttypes-pri.m4},
-@file{lcmessage.m4}, @file{lib-ld.m4}, @file{lib-link.m4},
-@file{lib-prefix.m4}, @file{lock.m4}, @file{longlong.m4}, @file{nls.m4},
-@file{po.m4}, @file{printf-posix.m4}, @file{progtest.m4}, @file{size_max.m4},
-@file{stdint_h.m4}, @file{threadlib.m4}, @file{uintmax_t.m4},
-@file{visibility.m4}, @file{wchar_t.m4}, @file{wint_t.m4}, @file{xsize.m4}
+@file{intlsolaris.m4}, @file{intmax.m4}, @file{inttypes_h.m4},
+@file{inttypes-pri.m4}, @file{lcmessage.m4}, @file{lib-ld.m4},
+@file{lib-link.m4}, @file{lib-prefix.m4}, @file{lock.m4}, @file{longlong.m4},
+@file{nls.m4}, @file{po.m4}, @file{printf-posix.m4}, @file{progtest.m4},
+@file{size_max.m4}, @file{stdint_h.m4}, @file{threadlib.m4},
+@file{uintmax_t.m4}, @file{visibility.m4}, @file{wchar_t.m4}, @file{wint_t.m4},
+@file{xsize.m4}
from GNU @code{gettext}'s
@file{m4/} directory into a single file. If you have suppressed the
@file{intl/} directory, only @file{gettext.m4}, @file{intlmacosx.m4},
../../gettext-runtime/m4/intl.m4 \
../../gettext-runtime/m4/intldir.m4 \
../../gettext-runtime/m4/intlmacosx.m4 \
+ ../../gettext-runtime/m4/intlsolaris.m4 \
../../gettext-runtime/m4/intmax.m4 \
../../gettext-runtime/m4/inttypes_h.m4 \
../../gettext-runtime/m4/inttypes-pri.m4 \
intdiv0.m4
intl.m4
intldir.m4
+ intlsolaris.m4
intmax.m4
inttypes_h.m4
inttypes-pri.m4