From 9c99c0b81f7c384d94f2ae941844e2cba56a07e5 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Thu, 15 Feb 2024 01:33:51 +0100 Subject: [PATCH] localename: Notice setlocale() invocations on more platforms. * lib/localename.c (HAVE_LOCALE_NULL): Define also on musl, FreeBSD, NetBSD, Solaris, Haiku. * modules/localename (Files): Add m4/musl.m4. (configure.ac): Invoke gl_MUSL_LIBC. * tests/test-localename.c (C_CANONICALIZED): New macro, for Haiku. (is_default): New function, for musl libc and Haiku. (test_locale_name, test_locale_name_posix): Use these definitions. * modules/localename-tests (Files): Add m4/musl.m4. (configure.ac): Invoke gl_MUSL_LIBC. --- ChangeLog | 13 ++++++++ lib/localename.c | 32 +++++++++++++++--- modules/localename | 2 ++ modules/localename-tests | 2 ++ tests/test-localename.c | 71 +++++++++++++++++++++++++--------------- 5 files changed, 88 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4a7ef0fb85..023c1d4d50 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2024-02-14 Bruno Haible + + localename: Notice setlocale() invocations on more platforms. + * lib/localename.c (HAVE_LOCALE_NULL): Define also on musl, FreeBSD, + NetBSD, Solaris, Haiku. + * modules/localename (Files): Add m4/musl.m4. + (configure.ac): Invoke gl_MUSL_LIBC. + * tests/test-localename.c (C_CANONICALIZED): New macro, for Haiku. + (is_default): New function, for musl libc and Haiku. + (test_locale_name, test_locale_name_posix): Use these definitions. + * modules/localename-tests (Files): Add m4/musl.m4. + (configure.ac): Invoke gl_MUSL_LIBC. + 2024-02-14 Bruno Haible Don't treat Apple's new Citrus/FreeBSD-based iconv like GNU libiconv. diff --git a/lib/localename.c b/lib/localename.c index b4c78df8ae..3bfcdabf4f 100644 --- a/lib/localename.c +++ b/lib/localename.c @@ -3297,9 +3297,31 @@ gl_locale_name_thread (int category, _GL_UNUSED const char *categoryname) "Directs 'setlocale()' to query 'category' and return the current setting of 'local'." However it does not specify the exact format. Neither do SUSV2 and - ISO C 99. So we can use this feature only on selected systems (e.g. - those using GNU C Library). */ -#if defined _LIBC || ((defined __GLIBC__ && __GLIBC__ >= 2) && !defined __UCLIBC__) + ISO C 99. So we can use this feature only on selected systems, where + the return value has the XPG syntax + language[_territory][.codeset][@modifier] + or + C[.codeset] + namely + - glibc systems (except for aliases from /usr/share/locale/locale.alias, + that no one uses any more), + - musl libc, + - FreeBSD, NetBSD, + - Solaris, + - Haiku. + We cannot use it on + - macOS, Cygwin (because these systems have a facility for customizing the + default locale, and setlocale (category, NULL) ignores it and merely + returns "C" or "C.UTF-8"), + - OpenBSD (because on OpenBSD ≤ 6.1, LC_ALL does not set the LC_NUMERIC, + LC_TIME, LC_COLLATE, LC_MONETARY categories). + - AIX (because here the return value has the syntax + language[_script]_territory[.codeset] + e.g. zh_Hans_CN.UTF-8), + - native Windows (because it has locale names such as French_France.1252), + - Android (because it only supports the C and C.UTF-8 locales). + */ +#if defined _LIBC || ((defined __GLIBC__ && __GLIBC__ >= 2) && !defined __UCLIBC__) || MUSL_LIBC || defined __FreeBSD__ || defined __NetBSD__ || defined __sun || defined __HAIKU__ # define HAVE_LOCALE_NULL #endif @@ -3334,8 +3356,8 @@ gl_locale_name_posix (int category, _GL_UNUSED const char *categoryname) /* On other systems we ignore what setlocale reports and instead look at the environment variables directly. This is necessary 1. on systems which have a facility for customizing the default locale - (Mac OS X, native Windows, Cygwin) and where the system's setlocale() - function ignores this default locale (Mac OS X, Cygwin), in two cases: + (macOS, native Windows, Cygwin) and where the system's setlocale() + function ignores this default locale (macOS, Cygwin), in two cases: a. when the user missed to use the setlocale() override from libintl (for example by not including ), b. when setlocale supports only the "C" locale, such as on Cygwin diff --git a/modules/localename b/modules/localename index fc097829be..4c33624548 100644 --- a/modules/localename +++ b/modules/localename @@ -10,6 +10,7 @@ m4/localename.m4 m4/intl-thread-locale.m4 m4/intlmacosx.m4 m4/lcmessage.m4 +m4/musl.m4 Depends-on: extensions @@ -26,6 +27,7 @@ thread-optim configure.ac: gl_LOCALENAME gl_LOCALE_MODULE_INDICATOR([localename]) +gl_MUSL_LIBC Makefile.am: lib_SOURCES += localename.c localename-table.c diff --git a/modules/localename-tests b/modules/localename-tests index f90d82da0d..0c24d5b4b6 100644 --- a/modules/localename-tests +++ b/modules/localename-tests @@ -1,6 +1,7 @@ Files: tests/test-localename.c tests/macros.h +m4/musl.m4 Depends-on: locale @@ -11,6 +12,7 @@ strdup configure.ac: gl_CHECK_FUNCS_ANDROID([newlocale], [[#include ]]) +gl_MUSL_LIBC Makefile.am: TESTS += test-localename diff --git a/tests/test-localename.c b/tests/test-localename.c index fe31201361..03b70527d5 100644 --- a/tests/test-localename.c +++ b/tests/test-localename.c @@ -40,6 +40,26 @@ # pragma GCC diagnostic ignored "-Wanalyzer-use-of-uninitialized-value" #endif +/* The name that setlocale(,NULL) returns for the "C" locale. */ +#ifdef __HAIKU__ +# define C_CANONICALIZED "POSIX" +#else +# define C_CANONICALIZED "C" +#endif + +static int +is_default (const char *name) +{ + return strcmp (name, gl_locale_name_default ()) == 0 + || (strcmp (name, C_CANONICALIZED) == 0 + && strcmp (gl_locale_name_default (), "C") == 0) +#if MUSL_LIBC + || (strcmp (name, "C.UTF-8") == 0 + && strcmp (gl_locale_name_default (), "C") == 0) +#endif + ; +} + #if HAVE_GOOD_USELOCALE static struct { int cat; int mask; const char *string; } const categories[] = @@ -110,10 +130,8 @@ test_locale_name (void) unsetenv ("LC_TELEPHONE"); ret = setlocale (LC_ALL, ""); ASSERT (ret != NULL); - ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), - gl_locale_name_default ()) == 0); - ASSERT (strcmp (gl_locale_name (LC_NUMERIC, "LC_NUMERIC"), - gl_locale_name_default ()) == 0); + ASSERT (is_default (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"))); + ASSERT (is_default (gl_locale_name (LC_NUMERIC, "LC_NUMERIC"))); /* Check that an empty environment variable is treated like an unset environment variable. */ @@ -123,32 +141,28 @@ test_locale_name (void) unsetenv ("LC_MESSAGES"); unsetenv ("LANG"); setlocale (LC_ALL, ""); - ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), - gl_locale_name_default ()) == 0); + ASSERT (is_default (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"))); unsetenv ("LC_ALL"); setenv ("LC_CTYPE", "", 1); unsetenv ("LC_MESSAGES"); unsetenv ("LANG"); setlocale (LC_ALL, ""); - ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), - gl_locale_name_default ()) == 0); + ASSERT (is_default (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"))); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); setenv ("LC_MESSAGES", "", 1); unsetenv ("LANG"); setlocale (LC_ALL, ""); - ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), - gl_locale_name_default ()) == 0); + ASSERT (is_default (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"))); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); setenv ("LANG", "", 1); setlocale (LC_ALL, ""); - ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), - gl_locale_name_default ()) == 0); + ASSERT (is_default (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"))); /* Check that LC_ALL overrides the others, and LANG is overridden by the others. */ @@ -158,21 +172,24 @@ test_locale_name (void) unsetenv ("LC_MESSAGES"); unsetenv ("LANG"); setlocale (LC_ALL, ""); - ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), "C") == 0); + ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), + C_CANONICALIZED) == 0); unsetenv ("LC_ALL"); setenv ("LC_CTYPE", "C", 1); setenv ("LC_MESSAGES", "C", 1); unsetenv ("LANG"); setlocale (LC_ALL, ""); - ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), "C") == 0); + ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), + C_CANONICALIZED) == 0); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); setenv ("LANG", "C", 1); setlocale (LC_ALL, ""); - ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), "C") == 0); + ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), + C_CANONICALIZED) == 0); /* Check mixed situations. */ @@ -204,7 +221,7 @@ test_locale_name (void) if (setlocale (LC_ALL, "") != NULL) { name = gl_locale_name (LC_CTYPE, "LC_CTYPE"); - ASSERT (strcmp (name, gl_locale_name_default ()) == 0); + ASSERT (is_default (name)); name = gl_locale_name (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); } @@ -552,9 +569,9 @@ test_locale_name_posix (void) ret = setlocale (LC_ALL, ""); ASSERT (ret != NULL); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); - ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0); + ASSERT (name == NULL || is_default (name)); name = gl_locale_name_posix (LC_NUMERIC, "LC_NUMERIC"); - ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0); + ASSERT (name == NULL || is_default (name)); /* Check that an empty environment variable is treated like an unset environment variable. */ @@ -565,7 +582,7 @@ test_locale_name_posix (void) unsetenv ("LANG"); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); - ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0); + ASSERT (name == NULL || is_default (name)); unsetenv ("LC_ALL"); setenv ("LC_CTYPE", "", 1); @@ -573,7 +590,7 @@ test_locale_name_posix (void) unsetenv ("LANG"); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); - ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0); + ASSERT (name == NULL || is_default (name)); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); @@ -581,7 +598,7 @@ test_locale_name_posix (void) unsetenv ("LANG"); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); - ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0); + ASSERT (name == NULL || is_default (name)); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); @@ -589,7 +606,7 @@ test_locale_name_posix (void) setenv ("LANG", "", 1); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); - ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0); + ASSERT (name == NULL || is_default (name)); /* Check that LC_ALL overrides the others, and LANG is overridden by the others. */ @@ -600,7 +617,7 @@ test_locale_name_posix (void) unsetenv ("LANG"); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); - ASSERT (strcmp (name, "C") == 0); + ASSERT (strcmp (name, C_CANONICALIZED) == 0); unsetenv ("LC_ALL"); setenv ("LC_CTYPE", "C", 1); @@ -608,7 +625,7 @@ test_locale_name_posix (void) unsetenv ("LANG"); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); - ASSERT (strcmp (name, "C") == 0); + ASSERT (strcmp (name, C_CANONICALIZED) == 0); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); @@ -616,7 +633,7 @@ test_locale_name_posix (void) setenv ("LANG", "C", 1); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); - ASSERT (strcmp (name, "C") == 0); + ASSERT (strcmp (name, C_CANONICALIZED) == 0); /* Check mixed situations. */ @@ -643,7 +660,7 @@ test_locale_name_posix (void) if (setlocale (LC_ALL, "") != NULL) { name = gl_locale_name_posix (LC_CTYPE, "LC_CTYPE"); - ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0); + ASSERT (name == NULL || is_default (name)); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); } @@ -661,7 +678,7 @@ test_locale_name_posix (void) setlocale (LC_ALL, ""); uselocale (locale); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); - ASSERT (strcmp (name, "C") == 0); + ASSERT (strcmp (name, C_CANONICALIZED) == 0); uselocale (LC_GLOBAL_LOCALE); freelocale (locale); } -- 2.39.5