(root)/
coreutils-9.4/
gnulib-tests/
test-localename.c
       1  /* Test of gl_locale_name function and its variants.
       2     Copyright (C) 2007-2023 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation, either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
      18  
      19  #include <config.h>
      20  
      21  #include "localename.h"
      22  
      23  #include <locale.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  
      27  #include "macros.h"
      28  
      29  #if HAVE_WORKING_NEWLOCALE && HAVE_WORKING_USELOCALE && !HAVE_FAKE_LOCALES
      30  # define HAVE_GOOD_USELOCALE 1
      31  #endif
      32  
      33  #ifdef __HAIKU__
      34  /* Work around Haiku bug <https://dev.haiku-os.org/ticket/18344>.  */
      35  # define freelocale(loc) ((void) (loc))
      36  #endif
      37  
      38  /* Suppress GCC false positive.  */
      39  #if __GNUC__ >= 12
      40  # pragma GCC diagnostic ignored "-Wanalyzer-use-of-uninitialized-value"
      41  #endif
      42  
      43  #if HAVE_GOOD_USELOCALE
      44  
      45  static struct { int cat; int mask; const char *string; } const categories[] =
      46    {
      47        { LC_CTYPE,          LC_CTYPE_MASK,          "LC_CTYPE" },
      48        { LC_NUMERIC,        LC_NUMERIC_MASK,        "LC_NUMERIC" },
      49        { LC_TIME,           LC_TIME_MASK,           "LC_TIME" },
      50        { LC_COLLATE,        LC_COLLATE_MASK,        "LC_COLLATE" },
      51        { LC_MONETARY,       LC_MONETARY_MASK,       "LC_MONETARY" },
      52        { LC_MESSAGES,       LC_MESSAGES_MASK,       "LC_MESSAGES" }
      53  # ifdef LC_PAPER
      54      , { LC_PAPER,          LC_PAPER_MASK,          "LC_PAPER" }
      55  # endif
      56  # ifdef LC_NAME
      57      , { LC_NAME,           LC_NAME_MASK,           "LC_NAME" }
      58  # endif
      59  # ifdef LC_ADDRESS
      60      , { LC_ADDRESS,        LC_ADDRESS_MASK,        "LC_ADDRESS" }
      61  # endif
      62  # ifdef LC_TELEPHONE
      63      , { LC_TELEPHONE,      LC_TELEPHONE_MASK,      "LC_TELEPHONE" }
      64  # endif
      65  # ifdef LC_MEASUREMENT
      66      , { LC_MEASUREMENT,    LC_MEASUREMENT_MASK,    "LC_MEASUREMENT" }
      67  # endif
      68  # ifdef LC_IDENTIFICATION
      69      , { LC_IDENTIFICATION, LC_IDENTIFICATION_MASK, "LC_IDENTIFICATION" }
      70  # endif
      71    };
      72  
      73  #endif
      74  
      75  /* Test the gl_locale_name() function.  */
      76  static void
      77  test_locale_name (void)
      78  {
      79    const char *ret;
      80    const char *name;
      81  
      82    /* Check that gl_locale_name returns non-NULL.  */
      83    ASSERT (gl_locale_name (LC_MESSAGES, "LC_MESSAGES") != NULL);
      84  
      85    /* Get into a defined state,  */
      86    setlocale (LC_ALL, "en_US.UTF-8");
      87  #if HAVE_GOOD_USELOCALE
      88    uselocale (LC_GLOBAL_LOCALE);
      89  #endif
      90  
      91    /* Check that when all environment variables are unset,
      92       gl_locale_name returns the default locale.  */
      93    unsetenv ("LC_ALL");
      94    unsetenv ("LC_CTYPE");
      95    unsetenv ("LC_MESSAGES");
      96    unsetenv ("LC_NUMERIC");
      97    unsetenv ("LANG");
      98    /* Need also to unset all environment variables that specify standard or
      99       non-standard locale categories.  Otherwise, on glibc systems, when some
     100       of these variables are set and reference a nonexistent locale, the
     101       setlocale (LC_ALL, "") call below would fail.  */
     102    unsetenv ("LC_COLLATE");
     103    unsetenv ("LC_MONETARY");
     104    unsetenv ("LC_TIME");
     105    unsetenv ("LC_ADDRESS");
     106    unsetenv ("LC_IDENTIFICATION");
     107    unsetenv ("LC_MEASUREMENT");
     108    unsetenv ("LC_NAME");
     109    unsetenv ("LC_PAPER");
     110    unsetenv ("LC_TELEPHONE");
     111    ret = setlocale (LC_ALL, "");
     112    ASSERT (ret != NULL);
     113    ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"),
     114                    gl_locale_name_default ()) == 0);
     115    ASSERT (strcmp (gl_locale_name (LC_NUMERIC, "LC_NUMERIC"),
     116                    gl_locale_name_default ()) == 0);
     117  
     118    /* Check that an empty environment variable is treated like an unset
     119       environment variable.  */
     120  
     121    setenv ("LC_ALL", "", 1);
     122    unsetenv ("LC_CTYPE");
     123    unsetenv ("LC_MESSAGES");
     124    unsetenv ("LANG");
     125    setlocale (LC_ALL, "");
     126    ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"),
     127                    gl_locale_name_default ()) == 0);
     128  
     129    unsetenv ("LC_ALL");
     130    setenv ("LC_CTYPE", "", 1);
     131    unsetenv ("LC_MESSAGES");
     132    unsetenv ("LANG");
     133    setlocale (LC_ALL, "");
     134    ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"),
     135                    gl_locale_name_default ()) == 0);
     136  
     137    unsetenv ("LC_ALL");
     138    unsetenv ("LC_CTYPE");
     139    setenv ("LC_MESSAGES", "", 1);
     140    unsetenv ("LANG");
     141    setlocale (LC_ALL, "");
     142    ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"),
     143                    gl_locale_name_default ()) == 0);
     144  
     145    unsetenv ("LC_ALL");
     146    unsetenv ("LC_CTYPE");
     147    unsetenv ("LC_MESSAGES");
     148    setenv ("LANG", "", 1);
     149    setlocale (LC_ALL, "");
     150    ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"),
     151                    gl_locale_name_default ()) == 0);
     152  
     153    /* Check that LC_ALL overrides the others, and LANG is overridden by the
     154       others.  */
     155  
     156    setenv ("LC_ALL", "C", 1);
     157    unsetenv ("LC_CTYPE");
     158    unsetenv ("LC_MESSAGES");
     159    unsetenv ("LANG");
     160    setlocale (LC_ALL, "");
     161    ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), "C") == 0);
     162  
     163    unsetenv ("LC_ALL");
     164    setenv ("LC_CTYPE", "C", 1);
     165    setenv ("LC_MESSAGES", "C", 1);
     166    unsetenv ("LANG");
     167    setlocale (LC_ALL, "");
     168    ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), "C") == 0);
     169  
     170    unsetenv ("LC_ALL");
     171    unsetenv ("LC_CTYPE");
     172    unsetenv ("LC_MESSAGES");
     173    setenv ("LANG", "C", 1);
     174    setlocale (LC_ALL, "");
     175    ASSERT (strcmp (gl_locale_name (LC_MESSAGES, "LC_MESSAGES"), "C") == 0);
     176  
     177    /* Check mixed situations.  */
     178  
     179    unsetenv ("LC_ALL");
     180    unsetenv ("LC_CTYPE");
     181    setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
     182    setenv ("LANG", "de_DE.UTF-8", 1);
     183    if (setlocale (LC_ALL, "") != NULL)
     184      {
     185        name = gl_locale_name (LC_CTYPE, "LC_CTYPE");
     186  #if defined _WIN32 && !defined __CYGWIN__
     187        /* On native Windows, here,
     188             gl_locale_name_thread (LC_CTYPE, "LC_CTYPE")
     189           returns NULL and
     190             gl_locale_name_posix (LC_CTYPE, "LC_CTYPE")
     191           returns either "de_DE" or "de_DE.UTF-8".  */
     192        ASSERT (strcmp (name, "de_DE") == 0 || strcmp (name, "de_DE.UTF-8") == 0);
     193  #else
     194        ASSERT (strcmp (name, "de_DE.UTF-8") == 0);
     195  #endif
     196        name = gl_locale_name (LC_MESSAGES, "LC_MESSAGES");
     197        ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
     198      }
     199  
     200    unsetenv ("LC_ALL");
     201    unsetenv ("LC_CTYPE");
     202    setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
     203    unsetenv ("LANG");
     204    if (setlocale (LC_ALL, "") != NULL)
     205      {
     206        name = gl_locale_name (LC_CTYPE, "LC_CTYPE");
     207        ASSERT (strcmp (name, gl_locale_name_default ()) == 0);
     208        name = gl_locale_name (LC_MESSAGES, "LC_MESSAGES");
     209        ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
     210      }
     211  
     212  #if HAVE_GOOD_USELOCALE
     213    /* Check that gl_locale_name considers the thread locale.  */
     214    {
     215      locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
     216      if (locale != NULL)
     217        {
     218          uselocale (locale);
     219          name = gl_locale_name (LC_CTYPE, "LC_CTYPE");
     220          ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
     221          name = gl_locale_name (LC_MESSAGES, "LC_MESSAGES");
     222          ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
     223          uselocale (LC_GLOBAL_LOCALE);
     224          freelocale (locale);
     225        }
     226    }
     227  
     228    /* Check that gl_locale_name distinguishes different categories of the
     229       thread locale, and that the name is the right one for each.  */
     230    {
     231      unsigned int i;
     232  
     233      for (i = 0; i < SIZEOF (categories); i++)
     234        {
     235          int category_mask = categories[i].mask;
     236          locale_t loc = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
     237          if (loc != NULL)
     238            {
     239              locale_t locale = newlocale (category_mask, "de_DE.UTF-8", loc);
     240              if (locale == NULL)
     241                freelocale (loc);
     242              else
     243                {
     244                  unsigned int j;
     245  
     246                  uselocale (locale);
     247                  for (j = 0; j < SIZEOF (categories); j++)
     248                    {
     249                      const char *name_j =
     250                        gl_locale_name (categories[j].cat, categories[j].string);
     251                      if (j == i)
     252                        ASSERT (strcmp (name_j, "de_DE.UTF-8") == 0);
     253                      else
     254                        ASSERT (strcmp (name_j, "fr_FR.UTF-8") == 0);
     255                    }
     256                  uselocale (LC_GLOBAL_LOCALE);
     257                  freelocale (locale);
     258                }
     259            }
     260        }
     261    }
     262  #endif
     263  }
     264  
     265  /* Test the gl_locale_name_thread() function.  */
     266  static void
     267  test_locale_name_thread (void)
     268  {
     269    /* Get into a defined state,  */
     270    setlocale (LC_ALL, "en_US.UTF-8");
     271  
     272  #if HAVE_GOOD_USELOCALE
     273    /* Check that gl_locale_name_thread returns NULL when no thread locale is
     274       set.  */
     275    uselocale (LC_GLOBAL_LOCALE);
     276    ASSERT (gl_locale_name_thread (LC_CTYPE, "LC_CTYPE") == NULL);
     277    ASSERT (gl_locale_name_thread (LC_MESSAGES, "LC_MESSAGES") == NULL);
     278  
     279    /* Check that gl_locale_name_thread considers the thread locale.  */
     280    {
     281      locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
     282      if (locale != NULL)
     283        {
     284          const char *name;
     285  
     286          uselocale (locale);
     287          name = gl_locale_name_thread (LC_CTYPE, "LC_CTYPE");
     288          ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
     289          name = gl_locale_name_thread (LC_MESSAGES, "LC_MESSAGES");
     290          ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
     291          uselocale (LC_GLOBAL_LOCALE);
     292          freelocale (locale);
     293        }
     294    }
     295  
     296    /* Check that gl_locale_name_thread distinguishes different categories of the
     297       thread locale, and that the name is the right one for each.  */
     298    {
     299      unsigned int i;
     300  
     301      for (i = 0; i < SIZEOF (categories); i++)
     302        {
     303          int category_mask = categories[i].mask;
     304          locale_t loc = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
     305          if (loc != NULL)
     306            {
     307              locale_t locale = newlocale (category_mask, "de_DE.UTF-8", loc);
     308              if (locale == NULL)
     309                freelocale (loc);
     310              else
     311                {
     312                  unsigned int j;
     313  
     314                  uselocale (locale);
     315                  for (j = 0; j < SIZEOF (categories); j++)
     316                    {
     317                      const char *name_j =
     318                        gl_locale_name_thread (categories[j].cat,
     319                                               categories[j].string);
     320                      if (j == i)
     321                        ASSERT (strcmp (name_j, "de_DE.UTF-8") == 0);
     322                      else
     323                        ASSERT (strcmp (name_j, "fr_FR.UTF-8") == 0);
     324                    }
     325                  uselocale (LC_GLOBAL_LOCALE);
     326                  freelocale (locale);
     327                }
     328            }
     329        }
     330    }
     331  
     332    /* Check that gl_locale_name_thread returns a string that is allocated with
     333       indefinite extent.  */
     334    {
     335      /* Try many locale names in turn, in order to defeat possible caches.  */
     336      static const char * const choices[] =
     337        {
     338          "C",
     339          "POSIX",
     340          "af_ZA",
     341          "af_ZA.UTF-8",
     342          "am_ET",
     343          "am_ET.UTF-8",
     344          "be_BY",
     345          "be_BY.UTF-8",
     346          "bg_BG",
     347          "bg_BG.UTF-8",
     348          "ca_ES",
     349          "ca_ES.UTF-8",
     350          "cs_CZ",
     351          "cs_CZ.UTF-8",
     352          "da_DK",
     353          "da_DK.UTF-8",
     354          "de_AT",
     355          "de_AT.UTF-8",
     356          "de_CH",
     357          "de_CH.UTF-8",
     358          "de_DE",
     359          "de_DE.UTF-8",
     360          "el_GR",
     361          "el_GR.UTF-8",
     362          "en_AU",
     363          "en_AU.UTF-8",
     364          "en_CA",
     365          "en_CA.UTF-8",
     366          "en_GB",
     367          "en_GB.UTF-8",
     368          "en_IE",
     369          "en_IE.UTF-8",
     370          "en_NZ",
     371          "en_NZ.UTF-8",
     372          "en_US",
     373          "en_US.UTF-8",
     374          "es_ES",
     375          "es_ES.UTF-8",
     376          "et_EE",
     377          "et_EE.UTF-8",
     378          "eu_ES",
     379          "eu_ES.UTF-8",
     380          "fi_FI",
     381          "fi_FI.UTF-8",
     382          "fr_BE",
     383          "fr_BE.UTF-8",
     384          "fr_CA",
     385          "fr_CA.UTF-8",
     386          "fr_CH",
     387          "fr_CH.UTF-8",
     388          "fr_FR",
     389          "fr_FR.UTF-8",
     390          "he_IL",
     391          "he_IL.UTF-8",
     392          "hr_HR",
     393          "hr_HR.UTF-8",
     394          "hu_HU",
     395          "hu_HU.UTF-8",
     396          "hy_AM",
     397          "is_IS",
     398          "is_IS.UTF-8",
     399          "it_CH",
     400          "it_CH.UTF-8",
     401          "it_IT",
     402          "it_IT.UTF-8",
     403          "ja_JP.UTF-8",
     404          "kk_KZ",
     405          "kk_KZ.UTF-8",
     406          "ko_KR.UTF-8",
     407          "lt_LT",
     408          "lt_LT.UTF-8",
     409          "nl_BE",
     410          "nl_BE.UTF-8",
     411          "nl_NL",
     412          "nl_NL.UTF-8",
     413          "no_NO",
     414          "no_NO.UTF-8",
     415          "pl_PL",
     416          "pl_PL.UTF-8",
     417          "pt_BR",
     418          "pt_BR.UTF-8",
     419          "pt_PT",
     420          "pt_PT.UTF-8",
     421          "ro_RO",
     422          "ro_RO.UTF-8",
     423          "ru_RU",
     424          "ru_RU.UTF-8",
     425          "sk_SK",
     426          "sk_SK.UTF-8",
     427          "sl_SI",
     428          "sl_SI.UTF-8",
     429          "sv_SE",
     430          "sv_SE.UTF-8",
     431          "tr_TR",
     432          "tr_TR.UTF-8",
     433          "uk_UA",
     434          "uk_UA.UTF-8",
     435          "zh_CN",
     436          "zh_CN.UTF-8",
     437          "zh_HK",
     438          "zh_HK.UTF-8",
     439          "zh_TW",
     440          "zh_TW.UTF-8"
     441        };
     442      /* Remember which locales are available.  */
     443      unsigned char /* bool */ available[SIZEOF (choices)];
     444      /* Array of remembered results of gl_locale_name_thread.  */
     445      const char *unsaved_names[SIZEOF (choices)][SIZEOF (categories)];
     446      /* Array of remembered results of gl_locale_name_thread, stored in safe
     447         memory.  */
     448      char *saved_names[SIZEOF (choices)][SIZEOF (categories)];
     449      unsigned int j;
     450  
     451      for (j = 0; j < SIZEOF (choices); j++)
     452        {
     453          locale_t locale = newlocale (LC_ALL_MASK, choices[j], NULL);
     454          available[j] = (locale != NULL);
     455          if (locale != NULL)
     456            {
     457              unsigned int i;
     458  
     459              uselocale (locale);
     460              for (i = 0; i < SIZEOF (categories); i++)
     461                {
     462                  unsaved_names[j][i] = gl_locale_name_thread (categories[i].cat, categories[i].string);
     463                  saved_names[j][i] = strdup (unsaved_names[j][i]);
     464                }
     465              uselocale (LC_GLOBAL_LOCALE);
     466              freelocale (locale);
     467            }
     468        }
     469      /* Verify the unsaved_names are still valid.  */
     470      for (j = 0; j < SIZEOF (choices); j++)
     471        if (available[j])
     472          {
     473            unsigned int i;
     474  
     475            for (i = 0; i < SIZEOF (categories); i++)
     476              ASSERT (strcmp (unsaved_names[j][i], saved_names[j][i]) == 0);
     477          }
     478      /* Allocate many locales, without freeing them.  This is an attempt at
     479         overwriting as much of the previously allocated memory as possible.  */
     480      for (j = SIZEOF (choices); j > 0; )
     481        {
     482          j--;
     483          if (available[j])
     484            {
     485              locale_t locale = newlocale (LC_ALL_MASK, choices[j], NULL);
     486              unsigned int i;
     487  
     488              ASSERT (locale != NULL);
     489              uselocale (locale);
     490              for (i = 0; i < SIZEOF (categories); i++)
     491                {
     492                  const char *name = gl_locale_name_thread (categories[i].cat, categories[i].string);
     493                  ASSERT (strcmp (unsaved_names[j][i], name) == 0);
     494                }
     495              uselocale (LC_GLOBAL_LOCALE);
     496              freelocale (locale);
     497            }
     498        }
     499      /* Verify the unsaved_names are still valid.  */
     500      for (j = 0; j < SIZEOF (choices); j++)
     501        if (available[j])
     502          {
     503            unsigned int i;
     504  
     505            for (i = 0; i < SIZEOF (categories); i++)
     506              {
     507                ASSERT (strcmp (unsaved_names[j][i], saved_names[j][i]) == 0);
     508                free (saved_names[j][i]);
     509              }
     510          }
     511    }
     512  #else
     513    /* Check that gl_locale_name_thread always returns NULL.  */
     514    ASSERT (gl_locale_name_thread (LC_CTYPE, "LC_CTYPE") == NULL);
     515    ASSERT (gl_locale_name_thread (LC_MESSAGES, "LC_MESSAGES") == NULL);
     516  #endif
     517  }
     518  
     519  /* Test the gl_locale_name_posix() function.  */
     520  static void
     521  test_locale_name_posix (void)
     522  {
     523    const char *ret;
     524    const char *name;
     525  
     526    /* Get into a defined state,  */
     527    setlocale (LC_ALL, "en_US.UTF-8");
     528  #if HAVE_GOOD_USELOCALE
     529    uselocale (LC_GLOBAL_LOCALE);
     530  #endif
     531  
     532    /* Check that when all environment variables are unset,
     533       gl_locale_name_posix returns either NULL or the default locale.  */
     534    unsetenv ("LC_ALL");
     535    unsetenv ("LC_CTYPE");
     536    unsetenv ("LC_MESSAGES");
     537    unsetenv ("LC_NUMERIC");
     538    unsetenv ("LANG");
     539    /* Need also to unset all environment variables that specify standard or
     540       non-standard locale categories.  Otherwise, on glibc systems, when some
     541       of these variables are set and reference a nonexistent locale, the
     542       setlocale (LC_ALL, "") call below would fail.  */
     543    unsetenv ("LC_COLLATE");
     544    unsetenv ("LC_MONETARY");
     545    unsetenv ("LC_TIME");
     546    unsetenv ("LC_ADDRESS");
     547    unsetenv ("LC_IDENTIFICATION");
     548    unsetenv ("LC_MEASUREMENT");
     549    unsetenv ("LC_NAME");
     550    unsetenv ("LC_PAPER");
     551    unsetenv ("LC_TELEPHONE");
     552    ret = setlocale (LC_ALL, "");
     553    ASSERT (ret != NULL);
     554    name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
     555    ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
     556    name = gl_locale_name_posix (LC_NUMERIC, "LC_NUMERIC");
     557    ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
     558  
     559    /* Check that an empty environment variable is treated like an unset
     560       environment variable.  */
     561  
     562    setenv ("LC_ALL", "", 1);
     563    unsetenv ("LC_CTYPE");
     564    unsetenv ("LC_MESSAGES");
     565    unsetenv ("LANG");
     566    setlocale (LC_ALL, "");
     567    name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
     568    ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
     569  
     570    unsetenv ("LC_ALL");
     571    setenv ("LC_CTYPE", "", 1);
     572    unsetenv ("LC_MESSAGES");
     573    unsetenv ("LANG");
     574    setlocale (LC_ALL, "");
     575    name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
     576    ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
     577  
     578    unsetenv ("LC_ALL");
     579    unsetenv ("LC_CTYPE");
     580    setenv ("LC_MESSAGES", "", 1);
     581    unsetenv ("LANG");
     582    setlocale (LC_ALL, "");
     583    name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
     584    ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
     585  
     586    unsetenv ("LC_ALL");
     587    unsetenv ("LC_CTYPE");
     588    unsetenv ("LC_MESSAGES");
     589    setenv ("LANG", "", 1);
     590    setlocale (LC_ALL, "");
     591    name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
     592    ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
     593  
     594    /* Check that LC_ALL overrides the others, and LANG is overridden by the
     595       others.  */
     596  
     597    setenv ("LC_ALL", "C", 1);
     598    unsetenv ("LC_CTYPE");
     599    unsetenv ("LC_MESSAGES");
     600    unsetenv ("LANG");
     601    setlocale (LC_ALL, "");
     602    name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
     603    ASSERT (strcmp (name, "C") == 0);
     604  
     605    unsetenv ("LC_ALL");
     606    setenv ("LC_CTYPE", "C", 1);
     607    setenv ("LC_MESSAGES", "C", 1);
     608    unsetenv ("LANG");
     609    setlocale (LC_ALL, "");
     610    name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
     611    ASSERT (strcmp (name, "C") == 0);
     612  
     613    unsetenv ("LC_ALL");
     614    unsetenv ("LC_CTYPE");
     615    unsetenv ("LC_MESSAGES");
     616    setenv ("LANG", "C", 1);
     617    setlocale (LC_ALL, "");
     618    name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
     619    ASSERT (strcmp (name, "C") == 0);
     620  
     621    /* Check mixed situations.  */
     622  
     623    unsetenv ("LC_ALL");
     624    unsetenv ("LC_CTYPE");
     625    setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
     626    setenv ("LANG", "de_DE.UTF-8", 1);
     627    if (setlocale (LC_ALL, "") != NULL)
     628      {
     629        name = gl_locale_name_posix (LC_CTYPE, "LC_CTYPE");
     630  #if defined _WIN32 && !defined __CYGWIN__
     631        ASSERT (strcmp (name, "de_DE") == 0 || strcmp (name, "de_DE.UTF-8") == 0);
     632  #else
     633        ASSERT (strcmp (name, "de_DE.UTF-8") == 0);
     634  #endif
     635        name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
     636        ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
     637      }
     638  
     639    unsetenv ("LC_ALL");
     640    unsetenv ("LC_CTYPE");
     641    setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
     642    unsetenv ("LANG");
     643    if (setlocale (LC_ALL, "") != NULL)
     644      {
     645        name = gl_locale_name_posix (LC_CTYPE, "LC_CTYPE");
     646        ASSERT (name == NULL || strcmp (name, gl_locale_name_default ()) == 0);
     647        name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
     648        ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
     649      }
     650  
     651  #if HAVE_GOOD_USELOCALE
     652    /* Check that gl_locale_name_posix ignores the thread locale.  */
     653    {
     654      locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
     655      if (locale != NULL)
     656        {
     657          unsetenv ("LC_ALL");
     658          unsetenv ("LC_CTYPE");
     659          unsetenv ("LC_MESSAGES");
     660          setenv ("LANG", "C", 1);
     661          setlocale (LC_ALL, "");
     662          uselocale (locale);
     663          name = gl_locale_name_posix (LC_MESSAGES, "LC_MESSAGES");
     664          ASSERT (strcmp (name, "C") == 0);
     665          uselocale (LC_GLOBAL_LOCALE);
     666          freelocale (locale);
     667        }
     668    }
     669  #endif
     670  }
     671  
     672  /* Test the gl_locale_name_environ() function.  */
     673  static void
     674  test_locale_name_environ (void)
     675  {
     676    const char *name;
     677  
     678    /* Get into a defined state,  */
     679    setlocale (LC_ALL, "en_US.UTF-8");
     680  #if HAVE_GOOD_USELOCALE
     681    uselocale (LC_GLOBAL_LOCALE);
     682  #endif
     683  
     684    /* Check that when all environment variables are unset,
     685       gl_locale_name_environ returns NULL.  */
     686    unsetenv ("LC_ALL");
     687    unsetenv ("LC_CTYPE");
     688    unsetenv ("LC_MESSAGES");
     689    unsetenv ("LC_NUMERIC");
     690    unsetenv ("LANG");
     691    ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL);
     692    ASSERT (gl_locale_name_environ (LC_NUMERIC, "LC_NUMERIC") == NULL);
     693  
     694    /* Check that an empty environment variable is treated like an unset
     695       environment variable.  */
     696  
     697    setenv ("LC_ALL", "", 1);
     698    unsetenv ("LC_CTYPE");
     699    unsetenv ("LC_MESSAGES");
     700    unsetenv ("LANG");
     701    ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL);
     702  
     703    unsetenv ("LC_ALL");
     704    setenv ("LC_CTYPE", "", 1);
     705    unsetenv ("LC_MESSAGES");
     706    unsetenv ("LANG");
     707    ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL);
     708  
     709    unsetenv ("LC_ALL");
     710    unsetenv ("LC_CTYPE");
     711    setenv ("LC_MESSAGES", "", 1);
     712    unsetenv ("LANG");
     713    ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL);
     714  
     715    unsetenv ("LC_ALL");
     716    unsetenv ("LC_CTYPE");
     717    unsetenv ("LC_MESSAGES");
     718    setenv ("LANG", "", 1);
     719    ASSERT (gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES") == NULL);
     720  
     721    /* Check that LC_ALL overrides the others, and LANG is overridden by the
     722       others.  */
     723  
     724    setenv ("LC_ALL", "C", 1);
     725    unsetenv ("LC_CTYPE");
     726    unsetenv ("LC_MESSAGES");
     727    unsetenv ("LANG");
     728    name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
     729    ASSERT (strcmp (name, "C") == 0);
     730  
     731    unsetenv ("LC_ALL");
     732    setenv ("LC_CTYPE", "C", 1);
     733    setenv ("LC_MESSAGES", "C", 1);
     734    unsetenv ("LANG");
     735    name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
     736    ASSERT (strcmp (name, "C") == 0);
     737  
     738    unsetenv ("LC_ALL");
     739    unsetenv ("LC_CTYPE");
     740    unsetenv ("LC_MESSAGES");
     741    setenv ("LANG", "C", 1);
     742    name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
     743    ASSERT (strcmp (name, "C") == 0);
     744  
     745    /* Check mixed situations.  */
     746  
     747    unsetenv ("LC_ALL");
     748    unsetenv ("LC_CTYPE");
     749    setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
     750    setenv ("LANG", "de_DE.UTF-8", 1);
     751    name = gl_locale_name_environ (LC_CTYPE, "LC_CTYPE");
     752    ASSERT (strcmp (name, "de_DE.UTF-8") == 0);
     753    name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
     754    ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
     755  
     756    unsetenv ("LC_ALL");
     757    unsetenv ("LC_CTYPE");
     758    setenv ("LC_MESSAGES", "fr_FR.UTF-8", 1);
     759    unsetenv ("LANG");
     760    name = gl_locale_name_environ (LC_CTYPE, "LC_CTYPE");
     761    ASSERT (name == NULL);
     762    name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
     763    ASSERT (strcmp (name, "fr_FR.UTF-8") == 0);
     764  
     765  #if HAVE_GOOD_USELOCALE
     766    /* Check that gl_locale_name_environ ignores the thread locale.  */
     767    {
     768      locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
     769      if (locale != NULL)
     770        {
     771          unsetenv ("LC_ALL");
     772          unsetenv ("LC_CTYPE");
     773          unsetenv ("LC_MESSAGES");
     774          setenv ("LANG", "C", 1);
     775          setlocale (LC_ALL, "");
     776          uselocale (locale);
     777          name = gl_locale_name_environ (LC_MESSAGES, "LC_MESSAGES");
     778          ASSERT (strcmp (name, "C") == 0);
     779          uselocale (LC_GLOBAL_LOCALE);
     780          freelocale (locale);
     781        }
     782    }
     783  #endif
     784  }
     785  
     786  /* Test the gl_locale_name_default() function.  */
     787  static void
     788  test_locale_name_default (void)
     789  {
     790    const char *name = gl_locale_name_default ();
     791  
     792    ASSERT (name != NULL);
     793  
     794    /* Only Mac OS X and Windows have a facility for the user to set the default
     795       locale.  */
     796  #if !((defined __APPLE__ && defined __MACH__) || (defined _WIN32 || defined __CYGWIN__))
     797    ASSERT (strcmp (name, "C") == 0);
     798  #endif
     799  
     800  #if HAVE_GOOD_USELOCALE
     801    /* Check that gl_locale_name_default ignores the thread locale.  */
     802    {
     803      locale_t locale = newlocale (LC_ALL_MASK, "fr_FR.UTF-8", NULL);
     804      if (locale != NULL)
     805        {
     806          uselocale (locale);
     807          ASSERT (strcmp (gl_locale_name_default (), name) == 0);
     808          uselocale (LC_GLOBAL_LOCALE);
     809          freelocale (locale);
     810        }
     811    }
     812  #endif
     813  }
     814  
     815  int
     816  main ()
     817  {
     818    test_locale_name ();
     819    test_locale_name_thread ();
     820    test_locale_name_posix ();
     821    test_locale_name_environ ();
     822    test_locale_name_default ();
     823  
     824    return 0;
     825  }