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 }