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