changeset 16717:474c0712e7aa

locale: Provide a working 'struct lconv'. * lib/locale.in.h (lconv): Override if REPLACE_STRUCT_LCONV is 1. * m4/locale_h.m4 (gl_LOCALE_H): Set REPLACE_STRUCT_LCONV to 1 if 'struct lconv' does not even contain decimal_point. (gl_LOCALE_H_DEFAULTS): Initialize REPLACE_STRUCT_LCONV. * modules/locale (Makefile.am): Substitute REPLACE_STRUCT_LCONV. * tests/test-locale.c (main): Check that 'struct lconv' is complete. * doc/posix-headers/locale.texi: Mention the problems with 'struct lconv'. Reported by Gianluigi Tiesi <sherpya@netfarm.it>.
author Bruno Haible <bruno@clisp.org>
date Sun, 25 Mar 2012 13:22:41 +0200
parents 079fb1e73828
children e4aad6f843ed
files ChangeLog doc/posix-headers/locale.texi lib/locale.in.h m4/locale_h.m4 modules/locale tests/test-locale.c
diffstat 6 files changed, 170 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2012-03-25  Bruno Haible  <bruno@clisp.org>
+
+	locale: Provide a working 'struct lconv'.
+	* lib/locale.in.h (lconv): Override if REPLACE_STRUCT_LCONV is 1.
+	* m4/locale_h.m4 (gl_LOCALE_H): Set REPLACE_STRUCT_LCONV to 1 if
+	'struct lconv' does not even contain decimal_point.
+	(gl_LOCALE_H_DEFAULTS): Initialize REPLACE_STRUCT_LCONV.
+	* modules/locale (Makefile.am): Substitute REPLACE_STRUCT_LCONV.
+	* tests/test-locale.c (main): Check that 'struct lconv' is complete.
+	* doc/posix-headers/locale.texi: Mention the problems with
+	'struct lconv'.
+	Reported by Gianluigi Tiesi <sherpya@netfarm.it>.
+
 2012-03-24  Bruno Haible  <bruno@clisp.org>
 
 	Enable common subexpression optimization in GCC.
--- a/doc/posix-headers/locale.texi
+++ b/doc/posix-headers/locale.texi
@@ -16,6 +16,17 @@
 glibc 2.11, MacOS X 10.5.
 
 @item
+The @code{struct lconv} type does not contain any members on some platforms:
+Android.
+
+@item
+The @code{struct lconv} type does not contain the members
+@code{int_p_cs_precedes}, @code{int_p_sign_posn}, @code{int_p_sep_by_space},
+@code{int_n_cs_precedes}, @code{int_n_sign_posn}, @code{int_n_sep_by_space}
+on some platforms:
+glibc.
+
+@item
 Some platforms provide a @code{NULL} macro that cannot be used in arbitrary
 expressions:
 NetBSD 5.0
@@ -23,4 +34,10 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
+@item
+The @code{struct lconv} type does not contain the members
+@code{int_p_cs_precedes}, @code{int_p_sign_posn}, @code{int_p_sep_by_space},
+@code{int_n_cs_precedes}, @code{int_n_sign_posn}, @code{int_n_sep_by_space}
+on some platforms:
+OpenBSD 4.9, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 11 2011-11, Cygwin 1.5.x, mingw, MSVC 9.
 @end itemize
--- a/lib/locale.in.h
+++ b/lib/locale.in.h
@@ -47,6 +47,87 @@
 # define LC_MESSAGES 1729
 #endif
 
+/* Bionic libc's 'struct lconv' is just a dummy.  */
+#if @REPLACE_STRUCT_LCONV@
+# define lconv rpl_lconv
+struct lconv
+{
+  /* All 'char *' are actually 'const char *'.  */
+
+  /* Members that depend on the LC_NUMERIC category of the locale.  See
+     <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_04> */
+
+  /* Symbol used as decimal point.  */
+  char *decimal_point;
+  /* Symbol used to separate groups of digits to the left of the decimal
+     point.  */
+  char *thousands_sep;
+  /* Definition of the size of groups of digits to the left of the decimal
+     point.  */
+  char *grouping;
+
+  /* Members that depend on the LC_MONETARY category of the locale.  See
+     <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_03> */
+
+  /* Symbol used as decimal point.  */
+  char *mon_decimal_point;
+  /* Symbol used to separate groups of digits to the left of the decimal
+     point.  */
+  char *mon_thousands_sep;
+  /* Definition of the size of groups of digits to the left of the decimal
+     point.  */
+  char *mon_grouping;
+  /* Sign used to indicate a value >= 0.  */
+  char *positive_sign;
+  /* Sign used to indicate a value < 0.  */
+  char *negative_sign;
+
+  /* For formatting local currency.  */
+  /* Currency symbol (3 characters) followed by separator (1 character).  */
+  char *currency_symbol;
+  /* Number of digits after the decimal point.  */
+  char frac_digits;
+  /* For values >= 0: 1 if the currency symbol precedes the number, 0 if it
+     comes after the number.  */
+  char p_cs_precedes;
+  /* For values >= 0: Position of the sign.  */
+  char p_sign_posn;
+  /* For values >= 0: Placement of spaces between currency symbol, sign, and
+     number.  */
+  char p_sep_by_space;
+  /* For values < 0: 1 if the currency symbol precedes the number, 0 if it
+     comes after the number.  */
+  char n_cs_precedes;
+  /* For values < 0: Position of the sign.  */
+  char n_sign_posn;
+  /* For values < 0: Placement of spaces between currency symbol, sign, and
+     number.  */
+  char n_sep_by_space;
+
+  /* For formatting international currency.  */
+  /* Currency symbol (3 characters) followed by separator (1 character).  */
+  char *int_curr_symbol;
+  /* Number of digits after the decimal point.  */
+  char int_frac_digits;
+  /* For values >= 0: 1 if the currency symbol precedes the number, 0 if it
+     comes after the number.  */
+  char int_p_cs_precedes;
+  /* For values >= 0: Position of the sign.  */
+  char int_p_sign_posn;
+  /* For values >= 0: Placement of spaces between currency symbol, sign, and
+     number.  */
+  char int_p_sep_by_space;
+  /* For values < 0: 1 if the currency symbol precedes the number, 0 if it
+     comes after the number.  */
+  char int_n_cs_precedes;
+  /* For values < 0: Position of the sign.  */
+  char int_n_sign_posn;
+  /* For values < 0: Placement of spaces between currency symbol, sign, and
+     number.  */
+  char int_n_sep_by_space;
+};
+#endif
+
 #if @GNULIB_SETLOCALE@
 # if @REPLACE_SETLOCALE@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
--- a/m4/locale_h.m4
+++ b/m4/locale_h.m4
@@ -1,4 +1,4 @@
-# locale_h.m4 serial 14
+# locale_h.m4 serial 15
 dnl Copyright (C) 2007, 2009-2012 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -10,7 +10,8 @@
   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.
+  dnl Persuade glibc <locale.h> to define locale_t and the int_p_*, int_n_*
+  dnl members of 'struct lconv'.
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
 
   dnl If <stddef.h> is replaced, then <locale.h> must also be replaced.
@@ -21,7 +22,8 @@
     [AC_COMPILE_IFELSE(
        [AC_LANG_PROGRAM(
           [[#include <locale.h>
-            int x = LC_MESSAGES;]],
+            int x = LC_MESSAGES;
+            int y = sizeof (((struct lconv *) 0)->decimal_point);]],
           [[]])],
        [gl_cv_header_locale_h_posix2001=yes],
        [gl_cv_header_locale_h_posix2001=no])])
@@ -54,6 +56,23 @@
   fi
   AC_SUBST([HAVE_XLOCALE_H])
 
+  dnl Check whether 'struct lconv' is well-defined.
+  dnl Bionic libc's 'struct lconv' is just a dummy.
+  AC_CACHE_CHECK([whether struct lconv is properly defined],
+    [gl_cv_sys_struct_lconv_ok],
+    [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <locale.h>
+            struct lconv l;
+            int x = sizeof (l.decimal_point);]],
+          [[]])],
+       [gl_cv_sys_struct_lconv_ok=yes],
+       [gl_cv_sys_struct_lconv_ok=no])
+    ])
+  if test $gl_cv_sys_struct_lconv_ok = no; then
+    REPLACE_STRUCT_LCONV=1
+  fi
+
   dnl <locale.h> is always overridden, because of GNULIB_POSIXCHECK.
   gl_NEXT_HEADERS([locale.h])
 
@@ -82,7 +101,8 @@
   GNULIB_SETLOCALE=0;  AC_SUBST([GNULIB_SETLOCALE])
   GNULIB_DUPLOCALE=0;  AC_SUBST([GNULIB_DUPLOCALE])
   dnl Assume proper GNU behavior unless another module says otherwise.
-  HAVE_DUPLOCALE=1;    AC_SUBST([HAVE_DUPLOCALE])
-  REPLACE_SETLOCALE=0; AC_SUBST([REPLACE_SETLOCALE])
-  REPLACE_DUPLOCALE=0; AC_SUBST([REPLACE_DUPLOCALE])
+  HAVE_DUPLOCALE=1;       AC_SUBST([HAVE_DUPLOCALE])
+  REPLACE_SETLOCALE=0;    AC_SUBST([REPLACE_SETLOCALE])
+  REPLACE_DUPLOCALE=0;    AC_SUBST([REPLACE_DUPLOCALE])
+  REPLACE_STRUCT_LCONV=0; AC_SUBST([REPLACE_STRUCT_LCONV])
 ])
--- a/modules/locale
+++ b/modules/locale
@@ -35,6 +35,7 @@
 	      -e 's|@''HAVE_XLOCALE_H''@|$(HAVE_XLOCALE_H)|g' \
 	      -e 's|@''REPLACE_SETLOCALE''@|$(REPLACE_SETLOCALE)|g' \
 	      -e 's|@''REPLACE_DUPLOCALE''@|$(REPLACE_DUPLOCALE)|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)' \
 	      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
--- a/tests/test-locale.c
+++ b/tests/test-locale.c
@@ -38,6 +38,10 @@
 locale_t b = LC_GLOBAL_LOCALE;
 #endif
 
+/* Check that the 'struct lconv' type is defined.  */
+struct lconv l;
+int ls;
+
 /* Check that NULL can be passed through varargs as a pointer type,
    per POSIX 2008.  */
 verify (sizeof NULL == sizeof (void *));
@@ -45,5 +49,33 @@
 int
 main ()
 {
+  /* Check that 'struct lconv' has the ISO C and POSIX specified members.  */
+  ls += sizeof (*l.decimal_point);
+  ls += sizeof (*l.thousands_sep);
+  ls += sizeof (*l.grouping);
+  ls += sizeof (*l.mon_decimal_point);
+  ls += sizeof (*l.mon_thousands_sep);
+  ls += sizeof (*l.mon_grouping);
+  ls += sizeof (*l.positive_sign);
+  ls += sizeof (*l.negative_sign);
+  ls += sizeof (*l.currency_symbol);
+  ls += sizeof (l.frac_digits);
+  ls += sizeof (l.p_cs_precedes);
+  ls += sizeof (l.p_sign_posn);
+  ls += sizeof (l.p_sep_by_space);
+  ls += sizeof (l.n_cs_precedes);
+  ls += sizeof (l.n_sign_posn);
+  ls += sizeof (l.n_sep_by_space);
+  ls += sizeof (*l.int_curr_symbol);
+  ls += sizeof (l.int_frac_digits);
+#if 0
+  ls += sizeof (l.int_p_cs_precedes);
+  ls += sizeof (l.int_p_sign_posn);
+  ls += sizeof (l.int_p_sep_by_space);
+  ls += sizeof (l.int_n_cs_precedes);
+  ls += sizeof (l.int_n_sign_posn);
+  ls += sizeof (l.int_n_sep_by_space);
+#endif
+
   return 0;
 }