localeconv: Work around a mingw bug.
authorBruno Haible <bruno@clisp.org>
Thu, 27 Apr 2023 23:12:16 +0000 (01:12 +0200)
committerBruno Haible <bruno@clisp.org>
Thu, 27 Apr 2023 23:12:16 +0000 (01:12 +0200)
* m4/localeconv.m4 (gl_FUNC_LOCALECONV): Test whether fields of type
'char' are filled correctly.
(gl_PREREQ_LOCALECONV): Test whether 'struct lconv' has the int_{p,n}_*
members.
* lib/localeconv.c (FIX_CHAR_VALUE): New macro.
(localeconv): Replace negative field values with CHAR_MAX.
* doc/posix-functions/localeconv.texi: Mention the mingw bug.

ChangeLog
doc/posix-functions/localeconv.texi
lib/localeconv.c
m4/localeconv.m4

index a41aeff43ed74202ca9db6b53f86e1fab6caf37a..3932a30ae183daba2a940c9a46951f4b8c9639f6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2023-04-27  Bruno Haible  <bruno@clisp.org>
+
+       localeconv: Work around a mingw bug.
+       * m4/localeconv.m4 (gl_FUNC_LOCALECONV): Test whether fields of type
+       'char' are filled correctly.
+       (gl_PREREQ_LOCALECONV): Test whether 'struct lconv' has the int_{p,n}_*
+       members.
+       * lib/localeconv.c (FIX_CHAR_VALUE): New macro.
+       (localeconv): Replace negative field values with CHAR_MAX.
+       * doc/posix-functions/localeconv.texi: Mention the mingw bug.
+
 2023-04-27  Bruno Haible  <bruno@clisp.org>
 
        stdlib: Fix error when cross-compiling (regression 2023-04-04).
index 22a19ca3d38e3ff3c2a220df42a20d99a441a773..ebcc5a5b29699d153366203bf95d2a95bf2bc3a6 100644 (file)
@@ -17,6 +17,10 @@ The @code{struct lconv} type does not contain the members
 @code{int_n_cs_precedes}, @code{int_n_sign_posn}, @code{int_n_sep_by_space}
 on some platforms:
 glibc, OpenBSD 4.9, HP-UX 11, IRIX 6.5, Solaris 11.4, Cygwin 1.5.x, mingw, MSVC 14.
+@item
+The values of fields of @code{struct lconv} of type @code{char} are -1 instead
+of CHAR_MAX on some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
index 60c050f48693a755ddcd28daf00c7bf63a57e88f..c1a34baa0599c2a8281aba96bd67afbb1bedf442 100644 (file)
 /* Specification.  */
 #include <locale.h>
 
+#include <limits.h>
+
 #if HAVE_STRUCT_LCONV_DECIMAL_POINT
 
+# define FIX_CHAR_VALUE(x) ((x) >= 0 ? (x) : CHAR_MAX)
+
 /* Override for platforms where 'struct lconv' lacks the int_p_*, int_n_*
-   members.  */
+   members or where fields of type 'char' are set to -1 instead of CHAR_MAX.  */
 
 struct lconv *
 localeconv (void)
@@ -41,21 +45,30 @@ localeconv (void)
   result.positive_sign = sys_result->positive_sign;
   result.negative_sign = sys_result->negative_sign;
   result.currency_symbol = sys_result->currency_symbol;
-  result.frac_digits = sys_result->frac_digits;
-  result.p_cs_precedes = sys_result->p_cs_precedes;
-  result.p_sign_posn = sys_result->p_sign_posn;
-  result.p_sep_by_space = sys_result->p_sep_by_space;
-  result.n_cs_precedes = sys_result->n_cs_precedes;
-  result.n_sign_posn = sys_result->n_sign_posn;
-  result.n_sep_by_space = sys_result->n_sep_by_space;
+  result.frac_digits = FIX_CHAR_VALUE (sys_result->frac_digits);
+  result.p_cs_precedes = FIX_CHAR_VALUE (sys_result->p_cs_precedes);
+  result.p_sign_posn = FIX_CHAR_VALUE (sys_result->p_sign_posn);
+  result.p_sep_by_space = FIX_CHAR_VALUE (sys_result->p_sep_by_space);
+  result.n_cs_precedes = FIX_CHAR_VALUE (sys_result->n_cs_precedes);
+  result.n_sign_posn = FIX_CHAR_VALUE (sys_result->n_sign_posn);
+  result.n_sep_by_space = FIX_CHAR_VALUE (sys_result->n_sep_by_space);
   result.int_curr_symbol = sys_result->int_curr_symbol;
-  result.int_frac_digits = sys_result->int_frac_digits;
-  result.int_p_cs_precedes = sys_result->p_cs_precedes;
-  result.int_p_sign_posn = sys_result->p_sign_posn;
-  result.int_p_sep_by_space = sys_result->p_sep_by_space;
-  result.int_n_cs_precedes = sys_result->n_cs_precedes;
-  result.int_n_sign_posn = sys_result->n_sign_posn;
-  result.int_n_sep_by_space = sys_result->n_sep_by_space;
+  result.int_frac_digits = FIX_CHAR_VALUE (sys_result->int_frac_digits);
+# if HAVE_STRUCT_LCONV_INT_P_CS_PRECEDES
+  result.int_p_cs_precedes = FIX_CHAR_VALUE (sys_result->int_p_cs_precedes);
+  result.int_p_sign_posn = FIX_CHAR_VALUE (sys_result->int_p_sign_posn);
+  result.int_p_sep_by_space = FIX_CHAR_VALUE (sys_result->int_p_sep_by_space);
+  result.int_n_cs_precedes = FIX_CHAR_VALUE (sys_result->int_n_cs_precedes);
+  result.int_n_sign_posn = FIX_CHAR_VALUE (sys_result->int_n_sign_posn);
+  result.int_n_sep_by_space = FIX_CHAR_VALUE (sys_result->int_n_sep_by_space);
+# else
+  result.int_p_cs_precedes = FIX_CHAR_VALUE (sys_result->p_cs_precedes);
+  result.int_p_sign_posn = FIX_CHAR_VALUE (sys_result->p_sign_posn);
+  result.int_p_sep_by_space = FIX_CHAR_VALUE (sys_result->p_sep_by_space);
+  result.int_n_cs_precedes = FIX_CHAR_VALUE (sys_result->n_cs_precedes);
+  result.int_n_sign_posn = FIX_CHAR_VALUE (sys_result->n_sign_posn);
+  result.int_n_sep_by_space = FIX_CHAR_VALUE (sys_result->n_sep_by_space);
+# endif
 
   return &result;
 }
@@ -64,8 +77,6 @@ localeconv (void)
 
 /* Override for platforms where 'struct lconv' is a dummy.  */
 
-# include <limits.h>
-
 struct lconv *
 localeconv (void)
 {
index ae225fed6633391926662ac699038ae207f5f559..374dcbf54fe39f8fa4830c9e21ae6672b7b042ed 100644 (file)
@@ -1,4 +1,4 @@
-# localeconv.m4 serial 1
+# localeconv.m4 serial 2
 dnl Copyright (C) 2012-2023 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,10 +8,45 @@ AC_DEFUN([gl_FUNC_LOCALECONV],
 [
   AC_REQUIRE([gl_LOCALE_H_DEFAULTS])
   AC_REQUIRE([gl_LOCALE_H])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
 
   if test $REPLACE_STRUCT_LCONV = 1; then
     REPLACE_LOCALECONV=1
   fi
+  if test $REPLACE_LOCALECONV = 0; then
+    dnl Test whether fields of type 'char' are filled correctly.
+    dnl This test fails on mingw 5.0.3.
+    AC_CACHE_CHECK([whether localeconv works],
+      [gl_cv_func_localeconv_works],
+      [AC_RUN_IFELSE(
+         [AC_LANG_SOURCE([[
+            #include <locale.h>
+            #include <limits.h>
+            int main ()
+            {
+              struct lconv *l = localeconv ();
+              return l->frac_digits != CHAR_MAX && l->frac_digits < 0;
+            }
+         ]])],
+         [gl_cv_func_localeconv_works=yes],
+         [gl_cv_func_localeconv_works=no],
+         [case "$host_os" in
+                                # Guess yes on glibc systems.
+            *-gnu* | gnu*)      gl_cv_func_localeconv_works="guessing yes" ;;
+                                # Guess yes on musl systems.
+            *-musl* | midipix*) gl_cv_func_localeconv_works="guessing yes" ;;
+                                # Guess no on native Windows.
+            mingw*)             gl_cv_func_localeconv_works="guessing no" ;;
+                                # If we don't know, obey --enable-cross-guesses.
+            *)                  gl_cv_func_localeconv_works="$gl_cross_guess_normal" ;;
+          esac
+         ])
+      ])
+    case "$gl_cv_func_localeconv_works" in
+      *yes) ;;
+      *) REPLACE_LOCALECONV=1 ;;
+    esac
+  fi
 ])
 
 # Prerequisites of lib/localeconv.c.
@@ -19,4 +54,6 @@ AC_DEFUN([gl_PREREQ_LOCALECONV],
 [
   AC_CHECK_MEMBERS([struct lconv.decimal_point], [], [],
     [[#include <locale.h>]])
+  AC_CHECK_MEMBERS([struct lconv.int_p_cs_precedes], [], [],
+    [[#include <locale.h>]])
 ])