/* Test of gl_locale_name function and its variants. Copyright (C) 2007-2024 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* Written by Bruno Haible , 2007. */ #include #include "localename.h" #include #include #include #include "macros.h" #if HAVE_WORKING_NEWLOCALE && HAVE_WORKING_USELOCALE && !HAVE_FAKE_LOCALES # define HAVE_GOOD_USELOCALE 1 #endif #ifdef __HAIKU__ /* Work around Haiku bug . */ # define freelocale(loc) ((void) (loc)) #endif /* Suppress GCC false positive. */ #if _GL_GNUC_PREREQ (12, 0) # 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[] = { { LC_CTYPE, LC_CTYPE_MASK, "LC_CTYPE" }, { LC_NUMERIC, LC_NUMERIC_MASK, "LC_NUMERIC" }, { LC_TIME, LC_TIME_MASK, "LC_TIME" }, { LC_COLLATE, LC_COLLATE_MASK, "LC_COLLATE" }, { LC_MONETARY, LC_MONETARY_MASK, "LC_MONETARY" }, { LC_MESSAGES, LC_MESSAGES_MASK, "LC_MESSAGES" } # ifdef LC_PAPER , { LC_PAPER, LC_PAPER_MASK, "LC_PAPER" } # endif # ifdef LC_NAME , { LC_NAME, LC_NAME_MASK, "LC_NAME" } # endif # ifdef LC_ADDRESS , { LC_ADDRESS, LC_ADDRESS_MASK, "LC_ADDRESS" } # endif # ifdef LC_TELEPHONE , { LC_TELEPHONE, LC_TELEPHONE_MASK, "LC_TELEPHONE" } # endif # ifdef LC_MEASUREMENT , { LC_MEASUREMENT, LC_MEASUREMENT_MASK, "LC_MEASUREMENT" } # endif # ifdef LC_IDENTIFICATION , { LC_IDENTIFICATION, LC_IDENTIFICATION_MASK, "LC_IDENTIFICATION" } # endif }; #endif /* Test the gl_locale_name() function. */ static void test_locale_name (void) { const char *ret; const char *name; /* Check that gl_locale_name returns non-NULL. */ ASSERT (gl_locale_name (LC_MESSAGES, "LC_MESSAGES") != NULL); /* Get into a defined state, */ setlocale (LC_ALL, "en_US.UTF-8"); #if HAVE_GOOD_USELOCALE uselocale (LC_GLOBAL_LOCALE); #endif /* Check that when all environment variables are unset, gl_locale_name returns the default locale. */ unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); unsetenv ("LC_NUMERIC"); unsetenv ("LANG"); /* Need also to unset all environment variables that specify standard or non-standard locale categories. Otherwise, on glibc systems, when some of these variables are set and reference a nonexistent locale, the setlocale (LC_ALL, "") call below would fail. */ unsetenv ("LC_COLLATE"); unsetenv ("LC_MONETARY"); unsetenv ("LC_TIME"); unsetenv ("LC_ADDRESS"); unsetenv ("LC_IDENTIFICATION"); unsetenv ("LC_MEASUREMENT"); unsetenv ("LC_NAME"); unsetenv ("LC_PAPER"); unsetenv ("LC_TELEPHONE"); ret = setlocale (LC_ALL, ""); ASSERT (ret != NULL); 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. */ setenv ("LC_ALL", "", 1); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); unsetenv ("LANG"); setlocale (LC_ALL, ""); 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 (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 (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 (is_default (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"))); /* Check that LC_ALL overrides the others, and LANG is overridden by the others. */ setenv ("LC_ALL", "C", 1); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); unsetenv ("LANG"); setlocale (LC_ALL, ""); 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_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_CANONICALIZED) == 0); /* Check mixed situations. */ unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1); setenv ("LANG", "de_DE.UTF-8", 1); if (setlocale (LC_ALL, "") != NULL) { name = gl_locale_name (LC_CTYPE, "LC_CTYPE"); #if defined _WIN32 && !defined __CYGWIN__ /* On native Windows, here, gl_locale_name_thread (LC_CTYPE, "LC_CTYPE") returns NULL and gl_locale_name_posix (LC_CTYPE, "LC_CTYPE") returns either "de_DE" or "de_DE.UTF-8". */ ASSERT (strcmp (name, "de_DE") == 0 || strcmp (name, "de_DE.UTF-8") == 0); #else ASSERT (strcmp (name, "de_DE.UTF-8") == 0); #endif name = gl_locale_name (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); } unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1); unsetenv ("LANG"); if (setlocale (LC_ALL, "") != NULL) { name = gl_locale_name (LC_CTYPE, "LC_CTYPE"); ASSERT (is_default (name)); name = gl_locale_name (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); } #if HAVE_GOOD_USELOCALE /* Check that gl_locale_name considers the thread locale. */ { locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL); if (locale != NULL) { uselocale (locale); name = gl_locale_name (LC_CTYPE, "LC_CTYPE"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); name = gl_locale_name (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); uselocale (LC_GLOBAL_LOCALE); freelocale (locale); } } /* Check that gl_locale_name distinguishes different categories of the thread locale, and that the name is the right one for each. */ { unsigned int i; for (i = 0; i < SIZEOF (categories); i++) { int category_mask = categories[i].mask; locale_t loc = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL); if (loc != NULL) { locale_t locale = newlocale (category_mask, "de_DE.UTF-8", loc); if (locale == NULL) freelocale (loc); else { unsigned int j; uselocale (locale); for (j = 0; j < SIZEOF (categories); j++) { const char *name_j = gl_locale_name (categories[j].cat, categories[j].string); if (j == i) ASSERT (strcmp (name_j, "de_DE.UTF-8") == 0); else ASSERT (strcmp (name_j, "fr_FR.UTF-8") == 0); } uselocale (LC_GLOBAL_LOCALE); freelocale (locale); } } } } #endif } /* Test the gl_locale_name_thread() function. */ static void test_locale_name_thread (void) { /* Get into a defined state, */ setlocale (LC_ALL, "en_US.UTF-8"); #if HAVE_GOOD_USELOCALE /* Check that gl_locale_name_thread returns NULL when no thread locale is set. */ uselocale (LC_GLOBAL_LOCALE); ASSERT (gl_locale_name_thread (LC_CTYPE, "LC_CTYPE") == NULL); ASSERT (gl_locale_name_thread (LC_MESSAGES, "LC_MESSAGES") == NULL); /* Check that gl_locale_name_thread considers the thread locale. */ { locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL); if (locale != NULL) { const char *name; uselocale (locale); name = gl_locale_name_thread (LC_CTYPE, "LC_CTYPE"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); name = gl_locale_name_thread (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); uselocale (LC_GLOBAL_LOCALE); freelocale (locale); } } /* Check that gl_locale_name_thread distinguishes different categories of the thread locale, and that the name is the right one for each. */ { unsigned int i; for (i = 0; i < SIZEOF (categories); i++) { int category_mask = categories[i].mask; locale_t loc = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL); if (loc != NULL) { locale_t locale = newlocale (category_mask, "de_DE.UTF-8", loc); if (locale == NULL) freelocale (loc); else { unsigned int j; uselocale (locale); for (j = 0; j < SIZEOF (categories); j++) { const char *name_j = gl_locale_name_thread (categories[j].cat, categories[j].string); if (j == i) ASSERT (strcmp (name_j, "de_DE.UTF-8") == 0); else ASSERT (strcmp (name_j, "fr_FR.UTF-8") == 0); } uselocale (LC_GLOBAL_LOCALE); freelocale (locale); } } } } /* Check that gl_locale_name_thread returns a string that is allocated with indefinite extent. */ { /* Try many locale names in turn, in order to defeat possible caches. */ static const char * const choices[] = { "C", "POSIX", "af_ZA", "af_ZA.UTF-8", "am_ET", "am_ET.UTF-8", "be_BY", "be_BY.UTF-8", "bg_BG", "bg_BG.UTF-8", "ca_ES", "ca_ES.UTF-8", "cs_CZ", "cs_CZ.UTF-8", "da_DK", "da_DK.UTF-8", "de_AT", "de_AT.UTF-8", "de_CH", "de_CH.UTF-8", "de_DE", "de_DE.UTF-8", "el_GR", "el_GR.UTF-8", "en_AU", "en_AU.UTF-8", "en_CA", "en_CA.UTF-8", "en_GB", "en_GB.UTF-8", "en_IE", "en_IE.UTF-8", "en_NZ", "en_NZ.UTF-8", "en_US", "en_US.UTF-8", "es_ES", "es_ES.UTF-8", "et_EE", "et_EE.UTF-8", "eu_ES", "eu_ES.UTF-8", "fi_FI", "fi_FI.UTF-8", "fr_BE", "fr_BE.UTF-8", "fr_CA", "fr_CA.UTF-8", "fr_CH", "fr_CH.UTF-8", "fr_FR", "fr_FR.UTF-8", "he_IL", "he_IL.UTF-8", "hr_HR", "hr_HR.UTF-8", "hu_HU", "hu_HU.UTF-8", "hy_AM", "is_IS", "is_IS.UTF-8", "it_CH", "it_CH.UTF-8", "it_IT", "it_IT.UTF-8", "ja_JP.UTF-8", "kk_KZ", "kk_KZ.UTF-8", "ko_KR.UTF-8", "lt_LT", "lt_LT.UTF-8", "nl_BE", "nl_BE.UTF-8", "nl_NL", "nl_NL.UTF-8", "no_NO", "no_NO.UTF-8", "pl_PL", "pl_PL.UTF-8", "pt_BR", "pt_BR.UTF-8", "pt_PT", "pt_PT.UTF-8", "ro_RO", "ro_RO.UTF-8", "ru_RU", "ru_RU.UTF-8", "sk_SK", "sk_SK.UTF-8", "sl_SI", "sl_SI.UTF-8", "sv_SE", "sv_SE.UTF-8", "tr_TR", "tr_TR.UTF-8", "uk_UA", "uk_UA.UTF-8", "zh_CN", "zh_CN.UTF-8", "zh_HK", "zh_HK.UTF-8", "zh_TW", "zh_TW.UTF-8" }; /* Remember which locales are available. */ unsigned char /* bool */ available[SIZEOF (choices)]; /* Array of remembered results of gl_locale_name_thread. */ const char *unsaved_names[SIZEOF (choices)][SIZEOF (categories)]; /* Array of remembered results of gl_locale_name_thread, stored in safe memory. */ char *saved_names[SIZEOF (choices)][SIZEOF (categories)]; unsigned int j; for (j = 0; j < SIZEOF (choices); j++) { locale_t locale = newlocale (LC_ALL_MASK, choices[j], NULL); available[j] = (locale != NULL); if (locale != NULL) { unsigned int i; uselocale (locale); for (i = 0; i < SIZEOF (categories); i++) { unsaved_names[j][i] = gl_locale_name_thread (categories[i].cat, categories[i].string); saved_names[j][i] = strdup (unsaved_names[j][i]); } uselocale (LC_GLOBAL_LOCALE); freelocale (locale); } } /* Verify the unsaved_names are still valid. */ for (j = 0; j < SIZEOF (choices); j++) if (available[j]) { unsigned int i; for (i = 0; i < SIZEOF (categories); i++) ASSERT (strcmp (unsaved_names[j][i], saved_names[j][i]) == 0); } /* Allocate many locales, without freeing them. This is an attempt at overwriting as much of the previously allocated memory as possible. */ for (j = SIZEOF (choices); j > 0; ) { j--; if (available[j]) { locale_t locale = newlocale (LC_ALL_MASK, choices[j], NULL); unsigned int i; ASSERT (locale != NULL); uselocale (locale); for (i = 0; i < SIZEOF (categories); i++) { const char *name = gl_locale_name_thread (categories[i].cat, categories[i].string); ASSERT (strcmp (unsaved_names[j][i], name) == 0); } uselocale (LC_GLOBAL_LOCALE); freelocale (locale); } } /* Verify the unsaved_names are still valid. */ for (j = 0; j < SIZEOF (choices); j++) if (available[j]) { unsigned int i; for (i = 0; i < SIZEOF (categories); i++) { ASSERT (strcmp (unsaved_names[j][i], saved_names[j][i]) == 0); free (saved_names[j][i]); } } } #else /* Check that gl_locale_name_thread always returns NULL. */ ASSERT (gl_locale_name_thread (LC_CTYPE, "LC_CTYPE") == NULL); ASSERT (gl_locale_name_thread (LC_MESSAGES, "LC_MESSAGES") == NULL); #endif } /* Test the gl_locale_name_posix() function. */ static void test_locale_name_posix (void) { const char *ret; const char *name; /* Get into a defined state, */ setlocale (LC_ALL, "en_US.UTF-8"); #if HAVE_GOOD_USELOCALE uselocale (LC_GLOBAL_LOCALE); #endif /* Check that when all environment variables are unset, gl_locale_name_posix returns either NULL or the default locale. */ unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); unsetenv ("LC_NUMERIC"); unsetenv ("LANG"); /* Need also to unset all environment variables that specify standard or non-standard locale categories. Otherwise, on glibc systems, when some of these variables are set and reference a nonexistent locale, the setlocale (LC_ALL, "") call below would fail. */ unsetenv ("LC_COLLATE"); unsetenv ("LC_MONETARY"); unsetenv ("LC_TIME"); unsetenv ("LC_ADDRESS"); unsetenv ("LC_IDENTIFICATION"); unsetenv ("LC_MEASUREMENT"); unsetenv ("LC_NAME"); unsetenv ("LC_PAPER"); unsetenv ("LC_TELEPHONE"); ret = setlocale (LC_ALL, ""); ASSERT (ret != NULL); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (name == NULL || is_default (name)); name = gl_locale_name_posix (LC_NUMERIC, "LC_NUMERIC"); ASSERT (name == NULL || is_default (name)); /* Check that an empty environment variable is treated like an unset environment variable. */ setenv ("LC_ALL", "", 1); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); unsetenv ("LANG"); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (name == NULL || is_default (name)); unsetenv ("LC_ALL"); setenv ("LC_CTYPE", "", 1); unsetenv ("LC_MESSAGES"); unsetenv ("LANG"); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (name == NULL || is_default (name)); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); setenv ("LC_MESSAGES", "", 1); unsetenv ("LANG"); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (name == NULL || is_default (name)); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); setenv ("LANG", "", 1); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (name == NULL || is_default (name)); /* Check that LC_ALL overrides the others, and LANG is overridden by the others. */ setenv ("LC_ALL", "C", 1); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); unsetenv ("LANG"); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, C_CANONICALIZED) == 0); unsetenv ("LC_ALL"); setenv ("LC_CTYPE", "C", 1); setenv ("LC_MESSAGES", "C", 1); unsetenv ("LANG"); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, C_CANONICALIZED) == 0); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); setenv ("LANG", "C", 1); setlocale (LC_ALL, ""); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, C_CANONICALIZED) == 0); /* Check mixed situations. */ unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1); setenv ("LANG", "de_DE.UTF-8", 1); if (setlocale (LC_ALL, "") != NULL) { name = gl_locale_name_posix (LC_CTYPE, "LC_CTYPE"); #if defined _WIN32 && !defined __CYGWIN__ ASSERT (strcmp (name, "de_DE") == 0 || strcmp (name, "de_DE.UTF-8") == 0); #else ASSERT (strcmp (name, "de_DE.UTF-8") == 0); #endif name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); } unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1); unsetenv ("LANG"); if (setlocale (LC_ALL, "") != NULL) { name = gl_locale_name_posix (LC_CTYPE, "LC_CTYPE"); ASSERT (name == NULL || is_default (name)); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); } #if HAVE_GOOD_USELOCALE /* Check that gl_locale_name_posix ignores the thread locale. */ { locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL); if (locale != NULL) { unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); setenv ("LANG", "C", 1); setlocale (LC_ALL, ""); uselocale (locale); name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, C_CANONICALIZED) == 0); uselocale (LC_GLOBAL_LOCALE); freelocale (locale); } } #endif } /* Test the gl_locale_name_environ() function. */ static void test_locale_name_environ (void) { const char *name; /* Get into a defined state, */ setlocale (LC_ALL, "en_US.UTF-8"); #if HAVE_GOOD_USELOCALE uselocale (LC_GLOBAL_LOCALE); #endif /* Check that when all environment variables are unset, gl_locale_name_environ returns NULL. */ unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); unsetenv ("LC_NUMERIC"); unsetenv ("LANG"); ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL); ASSERT (gl_locale_name_environ (LC_NUMERIC, "LC_NUMERIC") == NULL); /* Check that an empty environment variable is treated like an unset environment variable. */ setenv ("LC_ALL", "", 1); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); unsetenv ("LANG"); ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL); unsetenv ("LC_ALL"); setenv ("LC_CTYPE", "", 1); unsetenv ("LC_MESSAGES"); unsetenv ("LANG"); ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); setenv ("LC_MESSAGES", "", 1); unsetenv ("LANG"); ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); setenv ("LANG", "", 1); ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL); /* Check that LC_ALL overrides the others, and LANG is overridden by the others. */ setenv ("LC_ALL", "C", 1); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); unsetenv ("LANG"); name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "C") == 0); unsetenv ("LC_ALL"); setenv ("LC_CTYPE", "C", 1); setenv ("LC_MESSAGES", "C", 1); unsetenv ("LANG"); name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "C") == 0); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); setenv ("LANG", "C", 1); name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "C") == 0); /* Check mixed situations. */ unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1); setenv ("LANG", "de_DE.UTF-8", 1); name = gl_locale_name_environ (LC_CTYPE, "LC_CTYPE"); ASSERT (strcmp (name, "de_DE.UTF-8") == 0); name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1); unsetenv ("LANG"); name = gl_locale_name_environ (LC_CTYPE, "LC_CTYPE"); ASSERT (name == NULL); name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "fr_FR.UTF-8") == 0); #if HAVE_GOOD_USELOCALE /* Check that gl_locale_name_environ ignores the thread locale. */ { locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL); if (locale != NULL) { unsetenv ("LC_ALL"); unsetenv ("LC_CTYPE"); unsetenv ("LC_MESSAGES"); setenv ("LANG", "C", 1); setlocale (LC_ALL, ""); uselocale (locale); name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES"); ASSERT (strcmp (name, "C") == 0); uselocale (LC_GLOBAL_LOCALE); freelocale (locale); } } #endif } /* Test the gl_locale_name_default() function. */ static void test_locale_name_default (void) { const char *name = gl_locale_name_default (); ASSERT (name != NULL); /* Only Mac OS X and Windows have a facility for the user to set the default locale. */ #if !((defined __APPLE__ && defined __MACH__) || (defined _WIN32 || defined __CYGWIN__)) ASSERT (strcmp (name, "C") == 0); #endif #if HAVE_GOOD_USELOCALE /* Check that gl_locale_name_default ignores the thread locale. */ { locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL); if (locale != NULL) { uselocale (locale); ASSERT (strcmp (gl_locale_name_default (), name) == 0); uselocale (LC_GLOBAL_LOCALE); freelocale (locale); } } #endif } int main () { test_locale_name (); test_locale_name_thread (); test_locale_name_posix (); test_locale_name_environ (); test_locale_name_default (); return test_exit_status; }