bug-gnulib
[Top][All Lists]
Advanced

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

localeconv: Work around a mingw bug


From: Bruno Haible
Subject: localeconv: Work around a mingw bug
Date: Fri, 28 Apr 2023 01:14:41 +0200

On mingw 5.0.3 I see this test failure:

FAIL: test-localeconv
=====================

../../gltests/test-localeconv.c:53: assertion 'l->frac_digits == CHAR_MAX' 
failed
FAIL test-localeconv.exe (exit status: 3)

Here, l->frac_digits is -1 instead of 127, and likewise for the other fields
of 'struct lconv' that are of type 'char'.

This patch provides a workaround.


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.

diff --git a/doc/posix-functions/localeconv.texi 
b/doc/posix-functions/localeconv.texi
index 22a19ca3d3..ebcc5a5b29 100644
--- a/doc/posix-functions/localeconv.texi
+++ b/doc/posix-functions/localeconv.texi
@@ -17,6 +17,10 @@
 @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:
diff --git a/lib/localeconv.c b/lib/localeconv.c
index 60c050f486..c1a34baa05 100644
--- a/lib/localeconv.c
+++ b/lib/localeconv.c
@@ -19,10 +19,14 @@
 /* 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)
 {
diff --git a/m4/localeconv.m4 b/m4/localeconv.m4
index ae225fed66..374dcbf54f 100644
--- a/m4/localeconv.m4
+++ b/m4/localeconv.m4
@@ -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>]])
 ])






reply via email to

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