source: trunk/src/sed/gnulib-tests/localename.c@ 3669

Last change on this file since 3669 was 3611, checked in by bird, 10 months ago

vendor/sed/current: GNU sed 4.9 (sed-4.9.tar.xz sha256:6e226b732e1cd739464ad6862bd1a1aba42d7982922da7a53519631d24975181)

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