"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
/* 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 <libintl.h>),
b. when setlocale supports only the "C" locale, such as on Cygwin
# 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[] =
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. */
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. */
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. */
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);
}
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. */
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);
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");
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");
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. */
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);
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");
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. */
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);
}
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);
}