From 55b2f23f298f16802baf844d9dd150dba298fd00 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 25 Mar 2012 13:22:41 +0200 Subject: [PATCH] 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 . --- ChangeLog | 13 +++++++ doc/posix-headers/locale.texi | 17 +++++++++ lib/locale.in.h | 81 +++++++++++++++++++++++++++++++++++++++++++ m4/locale_h.m4 | 32 +++++++++++++---- modules/locale | 1 + tests/test-locale.c | 32 +++++++++++++++++ 6 files changed, 170 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index efac2e4c6..4e0bca513 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2012-03-25 Bruno Haible + + 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 . + 2012-03-24 Bruno Haible Enable common subexpression optimization in GCC. diff --git a/doc/posix-headers/locale.texi b/doc/posix-headers/locale.texi index 5f8dc8cff..9ea582691 100644 --- a/doc/posix-headers/locale.texi +++ b/doc/posix-headers/locale.texi @@ -16,6 +16,17 @@ The @code{locale_t} type is not defined on some platforms: 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 @@ NetBSD 5.0 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 diff --git a/lib/locale.in.h b/lib/locale.in.h index a97e3e791..41c641430 100644 --- 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 + */ + + /* 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 + */ + + /* 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) diff --git a/m4/locale_h.m4 b/m4/locale_h.m4 index 428958745..66146d8bd 100644 --- 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 @@ AC_DEFUN([gl_LOCALE_H], dnl once only, before all statements that occur in other macros. AC_REQUIRE([gl_LOCALE_H_DEFAULTS]) - dnl Persuade glibc to define locale_t. + dnl Persuade glibc to define locale_t and the int_p_*, int_n_* + dnl members of 'struct lconv'. AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) dnl If is replaced, then must also be replaced. @@ -21,7 +22,8 @@ AC_DEFUN([gl_LOCALE_H], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include - 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 @@ AC_DEFUN([gl_LOCALE_H], 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 + 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 is always overridden, because of GNULIB_POSIXCHECK. gl_NEXT_HEADERS([locale.h]) @@ -82,7 +101,8 @@ AC_DEFUN([gl_LOCALE_H_DEFAULTS], 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]) ]) diff --git a/modules/locale b/modules/locale index 4c66c84e2..09f2d67e2 100644 --- a/modules/locale +++ b/modules/locale @@ -35,6 +35,7 @@ locale.h: locale.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -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)' \ diff --git a/tests/test-locale.c b/tests/test-locale.c index 1cd3daccd..1dafdf375 100644 --- a/tests/test-locale.c +++ b/tests/test-locale.c @@ -38,6 +38,10 @@ int a[] = 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 @@ verify (sizeof NULL == sizeof (void *)); 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; } -- 2.11.0