From: Bruno Haible Date: Mon, 23 Nov 2009 00:46:00 +0000 (+0100) Subject: New module 'duplocale'. X-Git-Tag: v0.1~5145 X-Git-Url: http://erislabs.net/gitweb/?a=commitdiff_plain;h=3f0d472e052865baf722ea457e35dd067b94a477;p=gnulib.git New module 'duplocale'. --- diff --git a/ChangeLog b/ChangeLog index 394c56c80..740085bcb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,20 @@ 2009-11-22 Bruno Haible + 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 + * modules/locale-tests (configure.ac): Test for newlocale function. * tests/test-locale.c: When the system has extended locale functions, verify that defines locale_t and LC_GLOBAL_LOCALE. diff --git a/doc/posix-functions/duplocale.texi b/doc/posix-functions/duplocale.texi index 6bae698ba..3abd73b2b 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 000000000..63d00d9a6 --- /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 . */ + +/* Written by Bruno Haible , 2007. */ + +#include + +/* Specification. */ +#include + +#include +#include +#include + +/* Work around an incorrect definition of the _NL_LOCALE_NAME macro in + glibc < 2.12. + See . */ +#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 . */ + 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 49835c5ca..08d05741d 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 000000000..7e0a0714c --- /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 . + AC_REQUIRE([gl_LOCALE_H]) + AC_CACHE_CHECK([whether duplocale(LC_GLOBAL_LOCALE) works], + [gl_cv_func_duplocale_works], + [AC_TRY_RUN([ +#include +#if HAVE_XLOCALE_H +# include +#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 +#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 913a2009b..35b8b322f 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 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 . +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 000000000..00852fd5b --- /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: + + +License: +LGPL + +Maintainer: +Bruno Haible diff --git a/modules/locale b/modules/locale index 953237dea..8b4b3b656 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 $@