+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.
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
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
#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.
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
}
#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
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
])
#include <locale.h>
-#if HAVE_WORKING_DUPLOCALE
-
#include "signature.h"
SIGNATURE_CHECK (duplocale, locale_t, (locale_t));
return test_exit_status;
}
-
-#else
-
-#include <stdio.h>
-
-int
-main ()
-{
- fprintf (stderr, "Skipping test: function duplocale not available\n");
- return 77;
-}
-
-#endif
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