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