]> Savannah Git Hosting - gnulib.git/commitdiff
duplocale: Support all platforms.
authorBruno Haible <bruno@clisp.org>
Fri, 14 Feb 2025 04:56:55 +0000 (05:56 +0100)
committerBruno Haible <bruno@clisp.org>
Fri, 14 Feb 2025 05:03:31 +0000 (06:03 +0100)
* lib/locale.in.h (duplocale): Declare also on platforms that don't
already have a duplocale function. Don't define HAVE_WORKING_DUPLOCALE.
* lib/duplocale.c: Include <stdlib.h>.
(duplocale): Renamed from rpl_duplocale. Add implementation for
platforms without native locale_t.
* modules/duplocale (Depends-on): Add newlocale, freelocale.
(configure.ac): Compile also on platforms without native locale_t.
* tests/test-duplocale.c: Ignore HAVE_WORKING_DUPLOCALE.
* tests/test-locale-h-c++.cc: Likewise.
* doc/posix-functions/duplocale.texi: Mention the change.

ChangeLog
doc/posix-functions/duplocale.texi
lib/duplocale.c
lib/locale.in.h
modules/duplocale
tests/test-duplocale.c
tests/test-locale-h-c++.cc

index 712f90be04b3e9bac237fbbc6013a913235d6fd6..50b6a1daf3c77910ec0cbeefd236378f7e51cb89 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2025-02-14  Bruno Haible  <bruno@clisp.org>
+
+       duplocale: Support all platforms.
+       * lib/locale.in.h (duplocale): Declare also on platforms that don't
+       already have a duplocale function. Don't define HAVE_WORKING_DUPLOCALE.
+       * lib/duplocale.c: Include <stdlib.h>.
+       (duplocale): Renamed from rpl_duplocale. Add implementation for
+       platforms without native locale_t.
+       * modules/duplocale (Depends-on): Add newlocale, freelocale.
+       (configure.ac): Compile also on platforms without native locale_t.
+       * tests/test-duplocale.c: Ignore HAVE_WORKING_DUPLOCALE.
+       * tests/test-locale-h-c++.cc: Likewise.
+       * doc/posix-functions/duplocale.texi: Mention the change.
+
 2025-02-14  Bruno Haible  <bruno@clisp.org>
 
        freelocale: Fix typo.
index 4d5e919b52cd8ec4a8df932f097daf709f9b7242..efcb847ca6bde77026c9fc06e18b0d97b4dfaab1 100644 (file)
@@ -10,6 +10,13 @@ Gnulib module: duplocale
 Portability problems fixed by Gnulib:
 @itemize
 @item
+This function is missing on many platforms:
+FreeBSD 9.0, NetBSD 6.1, OpenBSD 6.1, Minix 3.1.8, AIX 6.1, HP-UX 11, Solaris 11.3, Cygwin 2.5.x, mingw, MSVC 14, Android 4.4.
+@item
+This function is useless because the @code{locale_t} type is not defined
+on some platforms:
+z/OS.
+@item
 The argument @code{LC_GLOBAL_LOCALE} is not supported on some platforms:
 glibc 2.11, AIX 7.1.
 @item
@@ -21,13 +28,6 @@ NetBSD 7.1.
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-This function is missing on many platforms:
-FreeBSD 9.0, NetBSD 5.0, OpenBSD 6.1, Minix 3.1.8, AIX 6.1, HP-UX 11, Solaris 11.3, Cygwin 2.5.x, mingw, MSVC 14, Android 4.4.
-@item
-This function is useless because the @code{locale_t} type is not defined
-on some platforms:
-z/OS.
-@item
 With the argument @code{LC_GLOBAL_LOCALE}, this function returns a wrong result
 on some platforms:
 @c https://dev.haiku-os.org/ticket/18345
index 933c4bbf38be16177730043a941ca09e6697b2d7..47a626e1e6c106d1e83901449177d71a92913e16 100644 (file)
 #include <locale.h>
 
 #include <errno.h>
+#include <stdlib.h>
 #include <string.h>
 
 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
 
-#undef duplocale
-
 locale_t
-rpl_duplocale (locale_t locale)
+duplocale (locale_t locale)
+#undef duplocale
 {
-  /* Work around crash in the duplocale function in glibc < 2.12.
+  /* Implement duplocale(LC_GLOBAL_LOCALE) on platforms without locale_t.
+     Also, work around crash in the duplocale function in glibc < 2.12.
      See <https://sourceware.org/bugzilla/show_bug.cgi?id=10969>.
      Also, on AIX 7.1, duplocale(LC_GLOBAL_LOCALE) returns (locale_t)0 with
      errno set to EINVAL.
@@ -113,5 +114,75 @@ rpl_duplocale (locale_t locale)
       return base_copy;
     }
 
+#if GNULIB_defined_locale_t
+
+  locale_t result = (struct gl_locale_t *) malloc (sizeof (struct gl_locale_t));
+  if (result == NULL)
+    {
+      errno = ENOMEM;
+      return NULL;
+    }
+
+  int i;
+  int err;
+  for (i = 0; i < 6; i++)
+    {
+      int log2_lcmask = gl_index_to_log2_lcmask (i);
+
+      result->category[i].name = strdup (locale->category[i].name);
+      if (result->category[i].name == NULL)
+        {
+          err = ENOMEM;
+          goto fail_with_err;
+        }
+      result->category[i].is_c_locale = locale->category[i].is_c_locale;
+# if HAVE_WINDOWS_LOCALE_T
+      if (log2_lcmask == gl_log2_lc_mask (LC_MESSAGES)
+          || result->category[i].is_c_locale)
+        {
+          /* Just to initialize it.  */
+          result->category[i].system_locale = NULL;
+        }
+      else
+        {
+          int cat = log2_lcmask;
+          (void) cat;
+          /* Documentation:
+             <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/create-locale-wcreate-locale>  */
+          result->category[i].system_locale =
+            _create_locale (LC_ALL /* or cat */, result->category[i].name);
+          if (result->category[i].system_locale == NULL)
+            {
+              free (result->category[i].name);
+              err = ENOENT;
+              goto fail_with_err;
+            }
+        }
+# endif
+    }
+
+  /* Success.  */
+  return result;
+
+ fail_with_err:
+  while (--i >= 0)
+    {
+# if HAVE_WINDOWS_LOCALE_T
+      if (!(i == gl_log2_lcmask_to_index (gl_log2_lc_mask (LC_MESSAGES))
+            || result->category[i].is_c_locale))
+        /* Documentation:
+           <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/free-locale>  */
+        _free_locale (result->category[i].system_locale);
+# endif
+      free (result->category[i].name);
+    }
+  free (result);
+  errno = err;
+  return NULL;
+
+#else
+
   return duplocale (locale);
+
+#endif
 }
index 3d4f34f579b0484e5a0bf7939744461441fa2203..7c35b283ded3a003bb766f9c90e1e020dfad3d0b 100644 (file)
@@ -332,31 +332,27 @@ _GL_WARN_ON_USE (newlocale, "newlocale is not portable");
 #endif
 
 #if @GNULIB_DUPLOCALE@ || (@GNULIB_LOCALENAME_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_DUPLOCALE@)
-# if @HAVE_DUPLOCALE@ /* locale_t may be undefined if !@HAVE_DUPLOCALE@.  */
-#  if @REPLACE_DUPLOCALE@
-#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
-#    undef duplocale
-#    define duplocale rpl_duplocale
-#    define GNULIB_defined_duplocale 1
-#   endif
+# if @REPLACE_DUPLOCALE@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef duplocale
+#   define duplocale rpl_duplocale
+#   define GNULIB_defined_duplocale 1
+#  endif
 _GL_FUNCDECL_RPL (duplocale, locale_t, (locale_t locale), _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_RPL (duplocale, locale_t, (locale_t locale));
-#  else
-_GL_CXXALIAS_SYS (duplocale, locale_t, (locale_t locale));
+# else
+#  if !@HAVE_DUPLOCALE@
+_GL_FUNCDECL_SYS (duplocale, locale_t, (locale_t locale), _GL_ARG_NONNULL ((1)));
 #  endif
+_GL_CXXALIAS_SYS (duplocale, locale_t, (locale_t locale));
 # endif
-# if __GLIBC__ >= 2 && @HAVE_DUPLOCALE@
+# if __GLIBC__ >= 2
 _GL_CXXALIASWARN (duplocale);
 # endif
-# if @HAVE_DUPLOCALE@
-#  ifndef HAVE_WORKING_DUPLOCALE
-#   define HAVE_WORKING_DUPLOCALE 1
-#  endif
-# endif
 #elif defined GNULIB_POSIXCHECK
 # undef duplocale
 # if HAVE_RAW_DECL_DUPLOCALE
-_GL_WARN_ON_USE (duplocale, "duplocale is buggy on some glibc systems - "
+_GL_WARN_ON_USE (duplocale, "duplocale is unportable and buggy on some glibc systems - "
                  "use gnulib module duplocale for portability");
 # endif
 #endif
index 8ccc964a43b1f4215bf589e938be718e212db62b..8d34e9476ac6cc4dbe9da9a418ae6b2e74cf3f79 100644 (file)
@@ -7,12 +7,14 @@ m4/duplocale.m4
 
 Depends-on:
 locale-h
-setlocale-null  [test $HAVE_DUPLOCALE = 1 && test $REPLACE_DUPLOCALE = 1]
+freelocale      [test $HAVE_LOCALE_T = 0 || { test $HAVE_DUPLOCALE = 1 && test $REPLACE_DUPLOCALE = 1; }]
+newlocale       [test $HAVE_LOCALE_T = 0 || { test $HAVE_DUPLOCALE = 1 && test $REPLACE_DUPLOCALE = 1; }]
+setlocale-null  [test $HAVE_LOCALE_T = 0 || { test $HAVE_DUPLOCALE = 1 && test $REPLACE_DUPLOCALE = 1; }]
 
 configure.ac:
 gl_FUNC_DUPLOCALE
 gl_CONDITIONAL([GL_COND_OBJ_DUPLOCALE],
-               [test $HAVE_DUPLOCALE = 1 && test $REPLACE_DUPLOCALE = 1])
+               [test $HAVE_LOCALE_T = 0 || { test $HAVE_DUPLOCALE = 1 && test $REPLACE_DUPLOCALE = 1; }])
 AM_COND_IF([GL_COND_OBJ_DUPLOCALE], [
   gl_PREREQ_DUPLOCALE
 ])
index bce2491c0da660b5062d03732ac564fd50b6e96a..cc348441e4d855d98b1930b80031ab18bc11fe29 100644 (file)
@@ -20,8 +20,6 @@
 
 #include <locale.h>
 
-#if HAVE_WORKING_DUPLOCALE
-
 #include "signature.h"
 SIGNATURE_CHECK (duplocale, locale_t, (locale_t));
 
@@ -234,16 +232,3 @@ main ()
 
   return test_exit_status;
 }
-
-#else
-
-#include <stdio.h>
-
-int
-main ()
-{
-  fprintf (stderr, "Skipping test: function duplocale not available\n");
-  return 77;
-}
-
-#endif
index f2bcfaa71d42195f5d26c49c8be2d0c1cf148cd2..5a6a2a195bbef54e011a5a3683cf5f105c5e558f 100644 (file)
@@ -36,7 +36,7 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::setlocale, char *, (int, const char *));
 SIGNATURE_CHECK (GNULIB_NAMESPACE::newlocale, locale_t, (int, const char *, locale_t));
 #endif
 
-#if GNULIB_TEST_DUPLOCALE && HAVE_WORKING_DUPLOCALE
+#if GNULIB_TEST_DUPLOCALE
 SIGNATURE_CHECK (GNULIB_NAMESPACE::duplocale, locale_t, (locale_t));
 #endif