bug-gnulib
[Top][All Lists]
Advanced

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

new module 'duplocale'


From: Bruno Haible
Subject: new module 'duplocale'
Date: Mon, 23 Nov 2009 01:54:10 +0100
User-agent: KMail/1.9.9

glibc unfortunately has a big bug in its duplocale function:
  <http://sourceware.org/bugzilla/show_bug.cgi?id=10969>
This module provides a workaround for it. Tested on glibc and MacOS X systems,
which are AFAIK the only systems so far with a duplocale function.


2009-11-22  Bruno Haible  <address@hidden>

        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.

=============================== m4/duplocale.m4 ===============================
# 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],
[
  :
])
=============================== lib/duplocale.c ===============================
/* 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 <address@hidden>, 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);
}
============================== modules/duplocale ==============================
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
===============================================================================
*** lib/locale.in.h.orig        2009-11-23 01:42:27.000000000 +0100
--- lib/locale.in.h     2009-11-23 01:05:28.000000000 +0100
***************
*** 40,44 ****
--- 40,58 ----
  # 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 */
*** m4/locale_h.m4.orig 2009-11-23 01:42:27.000000000 +0100
--- m4/locale_h.m4      2009-11-23 01:05:28.000000000 +0100
***************
*** 1,4 ****
! # locale_h.m4 serial 4
  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,
--- 1,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,11 ****
--- 6,15 ----
  
  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,56 ****
    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
    fi
!   AC_SUBST([LOCALE_H])
  ])
--- 48,82 ----
    fi
    AC_SUBST([HAVE_XLOCALE_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
! ])
! 
! 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])
  ])
*** modules/locale.orig 2009-11-23 01:42:27.000000000 +0100
--- modules/locale      2009-11-23 01:05:28.000000000 +0100
***************
*** 24,30 ****
--- 24,32 ----
          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; \
        } > address@hidden && \
        mv address@hidden $@
*** doc/posix-functions/duplocale.texi.orig     2009-11-23 01:42:27.000000000 
+0100
--- doc/posix-functions/duplocale.texi  2009-11-23 01:05:28.000000000 +0100
***************
*** 4,13 ****
  
  POSIX specification: 
@url{http://www.opengroup.org/onlinepubs/9699919799/functions/duplocale.html}
  
! Gnulib module: ---
  
  Portability problems fixed by Gnulib:
  @itemize
  @end itemize
  
  Portability problems not fixed by Gnulib:
--- 4,16 ----
  
  POSIX specification: 
@url{http://www.opengroup.org/onlinepubs/9699919799/functions/duplocale.html}
  
! 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:




reply via email to

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