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