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