1 /* Determine name of the currently selected locale.
2 Copyright (C) 1995-2021 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 Ulrich Drepper <drepper@gnu.org>, 1995. */
18 /* Native Windows code written by Tor Lillqvist <tml@iki.fi>. */
19 /* Mac OS X code written by Bruno Haible <bruno@clisp.org>. */
20
21 #include <config.h>
22
23 /* Specification. */
24 #ifdef IN_LIBINTL
25 # include "gettextP.h"
26 #else
27 # include "localename.h"
28 #endif
29
30 #include <limits.h>
31 #include <stdbool.h>
32 #include <stddef.h>
33 #include <stdlib.h>
34 #include <locale.h>
35 #include <string.h>
36
37 #include "flexmember.h"
38 #include "setlocale_null.h"
39 #include "thread-optim.h"
40
41 #if HAVE_GOOD_USELOCALE
42 /* Mac OS X 10.5 defines the locale_t type in <xlocale.h>. */
43 # if defined __APPLE__ && defined __MACH__
44 # include <xlocale.h>
45 # endif
46 # if (__GLIBC__ >= 2 && !defined __UCLIBC__) || (defined __linux__ && HAVE_LANGINFO_H) || defined __CYGWIN__
47 # include <langinfo.h>
48 # endif
49 # if !defined IN_LIBINTL
50 # include "glthread/lock.h"
51 # endif
52 # if defined __sun
53 # if HAVE_GETLOCALENAME_L
54 /* Solaris >= 12. */
55 extern char * getlocalename_l(int, locale_t);
56 # elif HAVE_SOLARIS114_LOCALES
57 # include <sys/localedef.h>
58 # endif
59 # endif
60 # if HAVE_NAMELESS_LOCALES
61 # include "localename-table.h"
62 # endif
63 #endif
64
65 #if HAVE_CFPREFERENCESCOPYAPPVALUE
66 # include <CoreFoundation/CFString.h>
67 # include <CoreFoundation/CFPreferences.h>
68 #endif
69
70 #if defined _WIN32 && !defined __CYGWIN__
71 # define WINDOWS_NATIVE
72 # if !defined IN_LIBINTL
73 # include "glthread/lock.h"
74 # endif
75 #endif
76
77 #if defined WINDOWS_NATIVE || defined __CYGWIN__ /* Native Windows or Cygwin */
78 # define WIN32_LEAN_AND_MEAN
79 # include <windows.h>
80 # include <winnls.h>
81 /* List of language codes, sorted by value:
82 0x01 LANG_ARABIC
83 0x02 LANG_BULGARIAN
84 0x03 LANG_CATALAN
85 0x04 LANG_CHINESE
86 0x05 LANG_CZECH
87 0x06 LANG_DANISH
88 0x07 LANG_GERMAN
89 0x08 LANG_GREEK
90 0x09 LANG_ENGLISH
91 0x0a LANG_SPANISH
92 0x0b LANG_FINNISH
93 0x0c LANG_FRENCH
94 0x0d LANG_HEBREW
95 0x0e LANG_HUNGARIAN
96 0x0f LANG_ICELANDIC
97 0x10 LANG_ITALIAN
98 0x11 LANG_JAPANESE
99 0x12 LANG_KOREAN
100 0x13 LANG_DUTCH
101 0x14 LANG_NORWEGIAN
102 0x15 LANG_POLISH
103 0x16 LANG_PORTUGUESE
104 0x17 LANG_ROMANSH
105 0x18 LANG_ROMANIAN
106 0x19 LANG_RUSSIAN
107 0x1a LANG_CROATIAN == LANG_SERBIAN
108 0x1b LANG_SLOVAK
109 0x1c LANG_ALBANIAN
110 0x1d LANG_SWEDISH
111 0x1e LANG_THAI
112 0x1f LANG_TURKISH
113 0x20 LANG_URDU
114 0x21 LANG_INDONESIAN
115 0x22 LANG_UKRAINIAN
116 0x23 LANG_BELARUSIAN
117 0x24 LANG_SLOVENIAN
118 0x25 LANG_ESTONIAN
119 0x26 LANG_LATVIAN
120 0x27 LANG_LITHUANIAN
121 0x28 LANG_TAJIK
122 0x29 LANG_FARSI
123 0x2a LANG_VIETNAMESE
124 0x2b LANG_ARMENIAN
125 0x2c LANG_AZERI
126 0x2d LANG_BASQUE
127 0x2e LANG_SORBIAN
128 0x2f LANG_MACEDONIAN
129 0x30 LANG_SUTU
130 0x31 LANG_TSONGA
131 0x32 LANG_TSWANA
132 0x33 LANG_VENDA
133 0x34 LANG_XHOSA
134 0x35 LANG_ZULU
135 0x36 LANG_AFRIKAANS
136 0x37 LANG_GEORGIAN
137 0x38 LANG_FAEROESE
138 0x39 LANG_HINDI
139 0x3a LANG_MALTESE
140 0x3b LANG_SAMI
141 0x3c LANG_GAELIC
142 0x3d LANG_YIDDISH
143 0x3e LANG_MALAY
144 0x3f LANG_KAZAK
145 0x40 LANG_KYRGYZ
146 0x41 LANG_SWAHILI
147 0x42 LANG_TURKMEN
148 0x43 LANG_UZBEK
149 0x44 LANG_TATAR
150 0x45 LANG_BENGALI
151 0x46 LANG_PUNJABI
152 0x47 LANG_GUJARATI
153 0x48 LANG_ORIYA
154 0x49 LANG_TAMIL
155 0x4a LANG_TELUGU
156 0x4b LANG_KANNADA
157 0x4c LANG_MALAYALAM
158 0x4d LANG_ASSAMESE
159 0x4e LANG_MARATHI
160 0x4f LANG_SANSKRIT
161 0x50 LANG_MONGOLIAN
162 0x51 LANG_TIBETAN
163 0x52 LANG_WELSH
164 0x53 LANG_CAMBODIAN
165 0x54 LANG_LAO
166 0x55 LANG_BURMESE
167 0x56 LANG_GALICIAN
168 0x57 LANG_KONKANI
169 0x58 LANG_MANIPURI
170 0x59 LANG_SINDHI
171 0x5a LANG_SYRIAC
172 0x5b LANG_SINHALESE
173 0x5c LANG_CHEROKEE
174 0x5d LANG_INUKTITUT
175 0x5e LANG_AMHARIC
176 0x5f LANG_TAMAZIGHT
177 0x60 LANG_KASHMIRI
178 0x61 LANG_NEPALI
179 0x62 LANG_FRISIAN
180 0x63 LANG_PASHTO
181 0x64 LANG_TAGALOG
182 0x65 LANG_DIVEHI
183 0x66 LANG_EDO
184 0x67 LANG_FULFULDE
185 0x68 LANG_HAUSA
186 0x69 LANG_IBIBIO
187 0x6a LANG_YORUBA
188 0x6d LANG_BASHKIR
189 0x6e LANG_LUXEMBOURGISH
190 0x6f LANG_GREENLANDIC
191 0x70 LANG_IGBO
192 0x71 LANG_KANURI
193 0x72 LANG_OROMO
194 0x73 LANG_TIGRINYA
195 0x74 LANG_GUARANI
196 0x75 LANG_HAWAIIAN
197 0x76 LANG_LATIN
198 0x77 LANG_SOMALI
199 0x78 LANG_YI
200 0x79 LANG_PAPIAMENTU
201 0x7a LANG_MAPUDUNGUN
202 0x7c LANG_MOHAWK
203 0x7e LANG_BRETON
204 0x82 LANG_OCCITAN
205 0x83 LANG_CORSICAN
206 0x84 LANG_ALSATIAN
207 0x85 LANG_YAKUT
208 0x86 LANG_KICHE
209 0x87 LANG_KINYARWANDA
210 0x88 LANG_WOLOF
211 0x8c LANG_DARI
212 0x91 LANG_SCOTTISH_GAELIC
213 */
214 /* Mingw headers don't have latest language and sublanguage codes. */
215 # ifndef LANG_AFRIKAANS
216 # define LANG_AFRIKAANS 0x36
217 # endif
218 # ifndef LANG_ALBANIAN
219 # define LANG_ALBANIAN 0x1c
220 # endif
221 # ifndef LANG_ALSATIAN
222 # define LANG_ALSATIAN 0x84
223 # endif
224 # ifndef LANG_AMHARIC
225 # define LANG_AMHARIC 0x5e
226 # endif
227 # ifndef LANG_ARABIC
228 # define LANG_ARABIC 0x01
229 # endif
230 # ifndef LANG_ARMENIAN
231 # define LANG_ARMENIAN 0x2b
232 # endif
233 # ifndef LANG_ASSAMESE
234 # define LANG_ASSAMESE 0x4d
235 # endif
236 # ifndef LANG_AZERI
237 # define LANG_AZERI 0x2c
238 # endif
239 # ifndef LANG_BASHKIR
240 # define LANG_BASHKIR 0x6d
241 # endif
242 # ifndef LANG_BASQUE
243 # define LANG_BASQUE 0x2d
244 # endif
245 # ifndef LANG_BELARUSIAN
246 # define LANG_BELARUSIAN 0x23
247 # endif
248 # ifndef LANG_BENGALI
249 # define LANG_BENGALI 0x45
250 # endif
251 # ifndef LANG_BRETON
252 # define LANG_BRETON 0x7e
253 # endif
254 # ifndef LANG_BURMESE
255 # define LANG_BURMESE 0x55
256 # endif
257 # ifndef LANG_CAMBODIAN
258 # define LANG_CAMBODIAN 0x53
259 # endif
260 # ifndef LANG_CATALAN
261 # define LANG_CATALAN 0x03
262 # endif
263 # ifndef LANG_CHEROKEE
264 # define LANG_CHEROKEE 0x5c
265 # endif
266 # ifndef LANG_CORSICAN
267 # define LANG_CORSICAN 0x83
268 # endif
269 # ifndef LANG_DARI
270 # define LANG_DARI 0x8c
271 # endif
272 # ifndef LANG_DIVEHI
273 # define LANG_DIVEHI 0x65
274 # endif
275 # ifndef LANG_EDO
276 # define LANG_EDO 0x66
277 # endif
278 # ifndef LANG_ESTONIAN
279 # define LANG_ESTONIAN 0x25
280 # endif
281 # ifndef LANG_FAEROESE
282 # define LANG_FAEROESE 0x38
283 # endif
284 # ifndef LANG_FARSI
285 # define LANG_FARSI 0x29
286 # endif
287 # ifndef LANG_FRISIAN
288 # define LANG_FRISIAN 0x62
289 # endif
290 # ifndef LANG_FULFULDE
291 # define LANG_FULFULDE 0x67
292 # endif
293 # ifndef LANG_GAELIC
294 # define LANG_GAELIC 0x3c
295 # endif
296 # ifndef LANG_GALICIAN
297 # define LANG_GALICIAN 0x56
298 # endif
299 # ifndef LANG_GEORGIAN
300 # define LANG_GEORGIAN 0x37
301 # endif
302 # ifndef LANG_GREENLANDIC
303 # define LANG_GREENLANDIC 0x6f
304 # endif
305 # ifndef LANG_GUARANI
306 # define LANG_GUARANI 0x74
307 # endif
308 # ifndef LANG_GUJARATI
309 # define LANG_GUJARATI 0x47
310 # endif
311 # ifndef LANG_HAUSA
312 # define LANG_HAUSA 0x68
313 # endif
314 # ifndef LANG_HAWAIIAN
315 # define LANG_HAWAIIAN 0x75
316 # endif
317 # ifndef LANG_HEBREW
318 # define LANG_HEBREW 0x0d
319 # endif
320 # ifndef LANG_HINDI
321 # define LANG_HINDI 0x39
322 # endif
323 # ifndef LANG_IBIBIO
324 # define LANG_IBIBIO 0x69
325 # endif
326 # ifndef LANG_IGBO
327 # define LANG_IGBO 0x70
328 # endif
329 # ifndef LANG_INDONESIAN
330 # define LANG_INDONESIAN 0x21
331 # endif
332 # ifndef LANG_INUKTITUT
333 # define LANG_INUKTITUT 0x5d
334 # endif
335 # ifndef LANG_KANNADA
336 # define LANG_KANNADA 0x4b
337 # endif
338 # ifndef LANG_KANURI
339 # define LANG_KANURI 0x71
340 # endif
341 # ifndef LANG_KASHMIRI
342 # define LANG_KASHMIRI 0x60
343 # endif
344 # ifndef LANG_KAZAK
345 # define LANG_KAZAK 0x3f
346 # endif
347 # ifndef LANG_KICHE
348 # define LANG_KICHE 0x86
349 # endif
350 # ifndef LANG_KINYARWANDA
351 # define LANG_KINYARWANDA 0x87
352 # endif
353 # ifndef LANG_KONKANI
354 # define LANG_KONKANI 0x57
355 # endif
356 # ifndef LANG_KYRGYZ
357 # define LANG_KYRGYZ 0x40
358 # endif
359 # ifndef LANG_LAO
360 # define LANG_LAO 0x54
361 # endif
362 # ifndef LANG_LATIN
363 # define LANG_LATIN 0x76
364 # endif
365 # ifndef LANG_LATVIAN
366 # define LANG_LATVIAN 0x26
367 # endif
368 # ifndef LANG_LITHUANIAN
369 # define LANG_LITHUANIAN 0x27
370 # endif
371 # ifndef LANG_LUXEMBOURGISH
372 # define LANG_LUXEMBOURGISH 0x6e
373 # endif
374 # ifndef LANG_MACEDONIAN
375 # define LANG_MACEDONIAN 0x2f
376 # endif
377 # ifndef LANG_MALAY
378 # define LANG_MALAY 0x3e
379 # endif
380 # ifndef LANG_MALAYALAM
381 # define LANG_MALAYALAM 0x4c
382 # endif
383 # ifndef LANG_MALTESE
384 # define LANG_MALTESE 0x3a
385 # endif
386 # ifndef LANG_MANIPURI
387 # define LANG_MANIPURI 0x58
388 # endif
389 # ifndef LANG_MAORI
390 # define LANG_MAORI 0x81
391 # endif
392 # ifndef LANG_MAPUDUNGUN
393 # define LANG_MAPUDUNGUN 0x7a
394 # endif
395 # ifndef LANG_MARATHI
396 # define LANG_MARATHI 0x4e
397 # endif
398 # ifndef LANG_MOHAWK
399 # define LANG_MOHAWK 0x7c
400 # endif
401 # ifndef LANG_MONGOLIAN
402 # define LANG_MONGOLIAN 0x50
403 # endif
404 # ifndef LANG_NEPALI
405 # define LANG_NEPALI 0x61
406 # endif
407 # ifndef LANG_OCCITAN
408 # define LANG_OCCITAN 0x82
409 # endif
410 # ifndef LANG_ORIYA
411 # define LANG_ORIYA 0x48
412 # endif
413 # ifndef LANG_OROMO
414 # define LANG_OROMO 0x72
415 # endif
416 # ifndef LANG_PAPIAMENTU
417 # define LANG_PAPIAMENTU 0x79
418 # endif
419 # ifndef LANG_PASHTO
420 # define LANG_PASHTO 0x63
421 # endif
422 # ifndef LANG_PUNJABI
423 # define LANG_PUNJABI 0x46
424 # endif
425 # ifndef LANG_QUECHUA
426 # define LANG_QUECHUA 0x6b
427 # endif
428 # ifndef LANG_ROMANSH
429 # define LANG_ROMANSH 0x17
430 # endif
431 # ifndef LANG_SAMI
432 # define LANG_SAMI 0x3b
433 # endif
434 # ifndef LANG_SANSKRIT
435 # define LANG_SANSKRIT 0x4f
436 # endif
437 # ifndef LANG_SCOTTISH_GAELIC
438 # define LANG_SCOTTISH_GAELIC 0x91
439 # endif
440 # ifndef LANG_SERBIAN
441 # define LANG_SERBIAN 0x1a
442 # endif
443 # ifndef LANG_SINDHI
444 # define LANG_SINDHI 0x59
445 # endif
446 # ifndef LANG_SINHALESE
447 # define LANG_SINHALESE 0x5b
448 # endif
449 # ifndef LANG_SLOVAK
450 # define LANG_SLOVAK 0x1b
451 # endif
452 # ifndef LANG_SOMALI
453 # define LANG_SOMALI 0x77
454 # endif
455 # ifndef LANG_SORBIAN
456 # define LANG_SORBIAN 0x2e
457 # endif
458 # ifndef LANG_SOTHO
459 # define LANG_SOTHO 0x6c
460 # endif
461 # ifndef LANG_SUTU
462 # define LANG_SUTU 0x30
463 # endif
464 # ifndef LANG_SWAHILI
465 # define LANG_SWAHILI 0x41
466 # endif
467 # ifndef LANG_SYRIAC
468 # define LANG_SYRIAC 0x5a
469 # endif
470 # ifndef LANG_TAGALOG
471 # define LANG_TAGALOG 0x64
472 # endif
473 # ifndef LANG_TAJIK
474 # define LANG_TAJIK 0x28
475 # endif
476 # ifndef LANG_TAMAZIGHT
477 # define LANG_TAMAZIGHT 0x5f
478 # endif
479 # ifndef LANG_TAMIL
480 # define LANG_TAMIL 0x49
481 # endif
482 # ifndef LANG_TATAR
483 # define LANG_TATAR 0x44
484 # endif
485 # ifndef LANG_TELUGU
486 # define LANG_TELUGU 0x4a
487 # endif
488 # ifndef LANG_THAI
489 # define LANG_THAI 0x1e
490 # endif
491 # ifndef LANG_TIBETAN
492 # define LANG_TIBETAN 0x51
493 # endif
494 # ifndef LANG_TIGRINYA
495 # define LANG_TIGRINYA 0x73
496 # endif
497 # ifndef LANG_TSONGA
498 # define LANG_TSONGA 0x31
499 # endif
500 # ifndef LANG_TSWANA
501 # define LANG_TSWANA 0x32
502 # endif
503 # ifndef LANG_TURKMEN
504 # define LANG_TURKMEN 0x42
505 # endif
506 # ifndef LANG_UIGHUR
507 # define LANG_UIGHUR 0x80
508 # endif
509 # ifndef LANG_UKRAINIAN
510 # define LANG_UKRAINIAN 0x22
511 # endif
512 # ifndef LANG_URDU
513 # define LANG_URDU 0x20
514 # endif
515 # ifndef LANG_UZBEK
516 # define LANG_UZBEK 0x43
517 # endif
518 # ifndef LANG_VENDA
519 # define LANG_VENDA 0x33
520 # endif
521 # ifndef LANG_VIETNAMESE
522 # define LANG_VIETNAMESE 0x2a
523 # endif
524 # ifndef LANG_WELSH
525 # define LANG_WELSH 0x52
526 # endif
527 # ifndef LANG_WOLOF
528 # define LANG_WOLOF 0x88
529 # endif
530 # ifndef LANG_XHOSA
531 # define LANG_XHOSA 0x34
532 # endif
533 # ifndef LANG_YAKUT
534 # define LANG_YAKUT 0x85
535 # endif
536 # ifndef LANG_YI
537 # define LANG_YI 0x78
538 # endif
539 # ifndef LANG_YIDDISH
540 # define LANG_YIDDISH 0x3d
541 # endif
542 # ifndef LANG_YORUBA
543 # define LANG_YORUBA 0x6a
544 # endif
545 # ifndef LANG_ZULU
546 # define LANG_ZULU 0x35
547 # endif
548 # ifndef SUBLANG_AFRIKAANS_SOUTH_AFRICA
549 # define SUBLANG_AFRIKAANS_SOUTH_AFRICA 0x01
550 # endif
551 # ifndef SUBLANG_ALBANIAN_ALBANIA
552 # define SUBLANG_ALBANIAN_ALBANIA 0x01
553 # endif
554 # ifndef SUBLANG_ALSATIAN_FRANCE
555 # define SUBLANG_ALSATIAN_FRANCE 0x01
556 # endif
557 # ifndef SUBLANG_AMHARIC_ETHIOPIA
558 # define SUBLANG_AMHARIC_ETHIOPIA 0x01
559 # endif
560 # ifndef SUBLANG_ARABIC_SAUDI_ARABIA
561 # define SUBLANG_ARABIC_SAUDI_ARABIA 0x01
562 # endif
563 # ifndef SUBLANG_ARABIC_IRAQ
564 # define SUBLANG_ARABIC_IRAQ 0x02
565 # endif
566 # ifndef SUBLANG_ARABIC_EGYPT
567 # define SUBLANG_ARABIC_EGYPT 0x03
568 # endif
569 # ifndef SUBLANG_ARABIC_LIBYA
570 # define SUBLANG_ARABIC_LIBYA 0x04
571 # endif
572 # ifndef SUBLANG_ARABIC_ALGERIA
573 # define SUBLANG_ARABIC_ALGERIA 0x05
574 # endif
575 # ifndef SUBLANG_ARABIC_MOROCCO
576 # define SUBLANG_ARABIC_MOROCCO 0x06
577 # endif
578 # ifndef SUBLANG_ARABIC_TUNISIA
579 # define SUBLANG_ARABIC_TUNISIA 0x07
580 # endif
581 # ifndef SUBLANG_ARABIC_OMAN
582 # define SUBLANG_ARABIC_OMAN 0x08
583 # endif
584 # ifndef SUBLANG_ARABIC_YEMEN
585 # define SUBLANG_ARABIC_YEMEN 0x09
586 # endif
587 # ifndef SUBLANG_ARABIC_SYRIA
588 # define SUBLANG_ARABIC_SYRIA 0x0a
589 # endif
590 # ifndef SUBLANG_ARABIC_JORDAN
591 # define SUBLANG_ARABIC_JORDAN 0x0b
592 # endif
593 # ifndef SUBLANG_ARABIC_LEBANON
594 # define SUBLANG_ARABIC_LEBANON 0x0c
595 # endif
596 # ifndef SUBLANG_ARABIC_KUWAIT
597 # define SUBLANG_ARABIC_KUWAIT 0x0d
598 # endif
599 # ifndef SUBLANG_ARABIC_UAE
600 # define SUBLANG_ARABIC_UAE 0x0e
601 # endif
602 # ifndef SUBLANG_ARABIC_BAHRAIN
603 # define SUBLANG_ARABIC_BAHRAIN 0x0f
604 # endif
605 # ifndef SUBLANG_ARABIC_QATAR
606 # define SUBLANG_ARABIC_QATAR 0x10
607 # endif
608 # ifndef SUBLANG_ARMENIAN_ARMENIA
609 # define SUBLANG_ARMENIAN_ARMENIA 0x01
610 # endif
611 # ifndef SUBLANG_ASSAMESE_INDIA
612 # define SUBLANG_ASSAMESE_INDIA 0x01
613 # endif
614 # ifndef SUBLANG_AZERI_LATIN
615 # define SUBLANG_AZERI_LATIN 0x01
616 # endif
617 # ifndef SUBLANG_AZERI_CYRILLIC
618 # define SUBLANG_AZERI_CYRILLIC 0x02
619 # endif
620 # ifndef SUBLANG_BASHKIR_RUSSIA
621 # define SUBLANG_BASHKIR_RUSSIA 0x01
622 # endif
623 # ifndef SUBLANG_BASQUE_BASQUE
624 # define SUBLANG_BASQUE_BASQUE 0x01
625 # endif
626 # ifndef SUBLANG_BELARUSIAN_BELARUS
627 # define SUBLANG_BELARUSIAN_BELARUS 0x01
628 # endif
629 # ifndef SUBLANG_BENGALI_INDIA
630 # define SUBLANG_BENGALI_INDIA 0x01
631 # endif
632 # ifndef SUBLANG_BENGALI_BANGLADESH
633 # define SUBLANG_BENGALI_BANGLADESH 0x02
634 # endif
635 # ifndef SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN
636 # define SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN 0x05
637 # endif
638 # ifndef SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC
639 # define SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC 0x08
640 # endif
641 # ifndef SUBLANG_BRETON_FRANCE
642 # define SUBLANG_BRETON_FRANCE 0x01
643 # endif
644 # ifndef SUBLANG_BULGARIAN_BULGARIA
645 # define SUBLANG_BULGARIAN_BULGARIA 0x01
646 # endif
647 # ifndef SUBLANG_CAMBODIAN_CAMBODIA
648 # define SUBLANG_CAMBODIAN_CAMBODIA 0x01
649 # endif
650 # ifndef SUBLANG_CATALAN_SPAIN
651 # define SUBLANG_CATALAN_SPAIN 0x01
652 # endif
653 # ifndef SUBLANG_CORSICAN_FRANCE
654 # define SUBLANG_CORSICAN_FRANCE 0x01
655 # endif
656 # ifndef SUBLANG_CROATIAN_CROATIA
657 # define SUBLANG_CROATIAN_CROATIA 0x01
658 # endif
659 # ifndef SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN
660 # define SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN 0x04
661 # endif
662 # ifndef SUBLANG_CHINESE_MACAU
663 # define SUBLANG_CHINESE_MACAU 0x05
664 # endif
665 # ifndef SUBLANG_CZECH_CZECH_REPUBLIC
666 # define SUBLANG_CZECH_CZECH_REPUBLIC 0x01
667 # endif
668 # ifndef SUBLANG_DANISH_DENMARK
669 # define SUBLANG_DANISH_DENMARK 0x01
670 # endif
671 # ifndef SUBLANG_DARI_AFGHANISTAN
672 # define SUBLANG_DARI_AFGHANISTAN 0x01
673 # endif
674 # ifndef SUBLANG_DIVEHI_MALDIVES
675 # define SUBLANG_DIVEHI_MALDIVES 0x01
676 # endif
677 # ifndef SUBLANG_DUTCH_SURINAM
678 # define SUBLANG_DUTCH_SURINAM 0x03
679 # endif
680 # ifndef SUBLANG_ENGLISH_SOUTH_AFRICA
681 # define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07
682 # endif
683 # ifndef SUBLANG_ENGLISH_JAMAICA
684 # define SUBLANG_ENGLISH_JAMAICA 0x08
685 # endif
686 # ifndef SUBLANG_ENGLISH_CARIBBEAN
687 # define SUBLANG_ENGLISH_CARIBBEAN 0x09
688 # endif
689 # ifndef SUBLANG_ENGLISH_BELIZE
690 # define SUBLANG_ENGLISH_BELIZE 0x0a
691 # endif
692 # ifndef SUBLANG_ENGLISH_TRINIDAD
693 # define SUBLANG_ENGLISH_TRINIDAD 0x0b
694 # endif
695 # ifndef SUBLANG_ENGLISH_ZIMBABWE
696 # define SUBLANG_ENGLISH_ZIMBABWE 0x0c
697 # endif
698 # ifndef SUBLANG_ENGLISH_PHILIPPINES
699 # define SUBLANG_ENGLISH_PHILIPPINES 0x0d
700 # endif
701 # ifndef SUBLANG_ENGLISH_INDONESIA
702 # define SUBLANG_ENGLISH_INDONESIA 0x0e
703 # endif
704 # ifndef SUBLANG_ENGLISH_HONGKONG
705 # define SUBLANG_ENGLISH_HONGKONG 0x0f
706 # endif
707 # ifndef SUBLANG_ENGLISH_INDIA
708 # define SUBLANG_ENGLISH_INDIA 0x10
709 # endif
710 # ifndef SUBLANG_ENGLISH_MALAYSIA
711 # define SUBLANG_ENGLISH_MALAYSIA 0x11
712 # endif
713 # ifndef SUBLANG_ENGLISH_SINGAPORE
714 # define SUBLANG_ENGLISH_SINGAPORE 0x12
715 # endif
716 # ifndef SUBLANG_ESTONIAN_ESTONIA
717 # define SUBLANG_ESTONIAN_ESTONIA 0x01
718 # endif
719 # ifndef SUBLANG_FAEROESE_FAROE_ISLANDS
720 # define SUBLANG_FAEROESE_FAROE_ISLANDS 0x01
721 # endif
722 # ifndef SUBLANG_FARSI_IRAN
723 # define SUBLANG_FARSI_IRAN 0x01
724 # endif
725 # ifndef SUBLANG_FINNISH_FINLAND
726 # define SUBLANG_FINNISH_FINLAND 0x01
727 # endif
728 # ifndef SUBLANG_FRENCH_LUXEMBOURG
729 # define SUBLANG_FRENCH_LUXEMBOURG 0x05
730 # endif
731 # ifndef SUBLANG_FRENCH_MONACO
732 # define SUBLANG_FRENCH_MONACO 0x06
733 # endif
734 # ifndef SUBLANG_FRENCH_WESTINDIES
735 # define SUBLANG_FRENCH_WESTINDIES 0x07
736 # endif
737 # ifndef SUBLANG_FRENCH_REUNION
738 # define SUBLANG_FRENCH_REUNION 0x08
739 # endif
740 # ifndef SUBLANG_FRENCH_CONGO
741 # define SUBLANG_FRENCH_CONGO 0x09
742 # endif
743 # ifndef SUBLANG_FRENCH_SENEGAL
744 # define SUBLANG_FRENCH_SENEGAL 0x0a
745 # endif
746 # ifndef SUBLANG_FRENCH_CAMEROON
747 # define SUBLANG_FRENCH_CAMEROON 0x0b
748 # endif
749 # ifndef SUBLANG_FRENCH_COTEDIVOIRE
750 # define SUBLANG_FRENCH_COTEDIVOIRE 0x0c
751 # endif
752 # ifndef SUBLANG_FRENCH_MALI
753 # define SUBLANG_FRENCH_MALI 0x0d
754 # endif
755 # ifndef SUBLANG_FRENCH_MOROCCO
756 # define SUBLANG_FRENCH_MOROCCO 0x0e
757 # endif
758 # ifndef SUBLANG_FRENCH_HAITI
759 # define SUBLANG_FRENCH_HAITI 0x0f
760 # endif
761 # ifndef SUBLANG_FRISIAN_NETHERLANDS
762 # define SUBLANG_FRISIAN_NETHERLANDS 0x01
763 # endif
764 # ifndef SUBLANG_GALICIAN_SPAIN
765 # define SUBLANG_GALICIAN_SPAIN 0x01
766 # endif
767 # ifndef SUBLANG_GEORGIAN_GEORGIA
768 # define SUBLANG_GEORGIAN_GEORGIA 0x01
769 # endif
770 # ifndef SUBLANG_GERMAN_LUXEMBOURG
771 # define SUBLANG_GERMAN_LUXEMBOURG 0x04
772 # endif
773 # ifndef SUBLANG_GERMAN_LIECHTENSTEIN
774 # define SUBLANG_GERMAN_LIECHTENSTEIN 0x05
775 # endif
776 # ifndef SUBLANG_GREEK_GREECE
777 # define SUBLANG_GREEK_GREECE 0x01
778 # endif
779 # ifndef SUBLANG_GREENLANDIC_GREENLAND
780 # define SUBLANG_GREENLANDIC_GREENLAND 0x01
781 # endif
782 # ifndef SUBLANG_GUJARATI_INDIA
783 # define SUBLANG_GUJARATI_INDIA 0x01
784 # endif
785 # ifndef SUBLANG_HAUSA_NIGERIA_LATIN
786 # define SUBLANG_HAUSA_NIGERIA_LATIN 0x01
787 # endif
788 # ifndef SUBLANG_HEBREW_ISRAEL
789 # define SUBLANG_HEBREW_ISRAEL 0x01
790 # endif
791 # ifndef SUBLANG_HINDI_INDIA
792 # define SUBLANG_HINDI_INDIA 0x01
793 # endif
794 # ifndef SUBLANG_HUNGARIAN_HUNGARY
795 # define SUBLANG_HUNGARIAN_HUNGARY 0x01
796 # endif
797 # ifndef SUBLANG_ICELANDIC_ICELAND
798 # define SUBLANG_ICELANDIC_ICELAND 0x01
799 # endif
800 # ifndef SUBLANG_IGBO_NIGERIA
801 # define SUBLANG_IGBO_NIGERIA 0x01
802 # endif
803 # ifndef SUBLANG_INDONESIAN_INDONESIA
804 # define SUBLANG_INDONESIAN_INDONESIA 0x01
805 # endif
806 # ifndef SUBLANG_INUKTITUT_CANADA
807 # define SUBLANG_INUKTITUT_CANADA 0x01
808 # endif
809 # undef SUBLANG_INUKTITUT_CANADA_LATIN
810 # define SUBLANG_INUKTITUT_CANADA_LATIN 0x02
811 # undef SUBLANG_IRISH_IRELAND
812 # define SUBLANG_IRISH_IRELAND 0x02
813 # ifndef SUBLANG_JAPANESE_JAPAN
814 # define SUBLANG_JAPANESE_JAPAN 0x01
815 # endif
816 # ifndef SUBLANG_KANNADA_INDIA
817 # define SUBLANG_KANNADA_INDIA 0x01
818 # endif
819 # ifndef SUBLANG_KASHMIRI_INDIA
820 # define SUBLANG_KASHMIRI_INDIA 0x02
821 # endif
822 # ifndef SUBLANG_KAZAK_KAZAKHSTAN
823 # define SUBLANG_KAZAK_KAZAKHSTAN 0x01
824 # endif
825 # ifndef SUBLANG_KICHE_GUATEMALA
826 # define SUBLANG_KICHE_GUATEMALA 0x01
827 # endif
828 # ifndef SUBLANG_KINYARWANDA_RWANDA
829 # define SUBLANG_KINYARWANDA_RWANDA 0x01
830 # endif
831 # ifndef SUBLANG_KONKANI_INDIA
832 # define SUBLANG_KONKANI_INDIA 0x01
833 # endif
834 # ifndef SUBLANG_KYRGYZ_KYRGYZSTAN
835 # define SUBLANG_KYRGYZ_KYRGYZSTAN 0x01
836 # endif
837 # ifndef SUBLANG_LAO_LAOS
838 # define SUBLANG_LAO_LAOS 0x01
839 # endif
840 # ifndef SUBLANG_LATVIAN_LATVIA
841 # define SUBLANG_LATVIAN_LATVIA 0x01
842 # endif
843 # ifndef SUBLANG_LITHUANIAN_LITHUANIA
844 # define SUBLANG_LITHUANIAN_LITHUANIA 0x01
845 # endif
846 # undef SUBLANG_LOWER_SORBIAN_GERMANY
847 # define SUBLANG_LOWER_SORBIAN_GERMANY 0x02
848 # ifndef SUBLANG_LUXEMBOURGISH_LUXEMBOURG
849 # define SUBLANG_LUXEMBOURGISH_LUXEMBOURG 0x01
850 # endif
851 # ifndef SUBLANG_MACEDONIAN_MACEDONIA
852 # define SUBLANG_MACEDONIAN_MACEDONIA 0x01
853 # endif
854 # ifndef SUBLANG_MALAY_MALAYSIA
855 # define SUBLANG_MALAY_MALAYSIA 0x01
856 # endif
857 # ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
858 # define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02
859 # endif
860 # ifndef SUBLANG_MALAYALAM_INDIA
861 # define SUBLANG_MALAYALAM_INDIA 0x01
862 # endif
863 # ifndef SUBLANG_MALTESE_MALTA
864 # define SUBLANG_MALTESE_MALTA 0x01
865 # endif
866 # ifndef SUBLANG_MAORI_NEW_ZEALAND
867 # define SUBLANG_MAORI_NEW_ZEALAND 0x01
868 # endif
869 # ifndef SUBLANG_MAPUDUNGUN_CHILE
870 # define SUBLANG_MAPUDUNGUN_CHILE 0x01
871 # endif
872 # ifndef SUBLANG_MARATHI_INDIA
873 # define SUBLANG_MARATHI_INDIA 0x01
874 # endif
875 # ifndef SUBLANG_MOHAWK_CANADA
876 # define SUBLANG_MOHAWK_CANADA 0x01
877 # endif
878 # ifndef SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
879 # define SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA 0x01
880 # endif
881 # ifndef SUBLANG_MONGOLIAN_PRC
882 # define SUBLANG_MONGOLIAN_PRC 0x02
883 # endif
884 # ifndef SUBLANG_NEPALI_NEPAL
885 # define SUBLANG_NEPALI_NEPAL 0x01
886 # endif
887 # ifndef SUBLANG_NEPALI_INDIA
888 # define SUBLANG_NEPALI_INDIA 0x02
889 # endif
890 # ifndef SUBLANG_OCCITAN_FRANCE
891 # define SUBLANG_OCCITAN_FRANCE 0x01
892 # endif
893 # ifndef SUBLANG_ORIYA_INDIA
894 # define SUBLANG_ORIYA_INDIA 0x01
895 # endif
896 # ifndef SUBLANG_PASHTO_AFGHANISTAN
897 # define SUBLANG_PASHTO_AFGHANISTAN 0x01
898 # endif
899 # ifndef SUBLANG_POLISH_POLAND
900 # define SUBLANG_POLISH_POLAND 0x01
901 # endif
902 # ifndef SUBLANG_PUNJABI_INDIA
903 # define SUBLANG_PUNJABI_INDIA 0x01
904 # endif
905 # ifndef SUBLANG_PUNJABI_PAKISTAN
906 # define SUBLANG_PUNJABI_PAKISTAN 0x02
907 # endif
908 # ifndef SUBLANG_QUECHUA_BOLIVIA
909 # define SUBLANG_QUECHUA_BOLIVIA 0x01
910 # endif
911 # ifndef SUBLANG_QUECHUA_ECUADOR
912 # define SUBLANG_QUECHUA_ECUADOR 0x02
913 # endif
914 # ifndef SUBLANG_QUECHUA_PERU
915 # define SUBLANG_QUECHUA_PERU 0x03
916 # endif
917 # ifndef SUBLANG_ROMANIAN_ROMANIA
918 # define SUBLANG_ROMANIAN_ROMANIA 0x01
919 # endif
920 # ifndef SUBLANG_ROMANIAN_MOLDOVA
921 # define SUBLANG_ROMANIAN_MOLDOVA 0x02
922 # endif
923 # ifndef SUBLANG_ROMANSH_SWITZERLAND
924 # define SUBLANG_ROMANSH_SWITZERLAND 0x01
925 # endif
926 # ifndef SUBLANG_RUSSIAN_RUSSIA
927 # define SUBLANG_RUSSIAN_RUSSIA 0x01
928 # endif
929 # ifndef SUBLANG_RUSSIAN_MOLDAVIA
930 # define SUBLANG_RUSSIAN_MOLDAVIA 0x02
931 # endif
932 # ifndef SUBLANG_SAMI_NORTHERN_NORWAY
933 # define SUBLANG_SAMI_NORTHERN_NORWAY 0x01
934 # endif
935 # ifndef SUBLANG_SAMI_NORTHERN_SWEDEN
936 # define SUBLANG_SAMI_NORTHERN_SWEDEN 0x02
937 # endif
938 # ifndef SUBLANG_SAMI_NORTHERN_FINLAND
939 # define SUBLANG_SAMI_NORTHERN_FINLAND 0x03
940 # endif
941 # ifndef SUBLANG_SAMI_LULE_NORWAY
942 # define SUBLANG_SAMI_LULE_NORWAY 0x04
943 # endif
944 # ifndef SUBLANG_SAMI_LULE_SWEDEN
945 # define SUBLANG_SAMI_LULE_SWEDEN 0x05
946 # endif
947 # ifndef SUBLANG_SAMI_SOUTHERN_NORWAY
948 # define SUBLANG_SAMI_SOUTHERN_NORWAY 0x06
949 # endif
950 # ifndef SUBLANG_SAMI_SOUTHERN_SWEDEN
951 # define SUBLANG_SAMI_SOUTHERN_SWEDEN 0x07
952 # endif
953 # undef SUBLANG_SAMI_SKOLT_FINLAND
954 # define SUBLANG_SAMI_SKOLT_FINLAND 0x08
955 # undef SUBLANG_SAMI_INARI_FINLAND
956 # define SUBLANG_SAMI_INARI_FINLAND 0x09
957 # ifndef SUBLANG_SANSKRIT_INDIA
958 # define SUBLANG_SANSKRIT_INDIA 0x01
959 # endif
960 # ifndef SUBLANG_SERBIAN_LATIN
961 # define SUBLANG_SERBIAN_LATIN 0x02
962 # endif
963 # ifndef SUBLANG_SERBIAN_CYRILLIC
964 # define SUBLANG_SERBIAN_CYRILLIC 0x03
965 # endif
966 # ifndef SUBLANG_SINDHI_INDIA
967 # define SUBLANG_SINDHI_INDIA 0x01
968 # endif
969 # undef SUBLANG_SINDHI_PAKISTAN
970 # define SUBLANG_SINDHI_PAKISTAN 0x02
971 # ifndef SUBLANG_SINDHI_AFGHANISTAN
972 # define SUBLANG_SINDHI_AFGHANISTAN 0x02
973 # endif
974 # ifndef SUBLANG_SINHALESE_SRI_LANKA
975 # define SUBLANG_SINHALESE_SRI_LANKA 0x01
976 # endif
977 # ifndef SUBLANG_SLOVAK_SLOVAKIA
978 # define SUBLANG_SLOVAK_SLOVAKIA 0x01
979 # endif
980 # ifndef SUBLANG_SLOVENIAN_SLOVENIA
981 # define SUBLANG_SLOVENIAN_SLOVENIA 0x01
982 # endif
983 # ifndef SUBLANG_SOTHO_SOUTH_AFRICA
984 # define SUBLANG_SOTHO_SOUTH_AFRICA 0x01
985 # endif
986 # ifndef SUBLANG_SPANISH_GUATEMALA
987 # define SUBLANG_SPANISH_GUATEMALA 0x04
988 # endif
989 # ifndef SUBLANG_SPANISH_COSTA_RICA
990 # define SUBLANG_SPANISH_COSTA_RICA 0x05
991 # endif
992 # ifndef SUBLANG_SPANISH_PANAMA
993 # define SUBLANG_SPANISH_PANAMA 0x06
994 # endif
995 # ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC
996 # define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07
997 # endif
998 # ifndef SUBLANG_SPANISH_VENEZUELA
999 # define SUBLANG_SPANISH_VENEZUELA 0x08
1000 # endif
1001 # ifndef SUBLANG_SPANISH_COLOMBIA
1002 # define SUBLANG_SPANISH_COLOMBIA 0x09
1003 # endif
1004 # ifndef SUBLANG_SPANISH_PERU
1005 # define SUBLANG_SPANISH_PERU 0x0a
1006 # endif
1007 # ifndef SUBLANG_SPANISH_ARGENTINA
1008 # define SUBLANG_SPANISH_ARGENTINA 0x0b
1009 # endif
1010 # ifndef SUBLANG_SPANISH_ECUADOR
1011 # define SUBLANG_SPANISH_ECUADOR 0x0c
1012 # endif
1013 # ifndef SUBLANG_SPANISH_CHILE
1014 # define SUBLANG_SPANISH_CHILE 0x0d
1015 # endif
1016 # ifndef SUBLANG_SPANISH_URUGUAY
1017 # define SUBLANG_SPANISH_URUGUAY 0x0e
1018 # endif
1019 # ifndef SUBLANG_SPANISH_PARAGUAY
1020 # define SUBLANG_SPANISH_PARAGUAY 0x0f
1021 # endif
1022 # ifndef SUBLANG_SPANISH_BOLIVIA
1023 # define SUBLANG_SPANISH_BOLIVIA 0x10
1024 # endif
1025 # ifndef SUBLANG_SPANISH_EL_SALVADOR
1026 # define SUBLANG_SPANISH_EL_SALVADOR 0x11
1027 # endif
1028 # ifndef SUBLANG_SPANISH_HONDURAS
1029 # define SUBLANG_SPANISH_HONDURAS 0x12
1030 # endif
1031 # ifndef SUBLANG_SPANISH_NICARAGUA
1032 # define SUBLANG_SPANISH_NICARAGUA 0x13
1033 # endif
1034 # ifndef SUBLANG_SPANISH_PUERTO_RICO
1035 # define SUBLANG_SPANISH_PUERTO_RICO 0x14
1036 # endif
1037 # ifndef SUBLANG_SPANISH_US
1038 # define SUBLANG_SPANISH_US 0x15
1039 # endif
1040 # ifndef SUBLANG_SWAHILI_KENYA
1041 # define SUBLANG_SWAHILI_KENYA 0x01
1042 # endif
1043 # ifndef SUBLANG_SWEDISH_SWEDEN
1044 # define SUBLANG_SWEDISH_SWEDEN 0x01
1045 # endif
1046 # ifndef SUBLANG_SWEDISH_FINLAND
1047 # define SUBLANG_SWEDISH_FINLAND 0x02
1048 # endif
1049 # ifndef SUBLANG_SYRIAC_SYRIA
1050 # define SUBLANG_SYRIAC_SYRIA 0x01
1051 # endif
1052 # ifndef SUBLANG_TAGALOG_PHILIPPINES
1053 # define SUBLANG_TAGALOG_PHILIPPINES 0x01
1054 # endif
1055 # ifndef SUBLANG_TAJIK_TAJIKISTAN
1056 # define SUBLANG_TAJIK_TAJIKISTAN 0x01
1057 # endif
1058 # ifndef SUBLANG_TAMAZIGHT_ARABIC
1059 # define SUBLANG_TAMAZIGHT_ARABIC 0x01
1060 # endif
1061 # ifndef SUBLANG_TAMAZIGHT_ALGERIA_LATIN
1062 # define SUBLANG_TAMAZIGHT_ALGERIA_LATIN 0x02
1063 # endif
1064 # ifndef SUBLANG_TAMIL_INDIA
1065 # define SUBLANG_TAMIL_INDIA 0x01
1066 # endif
1067 # ifndef SUBLANG_TATAR_RUSSIA
1068 # define SUBLANG_TATAR_RUSSIA 0x01
1069 # endif
1070 # ifndef SUBLANG_TELUGU_INDIA
1071 # define SUBLANG_TELUGU_INDIA 0x01
1072 # endif
1073 # ifndef SUBLANG_THAI_THAILAND
1074 # define SUBLANG_THAI_THAILAND 0x01
1075 # endif
1076 # ifndef SUBLANG_TIBETAN_PRC
1077 # define SUBLANG_TIBETAN_PRC 0x01
1078 # endif
1079 # undef SUBLANG_TIBETAN_BHUTAN
1080 # define SUBLANG_TIBETAN_BHUTAN 0x02
1081 # ifndef SUBLANG_TIGRINYA_ETHIOPIA
1082 # define SUBLANG_TIGRINYA_ETHIOPIA 0x01
1083 # endif
1084 # ifndef SUBLANG_TIGRINYA_ERITREA
1085 # define SUBLANG_TIGRINYA_ERITREA 0x02
1086 # endif
1087 # ifndef SUBLANG_TSWANA_SOUTH_AFRICA
1088 # define SUBLANG_TSWANA_SOUTH_AFRICA 0x01
1089 # endif
1090 # ifndef SUBLANG_TURKISH_TURKEY
1091 # define SUBLANG_TURKISH_TURKEY 0x01
1092 # endif
1093 # ifndef SUBLANG_TURKMEN_TURKMENISTAN
1094 # define SUBLANG_TURKMEN_TURKMENISTAN 0x01
1095 # endif
1096 # ifndef SUBLANG_UIGHUR_PRC
1097 # define SUBLANG_UIGHUR_PRC 0x01
1098 # endif
1099 # ifndef SUBLANG_UKRAINIAN_UKRAINE
1100 # define SUBLANG_UKRAINIAN_UKRAINE 0x01
1101 # endif
1102 # ifndef SUBLANG_UPPER_SORBIAN_GERMANY
1103 # define SUBLANG_UPPER_SORBIAN_GERMANY 0x01
1104 # endif
1105 # ifndef SUBLANG_URDU_PAKISTAN
1106 # define SUBLANG_URDU_PAKISTAN 0x01
1107 # endif
1108 # ifndef SUBLANG_URDU_INDIA
1109 # define SUBLANG_URDU_INDIA 0x02
1110 # endif
1111 # ifndef SUBLANG_UZBEK_LATIN
1112 # define SUBLANG_UZBEK_LATIN 0x01
1113 # endif
1114 # ifndef SUBLANG_UZBEK_CYRILLIC
1115 # define SUBLANG_UZBEK_CYRILLIC 0x02
1116 # endif
1117 # ifndef SUBLANG_VIETNAMESE_VIETNAM
1118 # define SUBLANG_VIETNAMESE_VIETNAM 0x01
1119 # endif
1120 # ifndef SUBLANG_WELSH_UNITED_KINGDOM
1121 # define SUBLANG_WELSH_UNITED_KINGDOM 0x01
1122 # endif
1123 # ifndef SUBLANG_WOLOF_SENEGAL
1124 # define SUBLANG_WOLOF_SENEGAL 0x01
1125 # endif
1126 # ifndef SUBLANG_XHOSA_SOUTH_AFRICA
1127 # define SUBLANG_XHOSA_SOUTH_AFRICA 0x01
1128 # endif
1129 # ifndef SUBLANG_YAKUT_RUSSIA
1130 # define SUBLANG_YAKUT_RUSSIA 0x01
1131 # endif
1132 # ifndef SUBLANG_YI_PRC
1133 # define SUBLANG_YI_PRC 0x01
1134 # endif
1135 # ifndef SUBLANG_YORUBA_NIGERIA
1136 # define SUBLANG_YORUBA_NIGERIA 0x01
1137 # endif
1138 # ifndef SUBLANG_ZULU_SOUTH_AFRICA
1139 # define SUBLANG_ZULU_SOUTH_AFRICA 0x01
1140 # endif
1141 /* GetLocaleInfoA operations. */
1142 # ifndef LOCALE_SNAME
1143 # define LOCALE_SNAME 0x5c
1144 # endif
1145 # ifndef LOCALE_NAME_MAX_LENGTH
1146 # define LOCALE_NAME_MAX_LENGTH 85
1147 # endif
1148 /* Don't assume that UNICODE is not defined. */
1149 # undef GetLocaleInfo
1150 # define GetLocaleInfo GetLocaleInfoA
1151 # undef EnumSystemLocales
1152 # define EnumSystemLocales EnumSystemLocalesA
1153 #endif
1154
1155 /* We want to use the system's setlocale() function here, not the gnulib
1156 override. */
1157 #undef setlocale
1158
1159
1160 #if HAVE_CFPREFERENCESCOPYAPPVALUE
1161 /* Mac OS X 10.4 or newer */
1162
1163 /* Canonicalize a Mac OS X locale name to a Unix locale name.
1164 NAME is a sufficiently large buffer.
1165 On input, it contains the Mac OS X locale name.
1166 On output, it contains the Unix locale name. */
1167 # if !defined IN_LIBINTL
1168 static
1169 # endif
1170 void
1171 gl_locale_name_canonicalize (char *name)
1172 {
1173 /* This conversion is based on a posting by
1174 Deborah GoldSmith <goldsmit@apple.com> on 2005-03-08,
1175 https://lists.apple.com/archives/carbon-dev/2005/Mar/msg00293.html */
1176
1177 /* Convert legacy (NeXTstep inherited) English names to Unix (ISO 639 and
1178 ISO 3166) names. Prior to Mac OS X 10.3, there is no API for doing this.
1179 Therefore we do it ourselves, using a table based on the results of the
1180 Mac OS X 10.3.8 function
1181 CFLocaleCreateCanonicalLocaleIdentifierFromString(). */
1182 typedef struct { const char legacy[21+1]; const char unixy[5+1]; }
1183 legacy_entry;
1184 static const legacy_entry legacy_table[] = {
1185 { "Afrikaans", "af" },
1186 { "Albanian", "sq" },
1187 { "Amharic", "am" },
1188 { "Arabic", "ar" },
1189 { "Armenian", "hy" },
1190 { "Assamese", "as" },
1191 { "Aymara", "ay" },
1192 { "Azerbaijani", "az" },
1193 { "Basque", "eu" },
1194 { "Belarusian", "be" },
1195 { "Belorussian", "be" },
1196 { "Bengali", "bn" },
1197 { "Brazilian Portugese", "pt_BR" },
1198 { "Brazilian Portuguese", "pt_BR" },
1199 { "Breton", "br" },
1200 { "Bulgarian", "bg" },
1201 { "Burmese", "my" },
1202 { "Byelorussian", "be" },
1203 { "Catalan", "ca" },
1204 { "Chewa", "ny" },
1205 { "Chichewa", "ny" },
1206 { "Chinese", "zh" },
1207 { "Chinese, Simplified", "zh_CN" },
1208 { "Chinese, Traditional", "zh_TW" },
1209 { "Chinese, Tradtional", "zh_TW" },
1210 { "Croatian", "hr" },
1211 { "Czech", "cs" },
1212 { "Danish", "da" },
1213 { "Dutch", "nl" },
1214 { "Dzongkha", "dz" },
1215 { "English", "en" },
1216 { "Esperanto", "eo" },
1217 { "Estonian", "et" },
1218 { "Faroese", "fo" },
1219 { "Farsi", "fa" },
1220 { "Finnish", "fi" },
1221 { "Flemish", "nl_BE" },
1222 { "French", "fr" },
1223 { "Galician", "gl" },
1224 { "Gallegan", "gl" },
1225 { "Georgian", "ka" },
1226 { "German", "de" },
1227 { "Greek", "el" },
1228 { "Greenlandic", "kl" },
1229 { "Guarani", "gn" },
1230 { "Gujarati", "gu" },
1231 { "Hawaiian", "haw" }, /* Yes, "haw", not "cpe". */
1232 { "Hebrew", "he" },
1233 { "Hindi", "hi" },
1234 { "Hungarian", "hu" },
1235 { "Icelandic", "is" },
1236 { "Indonesian", "id" },
1237 { "Inuktitut", "iu" },
1238 { "Irish", "ga" },
1239 { "Italian", "it" },
1240 { "Japanese", "ja" },
1241 { "Javanese", "jv" },
1242 { "Kalaallisut", "kl" },
1243 { "Kannada", "kn" },
1244 { "Kashmiri", "ks" },
1245 { "Kazakh", "kk" },
1246 { "Khmer", "km" },
1247 { "Kinyarwanda", "rw" },
1248 { "Kirghiz", "ky" },
1249 { "Korean", "ko" },
1250 { "Kurdish", "ku" },
1251 { "Latin", "la" },
1252 { "Latvian", "lv" },
1253 { "Lithuanian", "lt" },
1254 { "Macedonian", "mk" },
1255 { "Malagasy", "mg" },
1256 { "Malay", "ms" },
1257 { "Malayalam", "ml" },
1258 { "Maltese", "mt" },
1259 { "Manx", "gv" },
1260 { "Marathi", "mr" },
1261 { "Moldavian", "mo" },
1262 { "Mongolian", "mn" },
1263 { "Nepali", "ne" },
1264 { "Norwegian", "nb" }, /* Yes, "nb", not the obsolete "no". */
1265 { "Nyanja", "ny" },
1266 { "Nynorsk", "nn" },
1267 { "Oriya", "or" },
1268 { "Oromo", "om" },
1269 { "Panjabi", "pa" },
1270 { "Pashto", "ps" },
1271 { "Persian", "fa" },
1272 { "Polish", "pl" },
1273 { "Portuguese", "pt" },
1274 { "Portuguese, Brazilian", "pt_BR" },
1275 { "Punjabi", "pa" },
1276 { "Pushto", "ps" },
1277 { "Quechua", "qu" },
1278 { "Romanian", "ro" },
1279 { "Ruanda", "rw" },
1280 { "Rundi", "rn" },
1281 { "Russian", "ru" },
1282 { "Sami", "se_NO" }, /* Not just "se". */
1283 { "Sanskrit", "sa" },
1284 { "Scottish", "gd" },
1285 { "Serbian", "sr" },
1286 { "Simplified Chinese", "zh_CN" },
1287 { "Sindhi", "sd" },
1288 { "Sinhalese", "si" },
1289 { "Slovak", "sk" },
1290 { "Slovenian", "sl" },
1291 { "Somali", "so" },
1292 { "Spanish", "es" },
1293 { "Sundanese", "su" },
1294 { "Swahili", "sw" },
1295 { "Swedish", "sv" },
1296 { "Tagalog", "tl" },
1297 { "Tajik", "tg" },
1298 { "Tajiki", "tg" },
1299 { "Tamil", "ta" },
1300 { "Tatar", "tt" },
1301 { "Telugu", "te" },
1302 { "Thai", "th" },
1303 { "Tibetan", "bo" },
1304 { "Tigrinya", "ti" },
1305 { "Tongan", "to" },
1306 { "Traditional Chinese", "zh_TW" },
1307 { "Turkish", "tr" },
1308 { "Turkmen", "tk" },
1309 { "Uighur", "ug" },
1310 { "Ukrainian", "uk" },
1311 { "Urdu", "ur" },
1312 { "Uzbek", "uz" },
1313 { "Vietnamese", "vi" },
1314 { "Welsh", "cy" },
1315 { "Yiddish", "yi" }
1316 };
1317
1318 /* Convert new-style locale names with language tags (ISO 639 and ISO 15924)
1319 to Unix (ISO 639 and ISO 3166) names. */
1320 typedef struct { const char langtag[7+1]; const char unixy[12+1]; }
1321 langtag_entry;
1322 static const langtag_entry langtag_table[] = {
1323 /* Mac OS X has "az-Arab", "az-Cyrl", "az-Latn".
1324 The default script for az on Unix is Latin. */
1325 { "az-Latn", "az" },
1326 /* Mac OS X has "bs-Cyrl", "bs-Latn".
1327 The default script for bs on Unix is Latin. */
1328 { "bs-Latn", "bs" },
1329 /* Mac OS X has "ga-dots". Does not yet exist on Unix. */
1330 { "ga-dots", "ga" },
1331 /* Mac OS X has "kk-Cyrl".
1332 The default script for kk on Unix is Cyrillic. */
1333 { "kk-Cyrl", "kk" },
1334 /* Mac OS X has "mn-Cyrl", "mn-Mong".
1335 The default script for mn on Unix is Cyrillic. */
1336 { "mn-Cyrl", "mn" },
1337 /* Mac OS X has "ms-Arab", "ms-Latn".
1338 The default script for ms on Unix is Latin. */
1339 { "ms-Latn", "ms" },
1340 /* Mac OS X has "pa-Arab", "pa-Guru".
1341 Country codes are used to distinguish these on Unix. */
1342 { "pa-Arab", "pa_PK" },
1343 { "pa-Guru", "pa_IN" },
1344 /* Mac OS X has "shi-Latn", "shi-Tfng". Does not yet exist on Unix. */
1345 /* Mac OS X has "sr-Cyrl", "sr-Latn".
1346 The default script for sr on Unix is Cyrillic. */
1347 { "sr-Cyrl", "sr" },
1348 /* Mac OS X has "tg-Cyrl".
1349 The default script for tg on Unix is Cyrillic. */
1350 { "tg-Cyrl", "tg" },
1351 /* Mac OS X has "tk-Cyrl".
1352 The default script for tk on Unix is Cyrillic. */
1353 { "tk-Cyrl", "tk" },
1354 /* Mac OS X has "tt-Cyrl".
1355 The default script for tt on Unix is Cyrillic. */
1356 { "tt-Cyrl", "tt" },
1357 /* Mac OS X has "uz-Arab", "uz-Cyrl", "uz-Latn".
1358 The default script for uz on Unix is Latin. */
1359 { "uz-Latn", "uz" },
1360 /* Mac OS X has "vai-Latn", "vai-Vaii". Does not yet exist on Unix. */
1361 /* Mac OS X has "yue-Hans", "yue-Hant".
1362 The default script for yue on Unix is Simplified Han. */
1363 { "yue-Hans", "yue" },
1364 /* Mac OS X has "zh-Hans", "zh-Hant".
1365 Country codes are used to distinguish these on Unix. */
1366 { "zh-Hans", "zh_CN" },
1367 { "zh-Hant", "zh_TW" }
1368 };
1369
1370 /* Convert script names (ISO 15924) to Unix conventions.
1371 See https://www.unicode.org/iso15924/iso15924-codes.html */
1372 typedef struct { const char script[4+1]; const char unixy[9+1]; }
1373 script_entry;
1374 static const script_entry script_table[] = {
1375 { "Arab", "arabic" },
1376 { "Cyrl", "cyrillic" },
1377 { "Latn", "latin" },
1378 { "Mong", "mongolian" }
1379 };
1380
1381 /* Step 1: Convert using legacy_table. */
1382 if (name[0] >= 'A' && name[0] <= 'Z')
1383 {
1384 unsigned int i1, i2;
1385 i1 = 0;
1386 i2 = sizeof (legacy_table) / sizeof (legacy_entry);
1387 while (i2 - i1 > 1)
1388 {
1389 /* At this point we know that if name occurs in legacy_table,
1390 its index must be >= i1 and < i2. */
1391 unsigned int i = (i1 + i2) >> 1;
1392 const legacy_entry *p = &legacy_table[i];
1393 if (strcmp (name, p->legacy) < 0)
1394 i2 = i;
1395 else
1396 i1 = i;
1397 }
1398 if (strcmp (name, legacy_table[i1].legacy) == 0)
1399 {
1400 strcpy (name, legacy_table[i1].unixy);
1401 return;
1402 }
1403 }
1404
1405 /* Step 2: Convert using langtag_table and script_table. */
1406 if (strlen (name) == 7 && name[2] == '-')
1407 {
1408 unsigned int i1, i2;
1409 i1 = 0;
1410 i2 = sizeof (langtag_table) / sizeof (langtag_entry);
1411 while (i2 - i1 > 1)
1412 {
1413 /* At this point we know that if name occurs in langtag_table,
1414 its index must be >= i1 and < i2. */
1415 unsigned int i = (i1 + i2) >> 1;
1416 const langtag_entry *p = &langtag_table[i];
1417 if (strcmp (name, p->langtag) < 0)
1418 i2 = i;
1419 else
1420 i1 = i;
1421 }
1422 if (strcmp (name, langtag_table[i1].langtag) == 0)
1423 {
1424 strcpy (name, langtag_table[i1].unixy);
1425 return;
1426 }
1427
1428 i1 = 0;
1429 i2 = sizeof (script_table) / sizeof (script_entry);
1430 while (i2 - i1 > 1)
1431 {
1432 /* At this point we know that if (name + 3) occurs in script_table,
1433 its index must be >= i1 and < i2. */
1434 unsigned int i = (i1 + i2) >> 1;
1435 const script_entry *p = &script_table[i];
1436 if (strcmp (name + 3, p->script) < 0)
1437 i2 = i;
1438 else
1439 i1 = i;
1440 }
1441 if (strcmp (name + 3, script_table[i1].script) == 0)
1442 {
1443 name[2] = '@';
1444 strcpy (name + 3, script_table[i1].unixy);
1445 return;
1446 }
1447 }
1448
1449 /* Step 3: Convert new-style dash to Unix underscore. */
1450 {
1451 char *p;
1452 for (p = name; *p != '\0'; p++)
1453 if (*p == '-')
1454 *p = '_';
1455 }
1456 }
1457
1458 #endif
1459
1460
1461 #if defined WINDOWS_NATIVE || defined __CYGWIN__ /* Native Windows or Cygwin */
1462
1463 /* Canonicalize a Windows native locale name to a Unix locale name.
1464 NAME is a sufficiently large buffer.
1465 On input, it contains the Windows locale name.
1466 On output, it contains the Unix locale name. */
1467 # if !defined IN_LIBINTL
1468 static
1469 # endif
1470 void
1471 gl_locale_name_canonicalize (char *name)
1472 {
1473 /* FIXME: This is probably incomplete: it does not handle "zh-Hans" and
1474 "zh-Hant". */
1475 char *p;
1476
1477 for (p = name; *p != '\0'; p++)
1478 if (*p == '-')
1479 {
1480 *p = '_';
1481 p++;
1482 for (; *p != '\0'; p++)
1483 {
1484 if (*p >= 'a' && *p <= 'z')
1485 *p += 'A' - 'a';
1486 if (*p == '-')
1487 {
1488 *p = '\0';
1489 return;
1490 }
1491 }
1492 return;
1493 }
1494 }
1495
1496 # if !defined IN_LIBINTL
1497 static
1498 # endif
1499 const char *
1500 gl_locale_name_from_win32_LANGID (LANGID langid)
1501 {
1502 /* Activate the new code only when the GETTEXT_MUI environment variable is
1503 set, for the time being, since the new code is not well tested. */
1504 if (getenv ("GETTEXT_MUI") != NULL)
1505 {
1506 static char namebuf[256];
1507
1508 /* Query the system's notion of locale name.
1509 On Windows95/98/ME, GetLocaleInfoA returns some incorrect results.
1510 But we don't need to support systems that are so old. */
1511 if (GetLocaleInfoA (MAKELCID (langid, SORT_DEFAULT), LOCALE_SNAME,
1512 namebuf, sizeof (namebuf) - 1))
1513 {
1514 /* Convert it to a Unix locale name. */
1515 gl_locale_name_canonicalize (namebuf);
1516 return namebuf;
1517 }
1518 }
1519 /* Internet Explorer has an LCID to RFC3066 name mapping stored in
1520 HKEY_CLASSES_ROOT\Mime\Database\Rfc1766. But we better don't use that
1521 since IE's i18n subsystem is known to be inconsistent with the native
1522 Windows base (e.g. they have different character conversion facilities
1523 that produce different results). */
1524 /* Use our own table. */
1525 {
1526 int primary, sub;
1527
1528 /* Split into language and territory part. */
1529 primary = PRIMARYLANGID (langid);
1530 sub = SUBLANGID (langid);
1531
1532 /* Dispatch on language.
1533 See also https://www.unicode.org/unicode/onlinedat/languages.html .
1534 For details about languages, see https://www.ethnologue.com/ . */
1535 switch (primary)
1536 {
1537 case LANG_AFRIKAANS:
1538 switch (sub)
1539 {
1540 case SUBLANG_AFRIKAANS_SOUTH_AFRICA: return "af_ZA";
1541 }
1542 return "af";
1543 case LANG_ALBANIAN:
1544 switch (sub)
1545 {
1546 case SUBLANG_ALBANIAN_ALBANIA: return "sq_AL";
1547 }
1548 return "sq";
1549 case LANG_ALSATIAN:
1550 switch (sub)
1551 {
1552 case SUBLANG_ALSATIAN_FRANCE: return "gsw_FR";
1553 }
1554 return "gsw";
1555 case LANG_AMHARIC:
1556 switch (sub)
1557 {
1558 case SUBLANG_AMHARIC_ETHIOPIA: return "am_ET";
1559 }
1560 return "am";
1561 case LANG_ARABIC:
1562 switch (sub)
1563 {
1564 case SUBLANG_ARABIC_SAUDI_ARABIA: return "ar_SA";
1565 case SUBLANG_ARABIC_IRAQ: return "ar_IQ";
1566 case SUBLANG_ARABIC_EGYPT: return "ar_EG";
1567 case SUBLANG_ARABIC_LIBYA: return "ar_LY";
1568 case SUBLANG_ARABIC_ALGERIA: return "ar_DZ";
1569 case SUBLANG_ARABIC_MOROCCO: return "ar_MA";
1570 case SUBLANG_ARABIC_TUNISIA: return "ar_TN";
1571 case SUBLANG_ARABIC_OMAN: return "ar_OM";
1572 case SUBLANG_ARABIC_YEMEN: return "ar_YE";
1573 case SUBLANG_ARABIC_SYRIA: return "ar_SY";
1574 case SUBLANG_ARABIC_JORDAN: return "ar_JO";
1575 case SUBLANG_ARABIC_LEBANON: return "ar_LB";
1576 case SUBLANG_ARABIC_KUWAIT: return "ar_KW";
1577 case SUBLANG_ARABIC_UAE: return "ar_AE";
1578 case SUBLANG_ARABIC_BAHRAIN: return "ar_BH";
1579 case SUBLANG_ARABIC_QATAR: return "ar_QA";
1580 }
1581 return "ar";
1582 case LANG_ARMENIAN:
1583 switch (sub)
1584 {
1585 case SUBLANG_ARMENIAN_ARMENIA: return "hy_AM";
1586 }
1587 return "hy";
1588 case LANG_ASSAMESE:
1589 switch (sub)
1590 {
1591 case SUBLANG_ASSAMESE_INDIA: return "as_IN";
1592 }
1593 return "as";
1594 case LANG_AZERI:
1595 switch (sub)
1596 {
1597 /* FIXME: Adjust this when Azerbaijani locales appear on Unix. */
1598 case 0x1e: return "az@latin";
1599 case SUBLANG_AZERI_LATIN: return "az_AZ@latin";
1600 case 0x1d: return "az@cyrillic";
1601 case SUBLANG_AZERI_CYRILLIC: return "az_AZ@cyrillic";
1602 }
1603 return "az";
1604 case LANG_BASHKIR:
1605 switch (sub)
1606 {
1607 case SUBLANG_BASHKIR_RUSSIA: return "ba_RU";
1608 }
1609 return "ba";
1610 case LANG_BASQUE:
1611 switch (sub)
1612 {
1613 case SUBLANG_BASQUE_BASQUE: return "eu_ES";
1614 }
1615 return "eu"; /* Ambiguous: could be "eu_ES" or "eu_FR". */
1616 case LANG_BELARUSIAN:
1617 switch (sub)
1618 {
1619 case SUBLANG_BELARUSIAN_BELARUS: return "be_BY";
1620 }
1621 return "be";
1622 case LANG_BENGALI:
1623 switch (sub)
1624 {
1625 case SUBLANG_BENGALI_INDIA: return "bn_IN";
1626 case SUBLANG_BENGALI_BANGLADESH: return "bn_BD";
1627 }
1628 return "bn";
1629 case LANG_BRETON:
1630 switch (sub)
1631 {
1632 case SUBLANG_BRETON_FRANCE: return "br_FR";
1633 }
1634 return "br";
1635 case LANG_BULGARIAN:
1636 switch (sub)
1637 {
1638 case SUBLANG_BULGARIAN_BULGARIA: return "bg_BG";
1639 }
1640 return "bg";
1641 case LANG_BURMESE:
1642 switch (sub)
1643 {
1644 case SUBLANG_DEFAULT: return "my_MM";
1645 }
1646 return "my";
1647 case LANG_CAMBODIAN:
1648 switch (sub)
1649 {
1650 case SUBLANG_CAMBODIAN_CAMBODIA: return "km_KH";
1651 }
1652 return "km";
1653 case LANG_CATALAN:
1654 switch (sub)
1655 {
1656 case SUBLANG_CATALAN_SPAIN: return "ca_ES";
1657 }
1658 return "ca";
1659 case LANG_CHEROKEE:
1660 switch (sub)
1661 {
1662 case SUBLANG_DEFAULT: return "chr_US";
1663 }
1664 return "chr";
1665 case LANG_CHINESE:
1666 switch (sub)
1667 {
1668 case SUBLANG_CHINESE_TRADITIONAL: case 0x1f: return "zh_TW";
1669 case SUBLANG_CHINESE_SIMPLIFIED: case 0x00: return "zh_CN";
1670 case SUBLANG_CHINESE_HONGKONG: return "zh_HK"; /* traditional */
1671 case SUBLANG_CHINESE_SINGAPORE: return "zh_SG"; /* simplified */
1672 case SUBLANG_CHINESE_MACAU: return "zh_MO"; /* traditional */
1673 }
1674 return "zh";
1675 case LANG_CORSICAN:
1676 switch (sub)
1677 {
1678 case SUBLANG_CORSICAN_FRANCE: return "co_FR";
1679 }
1680 return "co";
1681 case LANG_CROATIAN: /* LANG_CROATIAN == LANG_SERBIAN == LANG_BOSNIAN
1682 * What used to be called Serbo-Croatian
1683 * should really now be two separate
1684 * languages because of political reasons.
1685 * (Says tml, who knows nothing about Serbian
1686 * or Croatian.)
1687 * (I can feel those flames coming already.)
1688 */
1689 switch (sub)
1690 {
1691 /* Croatian */
1692 case 0x00: return "hr";
1693 case SUBLANG_CROATIAN_CROATIA: return "hr_HR";
1694 case SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN: return "hr_BA";
1695 /* Serbian */
1696 case 0x1f: return "sr";
1697 case 0x1c: return "sr"; /* latin */
1698 case SUBLANG_SERBIAN_LATIN: return "sr_CS"; /* latin */
1699 case 0x09: return "sr_RS"; /* latin */
1700 case 0x0b: return "sr_ME"; /* latin */
1701 case 0x06: return "sr_BA"; /* latin */
1702 case 0x1b: return "sr@cyrillic";
1703 case SUBLANG_SERBIAN_CYRILLIC: return "sr_CS@cyrillic";
1704 case 0x0a: return "sr_RS@cyrillic";
1705 case 0x0c: return "sr_ME@cyrillic";
1706 case 0x07: return "sr_BA@cyrillic";
1707 /* Bosnian */
1708 case 0x1e: return "bs";
1709 case 0x1a: return "bs"; /* latin */
1710 case SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN: return "bs_BA"; /* latin */
1711 case 0x19: return "bs@cyrillic";
1712 case SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC: return "bs_BA@cyrillic";
1713 }
1714 return "hr";
1715 case LANG_CZECH:
1716 switch (sub)
1717 {
1718 case SUBLANG_CZECH_CZECH_REPUBLIC: return "cs_CZ";
1719 }
1720 return "cs";
1721 case LANG_DANISH:
1722 switch (sub)
1723 {
1724 case SUBLANG_DANISH_DENMARK: return "da_DK";
1725 }
1726 return "da";
1727 case LANG_DARI:
1728 /* FIXME: Adjust this when such locales appear on Unix. */
1729 switch (sub)
1730 {
1731 case SUBLANG_DARI_AFGHANISTAN: return "prs_AF";
1732 }
1733 return "prs";
1734 case LANG_DIVEHI:
1735 switch (sub)
1736 {
1737 case SUBLANG_DIVEHI_MALDIVES: return "dv_MV";
1738 }
1739 return "dv";
1740 case LANG_DUTCH:
1741 switch (sub)
1742 {
1743 case SUBLANG_DUTCH: return "nl_NL";
1744 case SUBLANG_DUTCH_BELGIAN: /* FLEMISH, VLAAMS */ return "nl_BE";
1745 case SUBLANG_DUTCH_SURINAM: return "nl_SR";
1746 }
1747 return "nl";
1748 case LANG_EDO:
1749 switch (sub)
1750 {
1751 case SUBLANG_DEFAULT: return "bin_NG";
1752 }
1753 return "bin";
1754 case LANG_ENGLISH:
1755 switch (sub)
1756 {
1757 /* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought
1758 * English was the language spoken in England.
1759 * Oh well.
1760 */
1761 case SUBLANG_ENGLISH_US: return "en_US";
1762 case SUBLANG_ENGLISH_UK: return "en_GB";
1763 case SUBLANG_ENGLISH_AUS: return "en_AU";
1764 case SUBLANG_ENGLISH_CAN: return "en_CA";
1765 case SUBLANG_ENGLISH_NZ: return "en_NZ";
1766 case SUBLANG_ENGLISH_EIRE: return "en_IE";
1767 case SUBLANG_ENGLISH_SOUTH_AFRICA: return "en_ZA";
1768 case SUBLANG_ENGLISH_JAMAICA: return "en_JM";
1769 case SUBLANG_ENGLISH_CARIBBEAN: return "en_GD"; /* Grenada? */
1770 case SUBLANG_ENGLISH_BELIZE: return "en_BZ";
1771 case SUBLANG_ENGLISH_TRINIDAD: return "en_TT";
1772 case SUBLANG_ENGLISH_ZIMBABWE: return "en_ZW";
1773 case SUBLANG_ENGLISH_PHILIPPINES: return "en_PH";
1774 case SUBLANG_ENGLISH_INDONESIA: return "en_ID";
1775 case SUBLANG_ENGLISH_HONGKONG: return "en_HK";
1776 case SUBLANG_ENGLISH_INDIA: return "en_IN";
1777 case SUBLANG_ENGLISH_MALAYSIA: return "en_MY";
1778 case SUBLANG_ENGLISH_SINGAPORE: return "en_SG";
1779 }
1780 return "en";
1781 case LANG_ESTONIAN:
1782 switch (sub)
1783 {
1784 case SUBLANG_ESTONIAN_ESTONIA: return "et_EE";
1785 }
1786 return "et";
1787 case LANG_FAEROESE:
1788 switch (sub)
1789 {
1790 case SUBLANG_FAEROESE_FAROE_ISLANDS: return "fo_FO";
1791 }
1792 return "fo";
1793 case LANG_FARSI:
1794 switch (sub)
1795 {
1796 case SUBLANG_FARSI_IRAN: return "fa_IR";
1797 }
1798 return "fa";
1799 case LANG_FINNISH:
1800 switch (sub)
1801 {
1802 case SUBLANG_FINNISH_FINLAND: return "fi_FI";
1803 }
1804 return "fi";
1805 case LANG_FRENCH:
1806 switch (sub)
1807 {
1808 case SUBLANG_FRENCH: return "fr_FR";
1809 case SUBLANG_FRENCH_BELGIAN: /* WALLOON */ return "fr_BE";
1810 case SUBLANG_FRENCH_CANADIAN: return "fr_CA";
1811 case SUBLANG_FRENCH_SWISS: return "fr_CH";
1812 case SUBLANG_FRENCH_LUXEMBOURG: return "fr_LU";
1813 case SUBLANG_FRENCH_MONACO: return "fr_MC";
1814 case SUBLANG_FRENCH_WESTINDIES: return "fr"; /* Caribbean? */
1815 case SUBLANG_FRENCH_REUNION: return "fr_RE";
1816 case SUBLANG_FRENCH_CONGO: return "fr_CG";
1817 case SUBLANG_FRENCH_SENEGAL: return "fr_SN";
1818 case SUBLANG_FRENCH_CAMEROON: return "fr_CM";
1819 case SUBLANG_FRENCH_COTEDIVOIRE: return "fr_CI";
1820 case SUBLANG_FRENCH_MALI: return "fr_ML";
1821 case SUBLANG_FRENCH_MOROCCO: return "fr_MA";
1822 case SUBLANG_FRENCH_HAITI: return "fr_HT";
1823 }
1824 return "fr";
1825 case LANG_FRISIAN:
1826 switch (sub)
1827 {
1828 case SUBLANG_FRISIAN_NETHERLANDS: return "fy_NL";
1829 }
1830 return "fy";
1831 case LANG_FULFULDE:
1832 /* Spoken in Nigeria, Guinea, Senegal, Mali, Niger, Cameroon, Benin. */
1833 switch (sub)
1834 {
1835 case SUBLANG_DEFAULT: return "ff_NG";
1836 }
1837 return "ff";
1838 case LANG_GAELIC:
1839 switch (sub)
1840 {
1841 case 0x01: /* SCOTTISH */
1842 /* old, superseded by LANG_SCOTTISH_GAELIC */
1843 return "gd_GB";
1844 case SUBLANG_IRISH_IRELAND: return "ga_IE";
1845 }
1846 return "ga";
1847 case LANG_GALICIAN:
1848 switch (sub)
1849 {
1850 case SUBLANG_GALICIAN_SPAIN: return "gl_ES";
1851 }
1852 return "gl";
1853 case LANG_GEORGIAN:
1854 switch (sub)
1855 {
1856 case SUBLANG_GEORGIAN_GEORGIA: return "ka_GE";
1857 }
1858 return "ka";
1859 case LANG_GERMAN:
1860 switch (sub)
1861 {
1862 case SUBLANG_GERMAN: return "de_DE";
1863 case SUBLANG_GERMAN_SWISS: return "de_CH";
1864 case SUBLANG_GERMAN_AUSTRIAN: return "de_AT";
1865 case SUBLANG_GERMAN_LUXEMBOURG: return "de_LU";
1866 case SUBLANG_GERMAN_LIECHTENSTEIN: return "de_LI";
1867 }
1868 return "de";
1869 case LANG_GREEK:
1870 switch (sub)
1871 {
1872 case SUBLANG_GREEK_GREECE: return "el_GR";
1873 }
1874 return "el";
1875 case LANG_GREENLANDIC:
1876 switch (sub)
1877 {
1878 case SUBLANG_GREENLANDIC_GREENLAND: return "kl_GL";
1879 }
1880 return "kl";
1881 case LANG_GUARANI:
1882 switch (sub)
1883 {
1884 case SUBLANG_DEFAULT: return "gn_PY";
1885 }
1886 return "gn";
1887 case LANG_GUJARATI:
1888 switch (sub)
1889 {
1890 case SUBLANG_GUJARATI_INDIA: return "gu_IN";
1891 }
1892 return "gu";
1893 case LANG_HAUSA:
1894 switch (sub)
1895 {
1896 case 0x1f: return "ha";
1897 case SUBLANG_HAUSA_NIGERIA_LATIN: return "ha_NG";
1898 }
1899 return "ha";
1900 case LANG_HAWAIIAN:
1901 /* FIXME: Do they mean Hawaiian ("haw_US", 1000 speakers)
1902 or Hawaii Creole English ("cpe_US", 600000 speakers)? */
1903 switch (sub)
1904 {
1905 case SUBLANG_DEFAULT: return "cpe_US";
1906 }
1907 return "cpe";
1908 case LANG_HEBREW:
1909 switch (sub)
1910 {
1911 case SUBLANG_HEBREW_ISRAEL: return "he_IL";
1912 }
1913 return "he";
1914 case LANG_HINDI:
1915 switch (sub)
1916 {
1917 case SUBLANG_HINDI_INDIA: return "hi_IN";
1918 }
1919 return "hi";
1920 case LANG_HUNGARIAN:
1921 switch (sub)
1922 {
1923 case SUBLANG_HUNGARIAN_HUNGARY: return "hu_HU";
1924 }
1925 return "hu";
1926 case LANG_IBIBIO:
1927 switch (sub)
1928 {
1929 case SUBLANG_DEFAULT: return "nic_NG";
1930 }
1931 return "nic";
1932 case LANG_ICELANDIC:
1933 switch (sub)
1934 {
1935 case SUBLANG_ICELANDIC_ICELAND: return "is_IS";
1936 }
1937 return "is";
1938 case LANG_IGBO:
1939 switch (sub)
1940 {
1941 case SUBLANG_IGBO_NIGERIA: return "ig_NG";
1942 }
1943 return "ig";
1944 case LANG_INDONESIAN:
1945 switch (sub)
1946 {
1947 case SUBLANG_INDONESIAN_INDONESIA: return "id_ID";
1948 }
1949 return "id";
1950 case LANG_INUKTITUT:
1951 switch (sub)
1952 {
1953 case 0x1e: return "iu"; /* syllabic */
1954 case SUBLANG_INUKTITUT_CANADA: return "iu_CA"; /* syllabic */
1955 case 0x1f: return "iu@latin";
1956 case SUBLANG_INUKTITUT_CANADA_LATIN: return "iu_CA@latin";
1957 }
1958 return "iu";
1959 case LANG_ITALIAN:
1960 switch (sub)
1961 {
1962 case SUBLANG_ITALIAN: return "it_IT";
1963 case SUBLANG_ITALIAN_SWISS: return "it_CH";
1964 }
1965 return "it";
1966 case LANG_JAPANESE:
1967 switch (sub)
1968 {
1969 case SUBLANG_JAPANESE_JAPAN: return "ja_JP";
1970 }
1971 return "ja";
1972 case LANG_KANNADA:
1973 switch (sub)
1974 {
1975 case SUBLANG_KANNADA_INDIA: return "kn_IN";
1976 }
1977 return "kn";
1978 case LANG_KANURI:
1979 switch (sub)
1980 {
1981 case SUBLANG_DEFAULT: return "kr_NG";
1982 }
1983 return "kr";
1984 case LANG_KASHMIRI:
1985 switch (sub)
1986 {
1987 case SUBLANG_DEFAULT: return "ks_PK";
1988 case SUBLANG_KASHMIRI_INDIA: return "ks_IN";
1989 }
1990 return "ks";
1991 case LANG_KAZAK:
1992 switch (sub)
1993 {
1994 case SUBLANG_KAZAK_KAZAKHSTAN: return "kk_KZ";
1995 }
1996 return "kk";
1997 case LANG_KICHE:
1998 /* FIXME: Adjust this when such locales appear on Unix. */
1999 switch (sub)
2000 {
2001 case SUBLANG_KICHE_GUATEMALA: return "qut_GT";
2002 }
2003 return "qut";
2004 case LANG_KINYARWANDA:
2005 switch (sub)
2006 {
2007 case SUBLANG_KINYARWANDA_RWANDA: return "rw_RW";
2008 }
2009 return "rw";
2010 case LANG_KONKANI:
2011 /* FIXME: Adjust this when such locales appear on Unix. */
2012 switch (sub)
2013 {
2014 case SUBLANG_KONKANI_INDIA: return "kok_IN";
2015 }
2016 return "kok";
2017 case LANG_KOREAN:
2018 switch (sub)
2019 {
2020 case SUBLANG_DEFAULT: return "ko_KR";
2021 }
2022 return "ko";
2023 case LANG_KYRGYZ:
2024 switch (sub)
2025 {
2026 case SUBLANG_KYRGYZ_KYRGYZSTAN: return "ky_KG";
2027 }
2028 return "ky";
2029 case LANG_LAO:
2030 switch (sub)
2031 {
2032 case SUBLANG_LAO_LAOS: return "lo_LA";
2033 }
2034 return "lo";
2035 case LANG_LATIN:
2036 switch (sub)
2037 {
2038 case SUBLANG_DEFAULT: return "la_VA";
2039 }
2040 return "la";
2041 case LANG_LATVIAN:
2042 switch (sub)
2043 {
2044 case SUBLANG_LATVIAN_LATVIA: return "lv_LV";
2045 }
2046 return "lv";
2047 case LANG_LITHUANIAN:
2048 switch (sub)
2049 {
2050 case SUBLANG_LITHUANIAN_LITHUANIA: return "lt_LT";
2051 }
2052 return "lt";
2053 case LANG_LUXEMBOURGISH:
2054 switch (sub)
2055 {
2056 case SUBLANG_LUXEMBOURGISH_LUXEMBOURG: return "lb_LU";
2057 }
2058 return "lb";
2059 case LANG_MACEDONIAN:
2060 switch (sub)
2061 {
2062 case SUBLANG_MACEDONIAN_MACEDONIA: return "mk_MK";
2063 }
2064 return "mk";
2065 case LANG_MALAY:
2066 switch (sub)
2067 {
2068 case SUBLANG_MALAY_MALAYSIA: return "ms_MY";
2069 case SUBLANG_MALAY_BRUNEI_DARUSSALAM: return "ms_BN";
2070 }
2071 return "ms";
2072 case LANG_MALAYALAM:
2073 switch (sub)
2074 {
2075 case SUBLANG_MALAYALAM_INDIA: return "ml_IN";
2076 }
2077 return "ml";
2078 case LANG_MALTESE:
2079 switch (sub)
2080 {
2081 case SUBLANG_MALTESE_MALTA: return "mt_MT";
2082 }
2083 return "mt";
2084 case LANG_MANIPURI:
2085 /* FIXME: Adjust this when such locales appear on Unix. */
2086 switch (sub)
2087 {
2088 case SUBLANG_DEFAULT: return "mni_IN";
2089 }
2090 return "mni";
2091 case LANG_MAORI:
2092 switch (sub)
2093 {
2094 case SUBLANG_MAORI_NEW_ZEALAND: return "mi_NZ";
2095 }
2096 return "mi";
2097 case LANG_MAPUDUNGUN:
2098 switch (sub)
2099 {
2100 case SUBLANG_MAPUDUNGUN_CHILE: return "arn_CL";
2101 }
2102 return "arn";
2103 case LANG_MARATHI:
2104 switch (sub)
2105 {
2106 case SUBLANG_MARATHI_INDIA: return "mr_IN";
2107 }
2108 return "mr";
2109 case LANG_MOHAWK:
2110 switch (sub)
2111 {
2112 case SUBLANG_MOHAWK_CANADA: return "moh_CA";
2113 }
2114 return "moh";
2115 case LANG_MONGOLIAN:
2116 switch (sub)
2117 {
2118 case SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA: case 0x1e: return "mn_MN";
2119 case SUBLANG_MONGOLIAN_PRC: case 0x1f: return "mn_CN";
2120 }
2121 return "mn"; /* Ambiguous: could be "mn_CN" or "mn_MN". */
2122 case LANG_NEPALI:
2123 switch (sub)
2124 {
2125 case SUBLANG_NEPALI_NEPAL: return "ne_NP";
2126 case SUBLANG_NEPALI_INDIA: return "ne_IN";
2127 }
2128 return "ne";
2129 case LANG_NORWEGIAN:
2130 switch (sub)
2131 {
2132 case 0x1f: return "nb";
2133 case SUBLANG_NORWEGIAN_BOKMAL: return "nb_NO";
2134 case 0x1e: return "nn";
2135 case SUBLANG_NORWEGIAN_NYNORSK: return "nn_NO";
2136 }
2137 return "no";
2138 case LANG_OCCITAN:
2139 switch (sub)
2140 {
2141 case SUBLANG_OCCITAN_FRANCE: return "oc_FR";
2142 }
2143 return "oc";
2144 case LANG_ORIYA:
2145 switch (sub)
2146 {
2147 case SUBLANG_ORIYA_INDIA: return "or_IN";
2148 }
2149 return "or";
2150 case LANG_OROMO:
2151 switch (sub)
2152 {
2153 case SUBLANG_DEFAULT: return "om_ET";
2154 }
2155 return "om";
2156 case LANG_PAPIAMENTU:
2157 switch (sub)
2158 {
2159 case SUBLANG_DEFAULT: return "pap_AN";
2160 }
2161 return "pap";
2162 case LANG_PASHTO:
2163 switch (sub)
2164 {
2165 case SUBLANG_PASHTO_AFGHANISTAN: return "ps_AF";
2166 }
2167 return "ps"; /* Ambiguous: could be "ps_PK" or "ps_AF". */
2168 case LANG_POLISH:
2169 switch (sub)
2170 {
2171 case SUBLANG_POLISH_POLAND: return "pl_PL";
2172 }
2173 return "pl";
2174 case LANG_PORTUGUESE:
2175 switch (sub)
2176 {
2177 /* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT.
2178 Same phenomenon as SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. */
2179 case SUBLANG_PORTUGUESE_BRAZILIAN: return "pt_BR";
2180 case SUBLANG_PORTUGUESE: return "pt_PT";
2181 }
2182 return "pt";
2183 case LANG_PUNJABI:
2184 switch (sub)
2185 {
2186 case SUBLANG_PUNJABI_INDIA: return "pa_IN"; /* Gurmukhi script */
2187 case SUBLANG_PUNJABI_PAKISTAN: return "pa_PK"; /* Arabic script */
2188 }
2189 return "pa";
2190 case LANG_QUECHUA:
2191 /* Note: Microsoft uses the non-ISO language code "quz". */
2192 switch (sub)
2193 {
2194 case SUBLANG_QUECHUA_BOLIVIA: return "qu_BO";
2195 case SUBLANG_QUECHUA_ECUADOR: return "qu_EC";
2196 case SUBLANG_QUECHUA_PERU: return "qu_PE";
2197 }
2198 return "qu";
2199 case LANG_ROMANIAN:
2200 switch (sub)
2201 {
2202 case SUBLANG_ROMANIAN_ROMANIA: return "ro_RO";
2203 case SUBLANG_ROMANIAN_MOLDOVA: return "ro_MD";
2204 }
2205 return "ro";
2206 case LANG_ROMANSH:
2207 switch (sub)
2208 {
2209 case SUBLANG_ROMANSH_SWITZERLAND: return "rm_CH";
2210 }
2211 return "rm";
2212 case LANG_RUSSIAN:
2213 switch (sub)
2214 {
2215 case SUBLANG_RUSSIAN_RUSSIA: return "ru_RU";
2216 case SUBLANG_RUSSIAN_MOLDAVIA: return "ru_MD";
2217 }
2218 return "ru"; /* Ambiguous: could be "ru_RU" or "ru_UA" or "ru_MD". */
2219 case LANG_SAMI:
2220 switch (sub)
2221 {
2222 /* Northern Sami */
2223 case 0x00: return "se";
2224 case SUBLANG_SAMI_NORTHERN_NORWAY: return "se_NO";
2225 case SUBLANG_SAMI_NORTHERN_SWEDEN: return "se_SE";
2226 case SUBLANG_SAMI_NORTHERN_FINLAND: return "se_FI";
2227 /* Lule Sami */
2228 case 0x1f: return "smj";
2229 case SUBLANG_SAMI_LULE_NORWAY: return "smj_NO";
2230 case SUBLANG_SAMI_LULE_SWEDEN: return "smj_SE";
2231 /* Southern Sami */
2232 case 0x1e: return "sma";
2233 case SUBLANG_SAMI_SOUTHERN_NORWAY: return "sma_NO";
2234 case SUBLANG_SAMI_SOUTHERN_SWEDEN: return "sma_SE";
2235 /* Skolt Sami */
2236 case 0x1d: return "sms";
2237 case SUBLANG_SAMI_SKOLT_FINLAND: return "sms_FI";
2238 /* Inari Sami */
2239 case 0x1c: return "smn";
2240 case SUBLANG_SAMI_INARI_FINLAND: return "smn_FI";
2241 }
2242 return "se"; /* or "smi"? */
2243 case LANG_SANSKRIT:
2244 switch (sub)
2245 {
2246 case SUBLANG_SANSKRIT_INDIA: return "sa_IN";
2247 }
2248 return "sa";
2249 case LANG_SCOTTISH_GAELIC:
2250 switch (sub)
2251 {
2252 case SUBLANG_DEFAULT: return "gd_GB";
2253 }
2254 return "gd";
2255 case LANG_SINDHI:
2256 switch (sub)
2257 {
2258 case SUBLANG_SINDHI_INDIA: return "sd_IN";
2259 case SUBLANG_SINDHI_PAKISTAN: return "sd_PK";
2260 /*case SUBLANG_SINDHI_AFGHANISTAN: return "sd_AF";*/
2261 }
2262 return "sd";
2263 case LANG_SINHALESE:
2264 switch (sub)
2265 {
2266 case SUBLANG_SINHALESE_SRI_LANKA: return "si_LK";
2267 }
2268 return "si";
2269 case LANG_SLOVAK:
2270 switch (sub)
2271 {
2272 case SUBLANG_SLOVAK_SLOVAKIA: return "sk_SK";
2273 }
2274 return "sk";
2275 case LANG_SLOVENIAN:
2276 switch (sub)
2277 {
2278 case SUBLANG_SLOVENIAN_SLOVENIA: return "sl_SI";
2279 }
2280 return "sl";
2281 case LANG_SOMALI:
2282 switch (sub)
2283 {
2284 case SUBLANG_DEFAULT: return "so_SO";
2285 }
2286 return "so";
2287 case LANG_SORBIAN:
2288 /* FIXME: Adjust this when such locales appear on Unix. */
2289 switch (sub)
2290 {
2291 /* Upper Sorbian */
2292 case 0x00: return "hsb";
2293 case SUBLANG_UPPER_SORBIAN_GERMANY: return "hsb_DE";
2294 /* Lower Sorbian */
2295 case 0x1f: return "dsb";
2296 case SUBLANG_LOWER_SORBIAN_GERMANY: return "dsb_DE";
2297 }
2298 return "wen";
2299 case LANG_SOTHO:
2300 /* <https://docs.microsoft.com/en-us/windows/desktop/Intl/language-identifier-constants-and-strings>
2301 calls it "Sesotho sa Leboa"; according to
2302 <https://www.ethnologue.com/show_language.asp?code=nso>
2303 <https://www.ethnologue.com/show_language.asp?code=sot>
2304 it's the same as Northern Sotho. */
2305 switch (sub)
2306 {
2307 case SUBLANG_SOTHO_SOUTH_AFRICA: return "nso_ZA";
2308 }
2309 return "nso";
2310 case LANG_SPANISH:
2311 switch (sub)
2312 {
2313 case SUBLANG_SPANISH: return "es_ES";
2314 case SUBLANG_SPANISH_MEXICAN: return "es_MX";
2315 case SUBLANG_SPANISH_MODERN:
2316 return "es_ES@modern"; /* not seen on Unix */
2317 case SUBLANG_SPANISH_GUATEMALA: return "es_GT";
2318 case SUBLANG_SPANISH_COSTA_RICA: return "es_CR";
2319 case SUBLANG_SPANISH_PANAMA: return "es_PA";
2320 case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: return "es_DO";
2321 case SUBLANG_SPANISH_VENEZUELA: return "es_VE";
2322 case SUBLANG_SPANISH_COLOMBIA: return "es_CO";
2323 case SUBLANG_SPANISH_PERU: return "es_PE";
2324 case SUBLANG_SPANISH_ARGENTINA: return "es_AR";
2325 case SUBLANG_SPANISH_ECUADOR: return "es_EC";
2326 case SUBLANG_SPANISH_CHILE: return "es_CL";
2327 case SUBLANG_SPANISH_URUGUAY: return "es_UY";
2328 case SUBLANG_SPANISH_PARAGUAY: return "es_PY";
2329 case SUBLANG_SPANISH_BOLIVIA: return "es_BO";
2330 case SUBLANG_SPANISH_EL_SALVADOR: return "es_SV";
2331 case SUBLANG_SPANISH_HONDURAS: return "es_HN";
2332 case SUBLANG_SPANISH_NICARAGUA: return "es_NI";
2333 case SUBLANG_SPANISH_PUERTO_RICO: return "es_PR";
2334 case SUBLANG_SPANISH_US: return "es_US";
2335 }
2336 return "es";
2337 case LANG_SUTU:
2338 switch (sub)
2339 {
2340 case SUBLANG_DEFAULT: return "bnt_TZ"; /* or "st_LS" or "nso_ZA"? */
2341 }
2342 return "bnt";
2343 case LANG_SWAHILI:
2344 switch (sub)
2345 {
2346 case SUBLANG_SWAHILI_KENYA: return "sw_KE";
2347 }
2348 return "sw";
2349 case LANG_SWEDISH:
2350 switch (sub)
2351 {
2352 case SUBLANG_SWEDISH_SWEDEN: return "sv_SE";
2353 case SUBLANG_SWEDISH_FINLAND: return "sv_FI";
2354 }
2355 return "sv";
2356 case LANG_SYRIAC:
2357 switch (sub)
2358 {
2359 case SUBLANG_SYRIAC_SYRIA: return "syr_SY"; /* An extinct language. */
2360 }
2361 return "syr";
2362 case LANG_TAGALOG:
2363 switch (sub)
2364 {
2365 case SUBLANG_TAGALOG_PHILIPPINES: return "tl_PH"; /* or "fil_PH"? */
2366 }
2367 return "tl"; /* or "fil"? */
2368 case LANG_TAJIK:
2369 switch (sub)
2370 {
2371 case 0x1f: return "tg";
2372 case SUBLANG_TAJIK_TAJIKISTAN: return "tg_TJ";
2373 }
2374 return "tg";
2375 case LANG_TAMAZIGHT:
2376 /* Note: Microsoft uses the non-ISO language code "tmz". */
2377 switch (sub)
2378 {
2379 /* FIXME: Adjust this when Tamazight locales appear on Unix. */
2380 case SUBLANG_TAMAZIGHT_ARABIC: return "ber_MA@arabic";
2381 case 0x1f: return "ber@latin";
2382 case SUBLANG_TAMAZIGHT_ALGERIA_LATIN: return "ber_DZ@latin";
2383 }
2384 return "ber";
2385 case LANG_TAMIL:
2386 switch (sub)
2387 {
2388 case SUBLANG_TAMIL_INDIA: return "ta_IN";
2389 }
2390 return "ta"; /* Ambiguous: could be "ta_IN" or "ta_LK" or "ta_SG". */
2391 case LANG_TATAR:
2392 switch (sub)
2393 {
2394 case SUBLANG_TATAR_RUSSIA: return "tt_RU";
2395 }
2396 return "tt";
2397 case LANG_TELUGU:
2398 switch (sub)
2399 {
2400 case SUBLANG_TELUGU_INDIA: return "te_IN";
2401 }
2402 return "te";
2403 case LANG_THAI:
2404 switch (sub)
2405 {
2406 case SUBLANG_THAI_THAILAND: return "th_TH";
2407 }
2408 return "th";
2409 case LANG_TIBETAN:
2410 switch (sub)
2411 {
2412 case SUBLANG_TIBETAN_PRC:
2413 /* Most Tibetans would not like "bo_CN". But Tibet does not yet
2414 have a country code of its own. */
2415 return "bo";
2416 case SUBLANG_TIBETAN_BHUTAN: return "bo_BT";
2417 }
2418 return "bo";
2419 case LANG_TIGRINYA:
2420 switch (sub)
2421 {
2422 case SUBLANG_TIGRINYA_ETHIOPIA: return "ti_ET";
2423 case SUBLANG_TIGRINYA_ERITREA: return "ti_ER";
2424 }
2425 return "ti";
2426 case LANG_TSONGA:
2427 switch (sub)
2428 {
2429 case SUBLANG_DEFAULT: return "ts_ZA";
2430 }
2431 return "ts";
2432 case LANG_TSWANA:
2433 /* Spoken in South Africa, Botswana. */
2434 switch (sub)
2435 {
2436 case SUBLANG_TSWANA_SOUTH_AFRICA: return "tn_ZA";
2437 }
2438 return "tn";
2439 case LANG_TURKISH:
2440 switch (sub)
2441 {
2442 case SUBLANG_TURKISH_TURKEY: return "tr_TR";
2443 }
2444 return "tr";
2445 case LANG_TURKMEN:
2446 switch (sub)
2447 {
2448 case SUBLANG_TURKMEN_TURKMENISTAN: return "tk_TM";
2449 }
2450 return "tk";
2451 case LANG_UIGHUR:
2452 switch (sub)
2453 {
2454 case SUBLANG_UIGHUR_PRC: return "ug_CN";
2455 }
2456 return "ug";
2457 case LANG_UKRAINIAN:
2458 switch (sub)
2459 {
2460 case SUBLANG_UKRAINIAN_UKRAINE: return "uk_UA";
2461 }
2462 return "uk";
2463 case LANG_URDU:
2464 switch (sub)
2465 {
2466 case SUBLANG_URDU_PAKISTAN: return "ur_PK";
2467 case SUBLANG_URDU_INDIA: return "ur_IN";
2468 }
2469 return "ur";
2470 case LANG_UZBEK:
2471 switch (sub)
2472 {
2473 case 0x1f: return "uz";
2474 case SUBLANG_UZBEK_LATIN: return "uz_UZ";
2475 case 0x1e: return "uz@cyrillic";
2476 case SUBLANG_UZBEK_CYRILLIC: return "uz_UZ@cyrillic";
2477 }
2478 return "uz";
2479 case LANG_VENDA:
2480 switch (sub)
2481 {
2482 case SUBLANG_DEFAULT: return "ve_ZA";
2483 }
2484 return "ve";
2485 case LANG_VIETNAMESE:
2486 switch (sub)
2487 {
2488 case SUBLANG_VIETNAMESE_VIETNAM: return "vi_VN";
2489 }
2490 return "vi";
2491 case LANG_WELSH:
2492 switch (sub)
2493 {
2494 case SUBLANG_WELSH_UNITED_KINGDOM: return "cy_GB";
2495 }
2496 return "cy";
2497 case LANG_WOLOF:
2498 switch (sub)
2499 {
2500 case SUBLANG_WOLOF_SENEGAL: return "wo_SN";
2501 }
2502 return "wo";
2503 case LANG_XHOSA:
2504 switch (sub)
2505 {
2506 case SUBLANG_XHOSA_SOUTH_AFRICA: return "xh_ZA";
2507 }
2508 return "xh";
2509 case LANG_YAKUT:
2510 switch (sub)
2511 {
2512 case SUBLANG_YAKUT_RUSSIA: return "sah_RU";
2513 }
2514 return "sah";
2515 case LANG_YI:
2516 switch (sub)
2517 {
2518 case SUBLANG_YI_PRC: return "ii_CN";
2519 }
2520 return "ii";
2521 case LANG_YIDDISH:
2522 switch (sub)
2523 {
2524 case SUBLANG_DEFAULT: return "yi_IL";
2525 }
2526 return "yi";
2527 case LANG_YORUBA:
2528 switch (sub)
2529 {
2530 case SUBLANG_YORUBA_NIGERIA: return "yo_NG";
2531 }
2532 return "yo";
2533 case LANG_ZULU:
2534 switch (sub)
2535 {
2536 case SUBLANG_ZULU_SOUTH_AFRICA: return "zu_ZA";
2537 }
2538 return "zu";
2539 default: return "C";
2540 }
2541 }
2542 }
2543
2544 # if !defined IN_LIBINTL
2545 static
2546 # endif
2547 const char *
2548 gl_locale_name_from_win32_LCID (LCID lcid)
2549 {
2550 LANGID langid;
2551
2552 /* Strip off the sorting rules, keep only the language part. */
2553 langid = LANGIDFROMLCID (lcid);
2554
2555 return gl_locale_name_from_win32_LANGID (langid);
2556 }
2557
2558 # ifdef WINDOWS_NATIVE
2559
2560 /* Two variables to interface between get_lcid and the EnumLocales
2561 callback function below. */
2562 static LCID found_lcid;
2563 static char lname[LC_MAX * (LOCALE_NAME_MAX_LENGTH + 1) + 1];
2564
2565 /* Callback function for EnumLocales. */
2566 static BOOL CALLBACK
2567 enum_locales_fn (LPSTR locale_num_str)
2568 {
2569 char *endp;
2570 char locval[2 * LOCALE_NAME_MAX_LENGTH + 1 + 1];
2571 LCID try_lcid = strtoul (locale_num_str, &endp, 16);
2572
2573 if (GetLocaleInfo (try_lcid, LOCALE_SENGLANGUAGE,
2574 locval, LOCALE_NAME_MAX_LENGTH))
2575 {
2576 strcat (locval, "_");
2577 if (GetLocaleInfo (try_lcid, LOCALE_SENGCOUNTRY,
2578 locval + strlen (locval), LOCALE_NAME_MAX_LENGTH))
2579 {
2580 size_t locval_len = strlen (locval);
2581
2582 if (strncmp (locval, lname, locval_len) == 0
2583 && (lname[locval_len] == '.'
2584 || lname[locval_len] == '\0'))
2585 {
2586 found_lcid = try_lcid;
2587 return FALSE;
2588 }
2589 }
2590 }
2591 return TRUE;
2592 }
2593
2594 /* This lock protects the get_lcid against multiple simultaneous calls. */
2595 gl_lock_define_initialized(static, get_lcid_lock)
2596
2597 /* Return the Locale ID (LCID) number given the locale's name, a
2598 string, in LOCALE_NAME. This works by enumerating all the locales
2599 supported by the system, until we find one whose name matches
2600 LOCALE_NAME. */
2601 static LCID
2602 get_lcid (const char *locale_name)
2603 {
2604 /* A simple cache. */
2605 static LCID last_lcid;
2606 static char last_locale[1000];
2607
2608 /* Lock while looking for an LCID, to protect access to static
2609 variables: last_lcid, last_locale, found_lcid, and lname. */
2610 gl_lock_lock (get_lcid_lock);
2611 if (last_lcid > 0 && strcmp (locale_name, last_locale) == 0)
2612 {
2613 gl_lock_unlock (get_lcid_lock);
2614 return last_lcid;
2615 }
2616 strncpy (lname, locale_name, sizeof (lname) - 1);
2617 lname[sizeof (lname) - 1] = '\0';
2618 found_lcid = 0;
2619 EnumSystemLocales (enum_locales_fn, LCID_SUPPORTED);
2620 if (found_lcid > 0)
2621 {
2622 last_lcid = found_lcid;
2623 strcpy (last_locale, locale_name);
2624 }
2625 gl_lock_unlock (get_lcid_lock);
2626 return found_lcid;
2627 }
2628
2629 # endif
2630 #endif
2631
2632
2633 #if HAVE_GOOD_USELOCALE /* glibc, Mac OS X, FreeBSD >= 9.1, Cygwin >= 2.6,
2634 Solaris 11 OpenIndiana, or Solaris >= 11.4 */
2635
2636 /* Simple hash set of strings. We don't want to drag in lots of hash table
2637 code here. */
2638
2639 # define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
2640
2641 /* A hash function for NUL-terminated char* strings using
2642 the method described by Bruno Haible.
2643 See https://www.haible.de/bruno/hashfunc.html. */
2644 static size_t _GL_ATTRIBUTE_PURE
2645 string_hash (const void *x)
2646 {
2647 const char *s = (const char *) x;
2648 size_t h = 0;
2649
2650 for (; *s; s++)
2651 h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
2652
2653 return h;
2654 }
2655
2656 /* A hash table of fixed size. Multiple threads can access it read-only
2657 simultaneously, but only one thread can insert into it at the same time. */
2658
2659 /* A node in a hash bucket collision list. */
2660 struct struniq_hash_node
2661 {
2662 struct struniq_hash_node * volatile next;
2663 char contents[FLEXIBLE_ARRAY_MEMBER];
2664 };
2665
2666 # define STRUNIQ_HASH_TABLE_SIZE 257
2667 static struct struniq_hash_node * volatile struniq_hash_table[STRUNIQ_HASH_TABLE_SIZE]
2668 /* = { NULL, ..., NULL } */;
2669
2670 /* This lock protects the struniq_hash_table against multiple simultaneous
2671 insertions. */
2672 gl_lock_define_initialized(static, struniq_lock)
2673
2674 /* Store a copy of the given string in a string pool with indefinite extent.
2675 Return a pointer to this copy. */
2676 static const char *
2677 struniq (const char *string)
2678 {
2679 size_t hashcode = string_hash (string);
2680 size_t slot = hashcode % STRUNIQ_HASH_TABLE_SIZE;
2681 size_t size;
2682 struct struniq_hash_node *new_node;
2683 struct struniq_hash_node *p;
2684 for (p = struniq_hash_table[slot]; p != NULL; p = p->next)
2685 if (strcmp (p->contents, string) == 0)
2686 return p->contents;
2687 size = strlen (string) + 1;
2688 new_node =
2689 (struct struniq_hash_node *)
2690 malloc (FLEXSIZEOF (struct struniq_hash_node, contents, size));
2691 if (new_node == NULL)
2692 /* Out of memory. Return a statically allocated string. */
2693 return "C";
2694 memcpy (new_node->contents, string, size);
2695 {
2696 bool mt = gl_multithreaded ();
2697 /* Lock while inserting new_node. */
2698 if (mt) gl_lock_lock (struniq_lock);
2699 /* Check whether another thread already added the string while we were
2700 waiting on the lock. */
2701 for (p = struniq_hash_table[slot]; p != NULL; p = p->next)
2702 if (strcmp (p->contents, string) == 0)
2703 {
2704 free (new_node);
2705 new_node = p;
2706 goto done;
2707 }
2708 /* Really insert new_node into the hash table. Fill new_node entirely
2709 first, because other threads may be iterating over the linked list. */
2710 new_node->next = struniq_hash_table[slot];
2711 struniq_hash_table[slot] = new_node;
2712 done:
2713 /* Unlock after new_node is inserted. */
2714 if (mt) gl_lock_unlock (struniq_lock);
2715 }
2716 return new_node->contents;
2717 }
2718
2719 #endif
2720
2721
2722 #if LOCALENAME_ENHANCE_LOCALE_FUNCS
2723
2724 /* The 'locale_t' object does not contain the names of the locale categories.
2725 We have to associate them with the object through a hash table.
2726 The hash table is defined in localename-table.[hc]. */
2727
2728 /* Returns the name of a given locale category in a given locale_t object,
2729 allocated as a string with indefinite extent. */
2730 static const char *
2731 get_locale_t_name (int category, locale_t locale)
2732 {
2733 if (locale == LC_GLOBAL_LOCALE)
2734 {
2735 /* Query the global locale. */
2736 const char *name = setlocale_null (category);
2737 if (name != NULL)
2738 return struniq (name);
2739 else
2740 /* Should normally not happen. */
2741 return "";
2742 }
2743 else
2744 {
2745 /* Look up the names in the hash table. */
2746 size_t hashcode = locale_hash_function (locale);
2747 size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE;
2748 /* If the locale was not found in the table, return "". This can
2749 happen if the application uses the original newlocale()/duplocale()
2750 functions instead of the overridden ones. */
2751 const char *name = "";
2752 struct locale_hash_node *p;
2753 /* Lock while looking up the hash node. */
2754 gl_rwlock_rdlock (locale_lock);
2755 for (p = locale_hash_table[slot]; p != NULL; p = p->next)
2756 if (p->locale == locale)
2757 {
2758 name = p->names.category_name[category];
2759 break;
2760 }
2761 gl_rwlock_unlock (locale_lock);
2762 return name;
2763 }
2764 }
2765
2766 # if !(defined newlocale && defined duplocale && defined freelocale)
2767 # error "newlocale, duplocale, freelocale not being replaced as expected!"
2768 # endif
2769
2770 /* newlocale() override. */
2771 locale_t
2772 newlocale (int category_mask, const char *name, locale_t base)
2773 #undef newlocale
2774 {
2775 struct locale_categories_names names;
2776 struct locale_hash_node *node;
2777 locale_t result;
2778
2779 /* Make sure name has indefinite extent. */
2780 if (((LC_CTYPE_MASK | LC_NUMERIC_MASK | LC_TIME_MASK | LC_COLLATE_MASK
2781 | LC_MONETARY_MASK | LC_MESSAGES_MASK)
2782 & category_mask) != 0)
2783 name = struniq (name);
2784
2785 /* Determine the category names of the result. */
2786 if (((LC_CTYPE_MASK | LC_NUMERIC_MASK | LC_TIME_MASK | LC_COLLATE_MASK
2787 | LC_MONETARY_MASK | LC_MESSAGES_MASK)
2788 & ~category_mask) == 0)
2789 {
2790 /* Use name, ignore base. */
2791 int category;
2792
2793 name = struniq (name);
2794 for (category = 0; category < 6; category++)
2795 names.category_name[category] = name;
2796 }
2797 else
2798 {
2799 /* Use base, possibly also name. */
2800 if (base == NULL)
2801 {
2802 int category;
2803
2804 for (category = 0; category < 6; category++)
2805 {
2806 int mask;
2807
2808 switch (category)
2809 {
2810 case LC_CTYPE:
2811 mask = LC_CTYPE_MASK;
2812 break;
2813 case LC_NUMERIC:
2814 mask = LC_NUMERIC_MASK;
2815 break;
2816 case LC_TIME:
2817 mask = LC_TIME_MASK;
2818 break;
2819 case LC_COLLATE:
2820 mask = LC_COLLATE_MASK;
2821 break;
2822 case LC_MONETARY:
2823 mask = LC_MONETARY_MASK;
2824 break;
2825 case LC_MESSAGES:
2826 mask = LC_MESSAGES_MASK;
2827 break;
2828 default:
2829 abort ();
2830 }
2831 names.category_name[category] =
2832 ((mask & category_mask) != 0 ? name : "C");
2833 }
2834 }
2835 else if (base == LC_GLOBAL_LOCALE)
2836 {
2837 int category;
2838
2839 for (category = 0; category < 6; category++)
2840 {
2841 int mask;
2842
2843 switch (category)
2844 {
2845 case LC_CTYPE:
2846 mask = LC_CTYPE_MASK;
2847 break;
2848 case LC_NUMERIC:
2849 mask = LC_NUMERIC_MASK;
2850 break;
2851 case LC_TIME:
2852 mask = LC_TIME_MASK;
2853 break;
2854 case LC_COLLATE:
2855 mask = LC_COLLATE_MASK;
2856 break;
2857 case LC_MONETARY:
2858 mask = LC_MONETARY_MASK;
2859 break;
2860 case LC_MESSAGES:
2861 mask = LC_MESSAGES_MASK;
2862 break;
2863 default:
2864 abort ();
2865 }
2866 names.category_name[category] =
2867 ((mask & category_mask) != 0
2868 ? name
2869 : get_locale_t_name (category, LC_GLOBAL_LOCALE));
2870 }
2871 }
2872 else
2873 {
2874 /* Look up the names of base in the hash table. Like multiple calls
2875 of get_locale_t_name, but locking only once. */
2876 struct locale_hash_node *p;
2877 int category;
2878
2879 /* Lock while looking up the hash node. */
2880 gl_rwlock_rdlock (locale_lock);
2881 for (p = locale_hash_table[locale_hash_function (base) % LOCALE_HASH_TABLE_SIZE];
2882 p != NULL;
2883 p = p->next)
2884 if (p->locale == base)
2885 break;
2886
2887 for (category = 0; category < 6; category++)
2888 {
2889 int mask;
2890
2891 switch (category)
2892 {
2893 case LC_CTYPE:
2894 mask = LC_CTYPE_MASK;
2895 break;
2896 case LC_NUMERIC:
2897 mask = LC_NUMERIC_MASK;
2898 break;
2899 case LC_TIME:
2900 mask = LC_TIME_MASK;
2901 break;
2902 case LC_COLLATE:
2903 mask = LC_COLLATE_MASK;
2904 break;
2905 case LC_MONETARY:
2906 mask = LC_MONETARY_MASK;
2907 break;
2908 case LC_MESSAGES:
2909 mask = LC_MESSAGES_MASK;
2910 break;
2911 default:
2912 abort ();
2913 }
2914 names.category_name[category] =
2915 ((mask & category_mask) != 0
2916 ? name
2917 : (p != NULL ? p->names.category_name[category] : ""));
2918 }
2919
2920 gl_rwlock_unlock (locale_lock);
2921 }
2922 }
2923
2924 node = (struct locale_hash_node *) malloc (sizeof (struct locale_hash_node));
2925 if (node == NULL)
2926 /* errno is set to ENOMEM. */
2927 return NULL;
2928
2929 result = newlocale (category_mask, name, base);
2930 if (result == NULL)
2931 {
2932 free (node);
2933 return NULL;
2934 }
2935
2936 /* Fill the hash node. */
2937 node->locale = result;
2938 node->names = names;
2939
2940 /* Insert it in the hash table. */
2941 {
2942 size_t hashcode = locale_hash_function (result);
2943 size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE;
2944 struct locale_hash_node *p;
2945
2946 /* Lock while inserting the new node. */
2947 gl_rwlock_wrlock (locale_lock);
2948 for (p = locale_hash_table[slot]; p != NULL; p = p->next)
2949 if (p->locale == result)
2950 {
2951 /* This can happen if the application uses the original freelocale()
2952 function instead of the overridden one. */
2953 p->names = node->names;
2954 break;
2955 }
2956 if (p == NULL)
2957 {
2958 node->next = locale_hash_table[slot];
2959 locale_hash_table[slot] = node;
2960 }
2961
2962 gl_rwlock_unlock (locale_lock);
2963
2964 if (p != NULL)
2965 free (node);
2966 }
2967
2968 return result;
2969 }
2970
2971 /* duplocale() override. */
2972 locale_t
2973 duplocale (locale_t locale)
2974 #undef duplocale
2975 {
2976 struct locale_hash_node *node;
2977 locale_t result;
2978
2979 if (locale == NULL)
2980 /* Invalid argument. */
2981 abort ();
2982
2983 node = (struct locale_hash_node *) malloc (sizeof (struct locale_hash_node));
2984 if (node == NULL)
2985 /* errno is set to ENOMEM. */
2986 return NULL;
2987
2988 result = duplocale (locale);
2989 if (result == NULL)
2990 {
2991 free (node);
2992 return NULL;
2993 }
2994
2995 /* Fill the hash node. */
2996 node->locale = result;
2997 if (locale == LC_GLOBAL_LOCALE)
2998 {
2999 int category;
3000
3001 for (category = 0; category < 6; category++)
3002 node->names.category_name[category] =
3003 get_locale_t_name (category, LC_GLOBAL_LOCALE);
3004
3005 /* Lock before inserting the new node. */
3006 gl_rwlock_wrlock (locale_lock);
3007 }
3008 else
3009 {
3010 struct locale_hash_node *p;
3011
3012 /* Lock once, for the lookup and the insertion. */
3013 gl_rwlock_wrlock (locale_lock);
3014
3015 for (p = locale_hash_table[locale_hash_function (locale) % LOCALE_HASH_TABLE_SIZE];
3016 p != NULL;
3017 p = p->next)
3018 if (p->locale == locale)
3019 break;
3020 if (p != NULL)
3021 node->names = p->names;
3022 else
3023 {
3024 /* This can happen if the application uses the original
3025 newlocale()/duplocale() functions instead of the overridden
3026 ones. */
3027 int category;
3028
3029 for (category = 0; category < 6; category++)
3030 node->names.category_name[category] = "";
3031 }
3032 }
3033
3034 /* Insert it in the hash table. */
3035 {
3036 size_t hashcode = locale_hash_function (result);
3037 size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE;
3038 struct locale_hash_node *p;
3039
3040 for (p = locale_hash_table[slot]; p != NULL; p = p->next)
3041 if (p->locale == result)
3042 {
3043 /* This can happen if the application uses the original freelocale()
3044 function instead of the overridden one. */
3045 p->names = node->names;
3046 break;
3047 }
3048 if (p == NULL)
3049 {
3050 node->next = locale_hash_table[slot];
3051 locale_hash_table[slot] = node;
3052 }
3053
3054 gl_rwlock_unlock (locale_lock);
3055
3056 if (p != NULL)
3057 free (node);
3058 }
3059
3060 return result;
3061 }
3062
3063 /* freelocale() override. */
3064 void
3065 freelocale (locale_t locale)
3066 #undef freelocale
3067 {
3068 if (locale == NULL || locale == LC_GLOBAL_LOCALE)
3069 /* Invalid argument. */
3070 abort ();
3071
3072 {
3073 size_t hashcode = locale_hash_function (locale);
3074 size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE;
3075 struct locale_hash_node *found;
3076 struct locale_hash_node **p;
3077
3078 found = NULL;
3079 /* Lock while removing the hash node. */
3080 gl_rwlock_wrlock (locale_lock);
3081 for (p = &locale_hash_table[slot]; *p != NULL; p = &(*p)->next)
3082 if ((*p)->locale == locale)
3083 {
3084 found = *p;
3085 *p = (*p)->next;
3086 break;
3087 }
3088 gl_rwlock_unlock (locale_lock);
3089 free (found);
3090 }
3091
3092 freelocale (locale);
3093 }
3094
3095 #endif
3096
3097
3098 #if defined IN_LIBINTL || HAVE_GOOD_USELOCALE
3099
3100 /* Like gl_locale_name_thread, except that the result is not in storage of
3101 indefinite extent. */
3102 # if !defined IN_LIBINTL
3103 static
3104 # endif
3105 const char *
3106 gl_locale_name_thread_unsafe (int category, const char *categoryname _GL_UNUSED)
3107 {
3108 # if HAVE_GOOD_USELOCALE
3109 {
3110 locale_t thread_locale = uselocale (NULL);
3111 if (thread_locale != LC_GLOBAL_LOCALE)
3112 {
3113 # if __GLIBC__ >= 2 && !defined __UCLIBC__
3114 /* Work around an incorrect definition of the _NL_LOCALE_NAME macro in
3115 glibc < 2.12.
3116 See <https://sourceware.org/bugzilla/show_bug.cgi?id=10968>. */
3117 const char *name =
3118 nl_langinfo (_NL_ITEM ((category), _NL_ITEM_INDEX (-1)));
3119 if (name[0] == '\0')
3120 /* Fallback code for glibc < 2.4, which did not implement
3121 nl_langinfo (_NL_LOCALE_NAME (category)). */
3122 name = thread_locale->__names[category];
3123 return name;
3124 # elif defined __linux__ && HAVE_LANGINFO_H && defined NL_LOCALE_NAME
3125 /* musl libc */
3126 return nl_langinfo_l (NL_LOCALE_NAME (category), thread_locale);
3127 # elif (defined __FreeBSD__ || defined __DragonFly__) || (defined __APPLE__ && defined __MACH__)
3128 /* FreeBSD, Mac OS X */
3129 int mask;
3130
3131 switch (category)
3132 {
3133 case LC_CTYPE:
3134 mask = LC_CTYPE_MASK;
3135 break;
3136 case LC_NUMERIC:
3137 mask = LC_NUMERIC_MASK;
3138 break;
3139 case LC_TIME:
3140 mask = LC_TIME_MASK;
3141 break;
3142 case LC_COLLATE:
3143 mask = LC_COLLATE_MASK;
3144 break;
3145 case LC_MONETARY:
3146 mask = LC_MONETARY_MASK;
3147 break;
3148 case LC_MESSAGES:
3149 mask = LC_MESSAGES_MASK;
3150 break;
3151 default: /* We shouldn't get here. */
3152 return "";
3153 }
3154 return querylocale (mask, thread_locale);
3155 # elif defined __sun
3156 # if HAVE_GETLOCALENAME_L
3157 /* Solaris >= 12. */
3158 return getlocalename_l (category, thread_locale);
3159 # elif HAVE_SOLARIS114_LOCALES
3160 /* Solaris >= 11.4. */
3161 void *lcp = (*thread_locale)->core.data->lcp;
3162 if (lcp != NULL)
3163 switch (category)
3164 {
3165 case LC_CTYPE:
3166 case LC_NUMERIC:
3167 case LC_TIME:
3168 case LC_COLLATE:
3169 case LC_MONETARY:
3170 case LC_MESSAGES:
3171 return ((const char * const *) lcp)[category];
3172 default: /* We shouldn't get here. */
3173 return "";
3174 }
3175 # elif HAVE_NAMELESS_LOCALES
3176 return get_locale_t_name (category, thread_locale);
3177 # else
3178 /* Solaris 11 OpenIndiana.
3179 For the internal structure of locale objects, see
3180 https://github.com/OpenIndiana/illumos-gate/blob/master/usr/src/lib/libc/port/locale/localeimpl.h */
3181 switch (category)
3182 {
3183 case LC_CTYPE:
3184 case LC_NUMERIC:
3185 case LC_TIME:
3186 case LC_COLLATE:
3187 case LC_MONETARY:
3188 case LC_MESSAGES:
3189 return ((const char * const *) thread_locale)[category];
3190 default: /* We shouldn't get here. */
3191 return "";
3192 }
3193 # endif
3194 # elif defined _AIX && HAVE_NAMELESS_LOCALES
3195 return get_locale_t_name (category, thread_locale);
3196 # elif defined __CYGWIN__
3197 /* Cygwin < 2.6 lacks uselocale and thread-local locales altogether.
3198 Cygwin <= 2.6.1 lacks NL_LOCALE_NAME, requiring peeking inside
3199 an opaque struct. */
3200 # ifdef NL_LOCALE_NAME
3201 return nl_langinfo_l (NL_LOCALE_NAME (category), thread_locale);
3202 # else
3203 /* FIXME: Remove when we can assume new-enough Cygwin. */
3204 struct __locale_t {
3205 char categories[7][32];
3206 };
3207 return ((struct __locale_t *) thread_locale)->categories[category];
3208 # endif
3209 # elif defined __ANDROID__
3210 return MB_CUR_MAX == 4 ? "C.UTF-8" : "C";
3211 # endif
3212 }
3213 }
3214 # endif
3215 return NULL;
3216 }
3217
3218 #endif
3219
3220 const char *
3221 gl_locale_name_thread (int category, const char *categoryname _GL_UNUSED)
3222 {
3223 #if HAVE_GOOD_USELOCALE
3224 const char *name = gl_locale_name_thread_unsafe (category, categoryname);
3225 if (name != NULL)
3226 return struniq (name);
3227 #endif
3228 /* On WINDOWS_NATIVE, don't use GetThreadLocale() here, because when
3229 SetThreadLocale has not been called - which is a very frequent case -
3230 the value of GetThreadLocale() ignores past calls to 'setlocale'. */
3231 return NULL;
3232 }
3233
3234 /* XPG3 defines the result of 'setlocale (category, NULL)' as:
3235 "Directs 'setlocale()' to query 'category' and return the current
3236 setting of 'local'."
3237 However it does not specify the exact format. Neither do SUSV2 and
3238 ISO C 99. So we can use this feature only on selected systems (e.g.
3239 those using GNU C Library). */
3240 #if defined _LIBC || ((defined __GLIBC__ && __GLIBC__ >= 2) && !defined __UCLIBC__)
3241 # define HAVE_LOCALE_NULL
3242 #endif
3243
3244 const char *
3245 gl_locale_name_posix (int category, const char *categoryname _GL_UNUSED)
3246 {
3247 #if defined WINDOWS_NATIVE
3248 if (LC_MIN <= category && category <= LC_MAX)
3249 {
3250 const char *locname =
3251 /* setlocale_null (category) is identical to setlocale (category, NULL)
3252 on this platform. */
3253 setlocale (category, NULL);
3254
3255 /* Convert locale name to LCID. We don't want to use
3256 LocaleNameToLCID because (a) it is only available since Vista,
3257 and (b) it doesn't accept locale names returned by 'setlocale'. */
3258 LCID lcid = get_lcid (locname);
3259
3260 if (lcid > 0)
3261 return gl_locale_name_from_win32_LCID (lcid);
3262 }
3263 #endif
3264 {
3265 const char *locname;
3266
3267 /* Use the POSIX methods of looking to 'LC_ALL', 'LC_xxx', and 'LANG'.
3268 On some systems this can be done by the 'setlocale' function itself. */
3269 #if defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
3270 locname = setlocale_null (category);
3271 #else
3272 /* On other systems we ignore what setlocale reports and instead look at the
3273 environment variables directly. This is necessary
3274 1. on systems which have a facility for customizing the default locale
3275 (Mac OS X, native Windows, Cygwin) and where the system's setlocale()
3276 function ignores this default locale (Mac OS X, Cygwin), in two cases:
3277 a. when the user missed to use the setlocale() override from libintl
3278 (for example by not including <libintl.h>),
3279 b. when setlocale supports only the "C" locale, such as on Cygwin
3280 1.5.x. In this case even the override from libintl cannot help.
3281 2. on all systems where setlocale supports only the "C" locale. */
3282 /* Strictly speaking, it is a POSIX violation to look at the environment
3283 variables regardless whether setlocale has been called or not. POSIX
3284 says:
3285 "For C-language programs, the POSIX locale shall be the
3286 default locale when the setlocale() function is not called."
3287 But we assume that all programs that use internationalized APIs call
3288 setlocale (LC_ALL, ""). */
3289 locname = gl_locale_name_environ (category, categoryname);
3290 #endif
3291 /* Convert the locale name from the format returned by setlocale() or found
3292 in the environment variables to the XPG syntax. */
3293 #if defined WINDOWS_NATIVE
3294 if (locname != NULL)
3295 {
3296 /* Convert locale name to LCID. We don't want to use
3297 LocaleNameToLCID because (a) it is only available since Vista,
3298 and (b) it doesn't accept locale names returned by 'setlocale'. */
3299 LCID lcid = get_lcid (locname);
3300
3301 if (lcid > 0)
3302 return gl_locale_name_from_win32_LCID (lcid);
3303 }
3304 #endif
3305 return locname;
3306 }
3307 }
3308
3309 const char *
3310 gl_locale_name_environ (int category _GL_UNUSED, const char *categoryname)
3311 {
3312 const char *retval;
3313
3314 /* Setting of LC_ALL overrides all other. */
3315 retval = getenv ("LC_ALL");
3316 if (retval != NULL && retval[0] != '\0')
3317 return retval;
3318 /* Next comes the name of the desired category. */
3319 retval = getenv (categoryname);
3320 if (retval != NULL && retval[0] != '\0')
3321 return retval;
3322 /* Last possibility is the LANG environment variable. */
3323 retval = getenv ("LANG");
3324 if (retval != NULL && retval[0] != '\0')
3325 {
3326 #if HAVE_CFPREFERENCESCOPYAPPVALUE
3327 /* Mac OS X 10.2 or newer.
3328 Ignore invalid LANG value set by the Terminal application. */
3329 if (strcmp (retval, "UTF-8") != 0)
3330 #endif
3331 #if defined __CYGWIN__
3332 /* Cygwin.
3333 Ignore dummy LANG value set by ~/.profile. */
3334 if (strcmp (retval, "C.UTF-8") != 0)
3335 #endif
3336 return retval;
3337 }
3338
3339 return NULL;
3340 }
3341
3342 const char *
3343 gl_locale_name_default (void)
3344 {
3345 /* POSIX:2001 says:
3346 "All implementations shall define a locale as the default locale, to be
3347 invoked when no environment variables are set, or set to the empty
3348 string. This default locale can be the POSIX locale or any other
3349 implementation-defined locale. Some implementations may provide
3350 facilities for local installation administrators to set the default
3351 locale, customizing it for each location. POSIX:2001 does not require
3352 such a facility.
3353
3354 The systems with such a facility are Mac OS X and Windows: They provide a
3355 GUI that allows the user to choose a locale.
3356 - On Mac OS X, by default, none of LC_* or LANG are set. Starting with
3357 Mac OS X 10.4 or 10.5, LANG is set for processes launched by the
3358 'Terminal' application (but sometimes to an incorrect value "UTF-8").
3359 When no environment variable is set, setlocale (LC_ALL, "") uses the
3360 "C" locale.
3361 - On native Windows, by default, none of LC_* or LANG are set.
3362 When no environment variable is set, setlocale (LC_ALL, "") uses the
3363 locale chosen by the user.
3364 - On Cygwin 1.5.x, by default, none of LC_* or LANG are set.
3365 When no environment variable is set, setlocale (LC_ALL, "") uses the
3366 "C" locale.
3367 - On Cygwin 1.7, by default, LANG is set to "C.UTF-8" when the default
3368 ~/.profile is executed.
3369 When no environment variable is set, setlocale (LC_ALL, "") uses the
3370 "C.UTF-8" locale, which operates in the same way as the "C" locale.
3371 */
3372
3373 #if !(HAVE_CFPREFERENCESCOPYAPPVALUE || defined WINDOWS_NATIVE || defined __CYGWIN__)
3374
3375 /* The system does not have a way of setting the locale, other than the
3376 POSIX specified environment variables. We use C as default locale. */
3377 return "C";
3378
3379 #else
3380
3381 /* Return an XPG style locale name language[_territory][@modifier].
3382 Don't even bother determining the codeset; it's not useful in this
3383 context, because message catalogs are not specific to a single
3384 codeset. */
3385
3386 # if HAVE_CFPREFERENCESCOPYAPPVALUE
3387 /* Mac OS X 10.4 or newer */
3388 /* Don't use the API introduced in Mac OS X 10.5, CFLocaleCopyCurrent,
3389 because in macOS 10.13.4 it has the following behaviour:
3390 When two or more languages are specified in the
3391 "System Preferences > Language & Region > Preferred Languages" panel,
3392 it returns en_CC where CC is the territory (even when English is not among
3393 the preferred languages!). What we want instead is what
3394 CFLocaleCopyCurrent returned in earlier macOS releases and what
3395 CFPreferencesCopyAppValue still returns, namely ll_CC where ll is the
3396 first among the preferred languages and CC is the territory. */
3397 {
3398 /* Cache the locale name, since CoreFoundation calls are expensive. */
3399 static const char *cached_localename;
3400
3401 if (cached_localename == NULL)
3402 {
3403 char namebuf[256];
3404 CFTypeRef value =
3405 CFPreferencesCopyAppValue (CFSTR ("AppleLocale"),
3406 kCFPreferencesCurrentApplication);
3407 if (value != NULL && CFGetTypeID (value) == CFStringGetTypeID ())
3408 {
3409 CFStringRef name = (CFStringRef)value;
3410
3411 if (CFStringGetCString (name, namebuf, sizeof (namebuf),
3412 kCFStringEncodingASCII))
3413 {
3414 gl_locale_name_canonicalize (namebuf);
3415 cached_localename = strdup (namebuf);
3416 }
3417 }
3418 if (cached_localename == NULL)
3419 cached_localename = "C";
3420 }
3421 return cached_localename;
3422 }
3423
3424 # endif
3425
3426 # if defined WINDOWS_NATIVE || defined __CYGWIN__ /* Native Windows or Cygwin */
3427 {
3428 LCID lcid;
3429
3430 /* Use native Windows API locale ID. */
3431 lcid = GetThreadLocale ();
3432
3433 return gl_locale_name_from_win32_LCID (lcid);
3434 }
3435 # endif
3436 #endif
3437 }
3438
3439 /* Determine the current locale's name, and canonicalize it into XPG syntax
3440 language[_territory][.codeset][@modifier]
3441 The codeset part in the result is not reliable; the locale_charset()
3442 should be used for codeset information instead.
3443 The result must not be freed; it is statically allocated. */
3444
3445 const char *
3446 gl_locale_name (int category, const char *categoryname)
3447 {
3448 const char *retval;
3449
3450 retval = gl_locale_name_thread (category, categoryname);
3451 if (retval != NULL)
3452 return retval;
3453
3454 retval = gl_locale_name_posix (category, categoryname);
3455 if (retval != NULL)
3456 return retval;
3457
3458 return gl_locale_name_default ();
3459 }