summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2009-11-23 01:46:00 +0100
committerBruno Haible <bruno@clisp.org>2009-11-23 01:48:36 +0100
commit3f0d472e052865baf722ea457e35dd067b94a477 (patch)
tree1a6f787abe701f0b87c23d2291012b743268c419
parent15b8a93426dff14b43cc5e1dc340a869a0096f02 (diff)
downloadgnulib-3f0d472e052865baf722ea457e35dd067b94a477.tar.gz
New module 'duplocale'.
-rw-r--r--ChangeLog15
-rw-r--r--doc/posix-functions/duplocale.texi5
-rw-r--r--lib/duplocale.c105
-rw-r--r--lib/locale.in.h14
-rw-r--r--m4/duplocale.m456
-rw-r--r--m4/locale_h.m444
-rw-r--r--modules/duplocale24
-rw-r--r--modules/locale2
8 files changed, 255 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 394c56c80d..740085bcb3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
2009-11-22 Bruno Haible <bruno@clisp.org>
+ New module 'duplocale'.
+ * m4/duplocale.m4: New file.
+ * lib/locale.in.h (duplocale): New declaration.
+ * lib/duplocale.c: New file.
+ * m4/locale_h.m4 (gl_REPLACE_LOCALE_H, gl_LOCALE_MODULE_INDICATOR,
+ gl_LOCALE_H_DEFAULTS): New macros.
+ (gl_LOCALE_H): Require gl_LOCALE_H_DEFAULTS. Invoke
+ gl_CHECK_NEXT_HEADERS unconditionally. Invoke gl_REPLACE_LOCALE_H.
+ * modules/locale (Makefile.am): Substitute also GNULIB_DUPLOCALE,
+ REPLACE_DUPLOCALE.
+ * modules/duplocale: New file.
+ * doc/posix-functions/duplocale.texi: Mention the glibc bug.
+
+2009-11-22 Bruno Haible <bruno@clisp.org>
+
* modules/locale-tests (configure.ac): Test for newlocale function.
* tests/test-locale.c: When the system has extended locale functions,
verify that <locale.h> defines locale_t and LC_GLOBAL_LOCALE.
diff --git a/doc/posix-functions/duplocale.texi b/doc/posix-functions/duplocale.texi
index 6bae698ba5..3abd73b2b0 100644
--- a/doc/posix-functions/duplocale.texi
+++ b/doc/posix-functions/duplocale.texi
@@ -4,10 +4,13 @@
POSIX specification: @url{http://www.opengroup.org/onlinepubs/9699919799/functions/duplocale.html}
-Gnulib module: ---
+Gnulib module: duplocale
Portability problems fixed by Gnulib:
@itemize
+@item
+The argument @code{LC_GLOBAL_LOCALE} is not supported on some platforms:
+glibc 2.11.
@end itemize
Portability problems not fixed by Gnulib:
diff --git a/lib/duplocale.c b/lib/duplocale.c
new file mode 100644
index 0000000000..63d00d9a6c
--- /dev/null
+++ b/lib/duplocale.c
@@ -0,0 +1,105 @@
+/* Duplicate a locale object.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2007. */
+
+#include <config.h>
+
+/* Specification. */
+#include <locale.h>
+
+#include <errno.h>
+#include <langinfo.h>
+#include <string.h>
+
+/* Work around an incorrect definition of the _NL_LOCALE_NAME macro in
+ glibc < 2.12.
+ See <http://sourceware.org/bugzilla/show_bug.cgi?id=10968>. */
+#undef _NL_LOCALE_NAME
+#define _NL_LOCALE_NAME(category) _NL_ITEM ((category), _NL_ITEM_INDEX (-1))
+
+#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
+
+#undef duplocale
+
+locale_t
+rpl_duplocale (locale_t locale)
+{
+ /* Work around crash in the duplocale function in glibc < 2.12.
+ See <http://sourceware.org/bugzilla/show_bug.cgi?id=10969>. */
+ if (locale == LC_GLOBAL_LOCALE)
+ {
+ /* Create a copy of the locale by fetching the name of each locale
+ category, starting with LC_CTYPE. */
+ static struct { int cat; int mask; } categories[] =
+ {
+ { LC_NUMERIC, LC_NUMERIC_MASK },
+ { LC_TIME, LC_TIME_MASK },
+ { LC_COLLATE, LC_COLLATE_MASK },
+ { LC_MONETARY, LC_MONETARY_MASK },
+ { LC_MESSAGES, LC_MESSAGES_MASK }
+#ifdef LC_PAPER
+ , { LC_PAPER, LC_PAPER_MASK }
+#endif
+#ifdef LC_NAME
+ , { LC_NAME, LC_NAME_MASK }
+#endif
+#ifdef LC_ADDRESS
+ , { LC_ADDRESS, LC_ADDRESS_MASK }
+#endif
+#ifdef LC_TELEPHONE
+ , { LC_TELEPHONE, LC_TELEPHONE_MASK }
+#endif
+#ifdef LC_MEASUREMENT
+ , { LC_MEASUREMENT, LC_MEASUREMENT_MASK }
+#endif
+#ifdef LC_IDENTIFICATION
+ , { LC_IDENTIFICATION, LC_IDENTIFICATION_MASK }
+#endif
+ };
+ const char *base_name = nl_langinfo (_NL_LOCALE_NAME (LC_CTYPE));
+ locale_t base_copy = newlocale (LC_ALL_MASK, base_name, NULL);
+ unsigned int i;
+
+ if (base_copy == NULL)
+ return NULL;
+
+ for (i = 0; i < SIZEOF (categories); i++)
+ {
+ int category = categories[i].cat;
+ int category_mask = categories[i].mask;
+ const char *name = nl_langinfo (_NL_LOCALE_NAME (category));
+ if (strcmp (name, base_name) != 0)
+ {
+ locale_t copy = newlocale (category_mask, name, base_copy);
+ if (copy == NULL)
+ {
+ int saved_errno = errno;
+ freelocale (base_copy);
+ errno = saved_errno;
+ return NULL;
+ }
+ /* No need to call freelocale (base_copy) if copy != base_copy;
+ the newlocale function already takes care of doing it. */
+ base_copy = copy;
+ }
+ }
+
+ return base_copy;
+ }
+
+ return duplocale (locale);
+}
diff --git a/lib/locale.in.h b/lib/locale.in.h
index 49835c5cab..08d05741da 100644
--- a/lib/locale.in.h
+++ b/lib/locale.in.h
@@ -40,5 +40,19 @@
# define LC_MESSAGES 1729
#endif
+#if @GNULIB_DUPLOCALE@
+# if @REPLACE_DUPLOCALE@
+# undef duplocale
+# define duplocale rpl_duplocale
+extern locale_t duplocale (locale_t locale);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef duplocale
+# define duplocale(l) \
+ (GL_LINK_WARNING ("duplocale is buggy on some glibc systems - " \
+ "use gnulib module duplocale for portability"), \
+ duplocale (l))
+#endif
+
#endif /* _GL_LOCALE_H */
#endif /* _GL_LOCALE_H */
diff --git a/m4/duplocale.m4 b/m4/duplocale.m4
new file mode 100644
index 0000000000..7e0a0714ca
--- /dev/null
+++ b/m4/duplocale.m4
@@ -0,0 +1,56 @@
+# duplocale.m4 serial 1
+dnl Copyright (C) 2009 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.
+
+AC_DEFUN([gl_FUNC_DUPLOCALE],
+[
+ AC_REQUIRE([gl_LOCALE_H_DEFAULTS])
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_CHECK_FUNCS_ONCE([duplocale])
+ if test $ac_cv_func_duplocale = yes; then
+ dnl Check against glibc bug where duplocale crashes.
+ dnl See <http://sourceware.org/bugzilla/show_bug.cgi?id=10969>.
+ AC_REQUIRE([gl_LOCALE_H])
+ AC_CACHE_CHECK([whether duplocale(LC_GLOBAL_LOCALE) works],
+ [gl_cv_func_duplocale_works],
+ [AC_TRY_RUN([
+#include <locale.h>
+#if HAVE_XLOCALE_H
+# include <xlocale.h>
+#endif
+int main ()
+{
+ (void) duplocale (LC_GLOBAL_LOCALE);
+ return 0;
+}], [gl_cv_func_duplocale_works=yes], [gl_cv_func_duplocale_works=no],
+ [dnl Guess it works except on glibc < 2.12.
+ AC_EGREP_CPP([Unlucky GNU user], [
+#include <features.h>
+#ifdef __GNU_LIBRARY__
+ #if (__GLIBC__ == 2 && __GLIBC_MINOR__ < 12)
+ Unlucky GNU user
+ #endif
+#endif
+ ],
+ [gl_cv_func_duplocale_works="guessing no"],
+ [gl_cv_func_duplocale_works="guessing yes"])
+ ])
+ ])
+ case "$gl_cv_func_duplocale_works" in
+ *no) REPLACE_DUPLOCALE=1 ;;
+ esac
+ fi
+ if test $REPLACE_DUPLOCALE = 1; then
+ gl_REPLACE_LOCALE_H
+ AC_LIBOBJ([duplocale])
+ gl_PREREQ_DUPLOCALE
+ fi
+])
+
+# Prerequisites of lib/duplocale.c.
+AC_DEFUN([gl_PREREQ_DUPLOCALE],
+[
+ :
+])
diff --git a/m4/locale_h.m4 b/m4/locale_h.m4
index 913a2009bc..35b8b322fb 100644
--- a/m4/locale_h.m4
+++ b/m4/locale_h.m4
@@ -1,4 +1,4 @@
-# locale_h.m4 serial 4
+# locale_h.m4 serial 5
dnl Copyright (C) 2007, 2009 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,6 +6,10 @@ dnl with or without modifications, as long as this notice is preserved.
AC_DEFUN([gl_LOCALE_H],
[
+ dnl Use AC_REQUIRE here, so that the default behavior below is expanded
+ dnl once only, before all statements that occur in other macros.
+ AC_REQUIRE([gl_LOCALE_H_DEFAULTS])
+
dnl Persuade glibc <locale.h> to define locale_t.
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
@@ -44,13 +48,35 @@ locale_t x;], [],
fi
AC_SUBST([HAVE_XLOCALE_H])
- if test -z "$STDDEF_H" \
- && test $gl_cv_header_locale_h_posix2001 = yes \
- && test $gl_cv_header_locale_h_needs_xlocale_h = no; then
- LOCALE_H=
- else
- gl_CHECK_NEXT_HEADERS([locale.h])
- LOCALE_H=locale.h
+ dnl Execute this unconditionally, because LOCALE_H may be set by other
+ dnl modules, after this code is executed.
+ gl_CHECK_NEXT_HEADERS([locale.h])
+
+ if test -n "$STDDEF_H" \
+ || test $gl_cv_header_locale_h_posix2001 = no \
+ || test $gl_cv_header_locale_h_needs_xlocale_h = yes; then
+ gl_REPLACE_LOCALE_H
fi
- AC_SUBST([LOCALE_H])
+])
+
+dnl Unconditionally enables the replacement of <locale.h>.
+AC_DEFUN([gl_REPLACE_LOCALE_H],
+[
+ AC_REQUIRE([gl_LOCALE_H_DEFAULTS])
+ LOCALE_H=locale.h
+])
+
+AC_DEFUN([gl_LOCALE_MODULE_INDICATOR],
+[
+ dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
+ AC_REQUIRE([gl_LOCALE_H_DEFAULTS])
+ GNULIB_[]m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./-],[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])=1
+])
+
+AC_DEFUN([gl_LOCALE_H_DEFAULTS],
+[
+ GNULIB_DUPLOCALE=0; AC_SUBST([GNULIB_DUPLOCALE])
+ dnl Assume proper GNU behavior unless another module says otherwise.
+ REPLACE_DUPLOCALE=0; AC_SUBST([REPLACE_DUPLOCALE])
+ LOCALE_H=''; AC_SUBST([LOCALE_H])
])
diff --git a/modules/duplocale b/modules/duplocale
new file mode 100644
index 0000000000..00852fd5b0
--- /dev/null
+++ b/modules/duplocale
@@ -0,0 +1,24 @@
+Description:
+duplocale() function: duplicate a locale object.
+
+Files:
+lib/duplocale.c
+m4/duplocale.m4
+
+Depends-on:
+locale
+
+configure.ac:
+gl_FUNC_DUPLOCALE
+gl_LOCALE_MODULE_INDICATOR([duplocale])
+
+Makefile.am:
+
+Include:
+<locale.h>
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible
diff --git a/modules/locale b/modules/locale
index 953237dea7..8b4b3b6562 100644
--- a/modules/locale
+++ b/modules/locale
@@ -24,7 +24,9 @@ locale.h: locale.in.h
sed -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
-e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
-e 's|@''NEXT_LOCALE_H''@|$(NEXT_LOCALE_H)|g' \
+ -e 's|@''GNULIB_DUPLOCALE''@|$(GNULIB_DUPLOCALE)|g' \
-e 's|@''HAVE_XLOCALE_H''@|$(HAVE_XLOCALE_H)|g' \
+ -e 's|@''REPLACE_DUPLOCALE''@|$(REPLACE_DUPLOCALE)|g' \
< $(srcdir)/locale.in.h; \
} > $@-t && \
mv $@-t $@