Add minimalistic protected-headers support
[gpgol.git] / src / w32-gettext.cpp
1 /* w32-gettext.h - A simple gettext implementation for Windows targets.
2    Copyright (C) 1995,1996,1997,1999,2005 Free Software Foundation, Inc.
3    Copyright (C) 2005, 2007 g10 Code GmbH
4
5    This file is part of libgpg-error.
6
7    libgpg-error is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public License
9    as published by the Free Software Foundation; either version 2.1 of
10    the License, or (at your option) any later version.
11
12    libgpg-error is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with libgpg-error; if not, write to the Free
19    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <ctype.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <stdint.h>
34
35 #include "w32-gettext.h"
36 #include "common_indep.h"
37 #include "xmalloc.h"
38
39 \f
40 /* localname.c from gettext.  */
41
42 /* Edit: Added a "static" to _nl_locale_name.  Note that the category
43    argument is ignored on w32.  */
44
45 /* Determine the current selected locale.
46    Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
47
48    This program is free software; you can redistribute it and/or modify it
49    under the terms of the GNU Library General Public License as published
50    by the Free Software Foundation; either version 2, or (at your option)
51    any later version.
52
53    This program is distributed in the hope that it will be useful,
54    but WITHOUT ANY WARRANTY; without even the implied warranty of
55    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
56    Library General Public License for more details.
57
58    You should have received a copy of the GNU Library General Public
59    License along with this program; if not, write to the Free Software
60    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
61    USA.  */
62
63 /* Written by Ulrich Drepper <drepper@gnu.org>, 1995.  */
64 /* Win32 code written by Tor Lillqvist <tml@iki.fi>.  */
65
66 #ifdef HAVE_CONFIG_H
67 # include <config.h>
68 #endif
69
70 #include <stdlib.h>
71 #include <locale.h>
72
73 #include <oomhelp.h>
74
75 #ifdef HAVE_W32_SYSTEM
76 # include <windows.h>
77 /* List of language codes, sorted by value:
78    0x01 LANG_ARABIC
79    0x02 LANG_BULGARIAN
80    0x03 LANG_CATALAN
81    0x04 LANG_CHINESE
82    0x05 LANG_CZECH
83    0x06 LANG_DANISH
84    0x07 LANG_GERMAN
85    0x08 LANG_GREEK
86    0x09 LANG_ENGLISH
87    0x0a LANG_SPANISH
88    0x0b LANG_FINNISH
89    0x0c LANG_FRENCH
90    0x0d LANG_HEBREW
91    0x0e LANG_HUNGARIAN
92    0x0f LANG_ICELANDIC
93    0x10 LANG_ITALIAN
94    0x11 LANG_JAPANESE
95    0x12 LANG_KOREAN
96    0x13 LANG_DUTCH
97    0x14 LANG_NORWEGIAN
98    0x15 LANG_POLISH
99    0x16 LANG_PORTUGUESE
100    0x17 LANG_RHAETO_ROMANCE
101    0x18 LANG_ROMANIAN
102    0x19 LANG_RUSSIAN
103    0x1a LANG_CROATIAN == LANG_SERBIAN
104    0x1b LANG_SLOVAK
105    0x1c LANG_ALBANIAN
106    0x1d LANG_SWEDISH
107    0x1e LANG_THAI
108    0x1f LANG_TURKISH
109    0x20 LANG_URDU
110    0x21 LANG_INDONESIAN
111    0x22 LANG_UKRAINIAN
112    0x23 LANG_BELARUSIAN
113    0x24 LANG_SLOVENIAN
114    0x25 LANG_ESTONIAN
115    0x26 LANG_LATVIAN
116    0x27 LANG_LITHUANIAN
117    0x28 LANG_TAJIK
118    0x29 LANG_FARSI
119    0x2a LANG_VIETNAMESE
120    0x2b LANG_ARMENIAN
121    0x2c LANG_AZERI
122    0x2d LANG_BASQUE
123    0x2e LANG_SORBIAN
124    0x2f LANG_MACEDONIAN
125    0x30 LANG_SUTU
126    0x31 LANG_TSONGA
127    0x32 LANG_TSWANA
128    0x33 LANG_VENDA
129    0x34 LANG_XHOSA
130    0x35 LANG_ZULU
131    0x36 LANG_AFRIKAANS
132    0x37 LANG_GEORGIAN
133    0x38 LANG_FAEROESE
134    0x39 LANG_HINDI
135    0x3a LANG_MALTESE
136    0x3b LANG_SAAMI
137    0x3c LANG_GAELIC
138    0x3d LANG_YIDDISH
139    0x3e LANG_MALAY
140    0x3f LANG_KAZAK
141    0x40 LANG_KYRGYZ
142    0x41 LANG_SWAHILI
143    0x42 LANG_TURKMEN
144    0x43 LANG_UZBEK
145    0x44 LANG_TATAR
146    0x45 LANG_BENGALI
147    0x46 LANG_PUNJABI
148    0x47 LANG_GUJARATI
149    0x48 LANG_ORIYA
150    0x49 LANG_TAMIL
151    0x4a LANG_TELUGU
152    0x4b LANG_KANNADA
153    0x4c LANG_MALAYALAM
154    0x4d LANG_ASSAMESE
155    0x4e LANG_MARATHI
156    0x4f LANG_SANSKRIT
157    0x50 LANG_MONGOLIAN
158    0x51 LANG_TIBETAN
159    0x52 LANG_WELSH
160    0x53 LANG_CAMBODIAN
161    0x54 LANG_LAO
162    0x55 LANG_BURMESE
163    0x56 LANG_GALICIAN
164    0x57 LANG_KONKANI
165    0x58 LANG_MANIPURI
166    0x59 LANG_SINDHI
167    0x5a LANG_SYRIAC
168    0x5b LANG_SINHALESE
169    0x5c LANG_CHEROKEE
170    0x5d LANG_INUKTITUT
171    0x5e LANG_AMHARIC
172    0x5f LANG_TAMAZIGHT
173    0x60 LANG_KASHMIRI
174    0x61 LANG_NEPALI
175    0x62 LANG_FRISIAN
176    0x63 LANG_PASHTO
177    0x64 LANG_TAGALOG
178    0x65 LANG_DIVEHI
179    0x66 LANG_EDO
180    0x67 LANG_FULFULDE
181    0x68 LANG_HAUSA
182    0x69 LANG_IBIBIO
183    0x6a LANG_YORUBA
184    0x70 LANG_IGBO
185    0x71 LANG_KANURI
186    0x72 LANG_OROMO
187    0x73 LANG_TIGRINYA
188    0x74 LANG_GUARANI
189    0x75 LANG_HAWAIIAN
190    0x76 LANG_LATIN
191    0x77 LANG_SOMALI
192    0x78 LANG_YI
193    0x79 LANG_PAPIAMENTU
194 */
195 /* Mingw headers don't have latest language and sublanguage codes.  */
196 # ifndef LANG_AFRIKAANS
197 # define LANG_AFRIKAANS 0x36
198 # endif
199 # ifndef LANG_ALBANIAN
200 # define LANG_ALBANIAN 0x1c
201 # endif
202 # ifndef LANG_AMHARIC
203 # define LANG_AMHARIC 0x5e
204 # endif
205 # ifndef LANG_ARABIC
206 # define LANG_ARABIC 0x01
207 # endif
208 # ifndef LANG_ARMENIAN
209 # define LANG_ARMENIAN 0x2b
210 # endif
211 # ifndef LANG_ASSAMESE
212 # define LANG_ASSAMESE 0x4d
213 # endif
214 # ifndef LANG_AZERI
215 # define LANG_AZERI 0x2c
216 # endif
217 # ifndef LANG_BASQUE
218 # define LANG_BASQUE 0x2d
219 # endif
220 # ifndef LANG_BELARUSIAN
221 # define LANG_BELARUSIAN 0x23
222 # endif
223 # ifndef LANG_BENGALI
224 # define LANG_BENGALI 0x45
225 # endif
226 # ifndef LANG_BURMESE
227 # define LANG_BURMESE 0x55
228 # endif
229 # ifndef LANG_CAMBODIAN
230 # define LANG_CAMBODIAN 0x53
231 # endif
232 # ifndef LANG_CATALAN
233 # define LANG_CATALAN 0x03
234 # endif
235 # ifndef LANG_CHEROKEE
236 # define LANG_CHEROKEE 0x5c
237 # endif
238 # ifndef LANG_DIVEHI
239 # define LANG_DIVEHI 0x65
240 # endif
241 # ifndef LANG_EDO
242 # define LANG_EDO 0x66
243 # endif
244 # ifndef LANG_ESTONIAN
245 # define LANG_ESTONIAN 0x25
246 # endif
247 # ifndef LANG_FAEROESE
248 # define LANG_FAEROESE 0x38
249 # endif
250 # ifndef LANG_FARSI
251 # define LANG_FARSI 0x29
252 # endif
253 # ifndef LANG_FRISIAN
254 # define LANG_FRISIAN 0x62
255 # endif
256 # ifndef LANG_FULFULDE
257 # define LANG_FULFULDE 0x67
258 # endif
259 # ifndef LANG_GAELIC
260 # define LANG_GAELIC 0x3c
261 # endif
262 # ifndef LANG_GALICIAN
263 # define LANG_GALICIAN 0x56
264 # endif
265 # ifndef LANG_GEORGIAN
266 # define LANG_GEORGIAN 0x37
267 # endif
268 # ifndef LANG_GUARANI
269 # define LANG_GUARANI 0x74
270 # endif
271 # ifndef LANG_GUJARATI
272 # define LANG_GUJARATI 0x47
273 # endif
274 # ifndef LANG_HAUSA
275 # define LANG_HAUSA 0x68
276 # endif
277 # ifndef LANG_HAWAIIAN
278 # define LANG_HAWAIIAN 0x75
279 # endif
280 # ifndef LANG_HEBREW
281 # define LANG_HEBREW 0x0d
282 # endif
283 # ifndef LANG_HINDI
284 # define LANG_HINDI 0x39
285 # endif
286 # ifndef LANG_IBIBIO
287 # define LANG_IBIBIO 0x69
288 # endif
289 # ifndef LANG_IGBO
290 # define LANG_IGBO 0x70
291 # endif
292 # ifndef LANG_INDONESIAN
293 # define LANG_INDONESIAN 0x21
294 # endif
295 # ifndef LANG_INUKTITUT
296 # define LANG_INUKTITUT 0x5d
297 # endif
298 # ifndef LANG_KANNADA
299 # define LANG_KANNADA 0x4b
300 # endif
301 # ifndef LANG_KANURI
302 # define LANG_KANURI 0x71
303 # endif
304 # ifndef LANG_KASHMIRI
305 # define LANG_KASHMIRI 0x60
306 # endif
307 # ifndef LANG_KAZAK
308 # define LANG_KAZAK 0x3f
309 # endif
310 # ifndef LANG_KONKANI
311 # define LANG_KONKANI 0x57
312 # endif
313 # ifndef LANG_KYRGYZ
314 # define LANG_KYRGYZ 0x40
315 # endif
316 # ifndef LANG_LAO
317 # define LANG_LAO 0x54
318 # endif
319 # ifndef LANG_LATIN
320 # define LANG_LATIN 0x76
321 # endif
322 # ifndef LANG_LATVIAN
323 # define LANG_LATVIAN 0x26
324 # endif
325 # ifndef LANG_LITHUANIAN
326 # define LANG_LITHUANIAN 0x27
327 # endif
328 # ifndef LANG_MACEDONIAN
329 # define LANG_MACEDONIAN 0x2f
330 # endif
331 # ifndef LANG_MALAY
332 # define LANG_MALAY 0x3e
333 # endif
334 # ifndef LANG_MALAYALAM
335 # define LANG_MALAYALAM 0x4c
336 # endif
337 # ifndef LANG_MALTESE
338 # define LANG_MALTESE 0x3a
339 # endif
340 # ifndef LANG_MANIPURI
341 # define LANG_MANIPURI 0x58
342 # endif
343 # ifndef LANG_MARATHI
344 # define LANG_MARATHI 0x4e
345 # endif
346 # ifndef LANG_MONGOLIAN
347 # define LANG_MONGOLIAN 0x50
348 # endif
349 # ifndef LANG_NEPALI
350 # define LANG_NEPALI 0x61
351 # endif
352 # ifndef LANG_ORIYA
353 # define LANG_ORIYA 0x48
354 # endif
355 # ifndef LANG_OROMO
356 # define LANG_OROMO 0x72
357 # endif
358 # ifndef LANG_PAPIAMENTU
359 # define LANG_PAPIAMENTU 0x79
360 # endif
361 # ifndef LANG_PASHTO
362 # define LANG_PASHTO 0x63
363 # endif
364 # ifndef LANG_PUNJABI
365 # define LANG_PUNJABI 0x46
366 # endif
367 # ifndef LANG_RHAETO_ROMANCE
368 # define LANG_RHAETO_ROMANCE 0x17
369 # endif
370 # ifndef LANG_SAAMI
371 # define LANG_SAAMI 0x3b
372 # endif
373 # ifndef LANG_SANSKRIT
374 # define LANG_SANSKRIT 0x4f
375 # endif
376 # ifndef LANG_SERBIAN
377 # define LANG_SERBIAN 0x1a
378 # endif
379 # ifndef LANG_SINDHI
380 # define LANG_SINDHI 0x59
381 # endif
382 # ifndef LANG_SINHALESE
383 # define LANG_SINHALESE 0x5b
384 # endif
385 # ifndef LANG_SLOVAK
386 # define LANG_SLOVAK 0x1b
387 # endif
388 # ifndef LANG_SOMALI
389 # define LANG_SOMALI 0x77
390 # endif
391 # ifndef LANG_SORBIAN
392 # define LANG_SORBIAN 0x2e
393 # endif
394 # ifndef LANG_SUTU
395 # define LANG_SUTU 0x30
396 # endif
397 # ifndef LANG_SWAHILI
398 # define LANG_SWAHILI 0x41
399 # endif
400 # ifndef LANG_SYRIAC
401 # define LANG_SYRIAC 0x5a
402 # endif
403 # ifndef LANG_TAGALOG
404 # define LANG_TAGALOG 0x64
405 # endif
406 # ifndef LANG_TAJIK
407 # define LANG_TAJIK 0x28
408 # endif
409 # ifndef LANG_TAMAZIGHT
410 # define LANG_TAMAZIGHT 0x5f
411 # endif
412 # ifndef LANG_TAMIL
413 # define LANG_TAMIL 0x49
414 # endif
415 # ifndef LANG_TATAR
416 # define LANG_TATAR 0x44
417 # endif
418 # ifndef LANG_TELUGU
419 # define LANG_TELUGU 0x4a
420 # endif
421 # ifndef LANG_THAI
422 # define LANG_THAI 0x1e
423 # endif
424 # ifndef LANG_TIBETAN
425 # define LANG_TIBETAN 0x51
426 # endif
427 # ifndef LANG_TIGRINYA
428 # define LANG_TIGRINYA 0x73
429 # endif
430 # ifndef LANG_TSONGA
431 # define LANG_TSONGA 0x31
432 # endif
433 # ifndef LANG_TSWANA
434 # define LANG_TSWANA 0x32
435 # endif
436 # ifndef LANG_TURKMEN
437 # define LANG_TURKMEN 0x42
438 # endif
439 # ifndef LANG_UKRAINIAN
440 # define LANG_UKRAINIAN 0x22
441 # endif
442 # ifndef LANG_URDU
443 # define LANG_URDU 0x20
444 # endif
445 # ifndef LANG_UZBEK
446 # define LANG_UZBEK 0x43
447 # endif
448 # ifndef LANG_VENDA
449 # define LANG_VENDA 0x33
450 # endif
451 # ifndef LANG_VIETNAMESE
452 # define LANG_VIETNAMESE 0x2a
453 # endif
454 # ifndef LANG_WELSH
455 # define LANG_WELSH 0x52
456 # endif
457 # ifndef LANG_XHOSA
458 # define LANG_XHOSA 0x34
459 # endif
460 # ifndef LANG_YI
461 # define LANG_YI 0x78
462 # endif
463 # ifndef LANG_YIDDISH
464 # define LANG_YIDDISH 0x3d
465 # endif
466 # ifndef LANG_YORUBA
467 # define LANG_YORUBA 0x6a
468 # endif
469 # ifndef LANG_ZULU
470 # define LANG_ZULU 0x35
471 # endif
472 # ifndef SUBLANG_ARABIC_SAUDI_ARABIA
473 # define SUBLANG_ARABIC_SAUDI_ARABIA 0x01
474 # endif
475 # ifndef SUBLANG_ARABIC_IRAQ
476 # define SUBLANG_ARABIC_IRAQ 0x02
477 # endif
478 # ifndef SUBLANG_ARABIC_EGYPT
479 # define SUBLANG_ARABIC_EGYPT 0x03
480 # endif
481 # ifndef SUBLANG_ARABIC_LIBYA
482 # define SUBLANG_ARABIC_LIBYA 0x04
483 # endif
484 # ifndef SUBLANG_ARABIC_ALGERIA
485 # define SUBLANG_ARABIC_ALGERIA 0x05
486 # endif
487 # ifndef SUBLANG_ARABIC_MOROCCO
488 # define SUBLANG_ARABIC_MOROCCO 0x06
489 # endif
490 # ifndef SUBLANG_ARABIC_TUNISIA
491 # define SUBLANG_ARABIC_TUNISIA 0x07
492 # endif
493 # ifndef SUBLANG_ARABIC_OMAN
494 # define SUBLANG_ARABIC_OMAN 0x08
495 # endif
496 # ifndef SUBLANG_ARABIC_YEMEN
497 # define SUBLANG_ARABIC_YEMEN 0x09
498 # endif
499 # ifndef SUBLANG_ARABIC_SYRIA
500 # define SUBLANG_ARABIC_SYRIA 0x0a
501 # endif
502 # ifndef SUBLANG_ARABIC_JORDAN
503 # define SUBLANG_ARABIC_JORDAN 0x0b
504 # endif
505 # ifndef SUBLANG_ARABIC_LEBANON
506 # define SUBLANG_ARABIC_LEBANON 0x0c
507 # endif
508 # ifndef SUBLANG_ARABIC_KUWAIT
509 # define SUBLANG_ARABIC_KUWAIT 0x0d
510 # endif
511 # ifndef SUBLANG_ARABIC_UAE
512 # define SUBLANG_ARABIC_UAE 0x0e
513 # endif
514 # ifndef SUBLANG_ARABIC_BAHRAIN
515 # define SUBLANG_ARABIC_BAHRAIN 0x0f
516 # endif
517 # ifndef SUBLANG_ARABIC_QATAR
518 # define SUBLANG_ARABIC_QATAR 0x10
519 # endif
520 # ifndef SUBLANG_AZERI_LATIN
521 # define SUBLANG_AZERI_LATIN 0x01
522 # endif
523 # ifndef SUBLANG_AZERI_CYRILLIC
524 # define SUBLANG_AZERI_CYRILLIC 0x02
525 # endif
526 # ifndef SUBLANG_BENGALI_INDIA
527 # define SUBLANG_BENGALI_INDIA 0x01
528 # endif
529 # ifndef SUBLANG_BENGALI_BANGLADESH
530 # define SUBLANG_BENGALI_BANGLADESH 0x02
531 # endif
532 # ifndef SUBLANG_CHINESE_MACAU
533 # define SUBLANG_CHINESE_MACAU 0x05
534 # endif
535 # ifndef SUBLANG_ENGLISH_SOUTH_AFRICA
536 # define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07
537 # endif
538 # ifndef SUBLANG_ENGLISH_JAMAICA
539 # define SUBLANG_ENGLISH_JAMAICA 0x08
540 # endif
541 # ifndef SUBLANG_ENGLISH_CARIBBEAN
542 # define SUBLANG_ENGLISH_CARIBBEAN 0x09
543 # endif
544 # ifndef SUBLANG_ENGLISH_BELIZE
545 # define SUBLANG_ENGLISH_BELIZE 0x0a
546 # endif
547 # ifndef SUBLANG_ENGLISH_TRINIDAD
548 # define SUBLANG_ENGLISH_TRINIDAD 0x0b
549 # endif
550 # ifndef SUBLANG_ENGLISH_ZIMBABWE
551 # define SUBLANG_ENGLISH_ZIMBABWE 0x0c
552 # endif
553 # ifndef SUBLANG_ENGLISH_PHILIPPINES
554 # define SUBLANG_ENGLISH_PHILIPPINES 0x0d
555 # endif
556 # ifndef SUBLANG_ENGLISH_INDONESIA
557 # define SUBLANG_ENGLISH_INDONESIA 0x0e
558 # endif
559 # ifndef SUBLANG_ENGLISH_HONGKONG
560 # define SUBLANG_ENGLISH_HONGKONG 0x0f
561 # endif
562 # ifndef SUBLANG_ENGLISH_INDIA
563 # define SUBLANG_ENGLISH_INDIA 0x10
564 # endif
565 # ifndef SUBLANG_ENGLISH_MALAYSIA
566 # define SUBLANG_ENGLISH_MALAYSIA 0x11
567 # endif
568 # ifndef SUBLANG_ENGLISH_SINGAPORE
569 # define SUBLANG_ENGLISH_SINGAPORE 0x12
570 # endif
571 # ifndef SUBLANG_FRENCH_LUXEMBOURG
572 # define SUBLANG_FRENCH_LUXEMBOURG 0x05
573 # endif
574 # ifndef SUBLANG_FRENCH_MONACO
575 # define SUBLANG_FRENCH_MONACO 0x06
576 # endif
577 # ifndef SUBLANG_FRENCH_WESTINDIES
578 # define SUBLANG_FRENCH_WESTINDIES 0x07
579 # endif
580 # ifndef SUBLANG_FRENCH_REUNION
581 # define SUBLANG_FRENCH_REUNION 0x08
582 # endif
583 # ifndef SUBLANG_FRENCH_CONGO
584 # define SUBLANG_FRENCH_CONGO 0x09
585 # endif
586 # ifndef SUBLANG_FRENCH_SENEGAL
587 # define SUBLANG_FRENCH_SENEGAL 0x0a
588 # endif
589 # ifndef SUBLANG_FRENCH_CAMEROON
590 # define SUBLANG_FRENCH_CAMEROON 0x0b
591 # endif
592 # ifndef SUBLANG_FRENCH_COTEDIVOIRE
593 # define SUBLANG_FRENCH_COTEDIVOIRE 0x0c
594 # endif
595 # ifndef SUBLANG_FRENCH_MALI
596 # define SUBLANG_FRENCH_MALI 0x0d
597 # endif
598 # ifndef SUBLANG_FRENCH_MOROCCO
599 # define SUBLANG_FRENCH_MOROCCO 0x0e
600 # endif
601 # ifndef SUBLANG_FRENCH_HAITI
602 # define SUBLANG_FRENCH_HAITI 0x0f
603 # endif
604 # ifndef SUBLANG_GERMAN_LUXEMBOURG
605 # define SUBLANG_GERMAN_LUXEMBOURG 0x04
606 # endif
607 # ifndef SUBLANG_GERMAN_LIECHTENSTEIN
608 # define SUBLANG_GERMAN_LIECHTENSTEIN 0x05
609 # endif
610 # ifndef SUBLANG_KASHMIRI_INDIA
611 # define SUBLANG_KASHMIRI_INDIA 0x02
612 # endif
613 # ifndef SUBLANG_MALAY_MALAYSIA
614 # define SUBLANG_MALAY_MALAYSIA 0x01
615 # endif
616 # ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
617 # define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02
618 # endif
619 # ifndef SUBLANG_NEPALI_INDIA
620 # define SUBLANG_NEPALI_INDIA 0x02
621 # endif
622 # ifndef SUBLANG_PUNJABI_INDIA
623 # define SUBLANG_PUNJABI_INDIA 0x01
624 # endif
625 # ifndef SUBLANG_ROMANIAN_ROMANIA
626 # define SUBLANG_ROMANIAN_ROMANIA 0x01
627 # endif
628 # ifndef SUBLANG_SERBIAN_LATIN
629 # define SUBLANG_SERBIAN_LATIN 0x02
630 # endif
631 # ifndef SUBLANG_SERBIAN_CYRILLIC
632 # define SUBLANG_SERBIAN_CYRILLIC 0x03
633 # endif
634 # ifndef SUBLANG_SINDHI_INDIA
635 # define SUBLANG_SINDHI_INDIA 0x00
636 # endif
637 # ifndef SUBLANG_SINDHI_PAKISTAN
638 # define SUBLANG_SINDHI_PAKISTAN 0x01
639 # endif
640 # ifndef SUBLANG_SPANISH_GUATEMALA
641 # define SUBLANG_SPANISH_GUATEMALA 0x04
642 # endif
643 # ifndef SUBLANG_SPANISH_COSTA_RICA
644 # define SUBLANG_SPANISH_COSTA_RICA 0x05
645 # endif
646 # ifndef SUBLANG_SPANISH_PANAMA
647 # define SUBLANG_SPANISH_PANAMA 0x06
648 # endif
649 # ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC
650 # define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07
651 # endif
652 # ifndef SUBLANG_SPANISH_VENEZUELA
653 # define SUBLANG_SPANISH_VENEZUELA 0x08
654 # endif
655 # ifndef SUBLANG_SPANISH_COLOMBIA
656 # define SUBLANG_SPANISH_COLOMBIA 0x09
657 # endif
658 # ifndef SUBLANG_SPANISH_PERU
659 # define SUBLANG_SPANISH_PERU 0x0a
660 # endif
661 # ifndef SUBLANG_SPANISH_ARGENTINA
662 # define SUBLANG_SPANISH_ARGENTINA 0x0b
663 # endif
664 # ifndef SUBLANG_SPANISH_ECUADOR
665 # define SUBLANG_SPANISH_ECUADOR 0x0c
666 # endif
667 # ifndef SUBLANG_SPANISH_CHILE
668 # define SUBLANG_SPANISH_CHILE 0x0d
669 # endif
670 # ifndef SUBLANG_SPANISH_URUGUAY
671 # define SUBLANG_SPANISH_URUGUAY 0x0e
672 # endif
673 # ifndef SUBLANG_SPANISH_PARAGUAY
674 # define SUBLANG_SPANISH_PARAGUAY 0x0f
675 # endif
676 # ifndef SUBLANG_SPANISH_BOLIVIA
677 # define SUBLANG_SPANISH_BOLIVIA 0x10
678 # endif
679 # ifndef SUBLANG_SPANISH_EL_SALVADOR
680 # define SUBLANG_SPANISH_EL_SALVADOR 0x11
681 # endif
682 # ifndef SUBLANG_SPANISH_HONDURAS
683 # define SUBLANG_SPANISH_HONDURAS 0x12
684 # endif
685 # ifndef SUBLANG_SPANISH_NICARAGUA
686 # define SUBLANG_SPANISH_NICARAGUA 0x13
687 # endif
688 # ifndef SUBLANG_SPANISH_PUERTO_RICO
689 # define SUBLANG_SPANISH_PUERTO_RICO 0x14
690 # endif
691 # ifndef SUBLANG_SWEDISH_FINLAND
692 # define SUBLANG_SWEDISH_FINLAND 0x02
693 # endif
694 # ifndef SUBLANG_TAMAZIGHT_ARABIC
695 # define SUBLANG_TAMAZIGHT_ARABIC 0x01
696 # endif
697 # ifndef SUBLANG_TAMAZIGHT_LATIN
698 # define SUBLANG_TAMAZIGHT_LATIN 0x02
699 # endif
700 # ifndef SUBLANG_TIGRINYA_ETHIOPIA
701 # define SUBLANG_TIGRINYA_ETHIOPIA 0x00
702 # endif
703 # ifndef SUBLANG_TIGRINYA_ERITREA
704 # define SUBLANG_TIGRINYA_ERITREA 0x01
705 # endif
706 # ifndef SUBLANG_URDU_PAKISTAN
707 # define SUBLANG_URDU_PAKISTAN 0x01
708 # endif
709 # ifndef SUBLANG_URDU_INDIA
710 # define SUBLANG_URDU_INDIA 0x02
711 # endif
712 # ifndef SUBLANG_UZBEK_LATIN
713 # define SUBLANG_UZBEK_LATIN 0x01
714 # endif
715 # ifndef SUBLANG_UZBEK_CYRILLIC
716 # define SUBLANG_UZBEK_CYRILLIC 0x02
717 # endif
718 #endif /* HAVE_W32_SYSTEM */
719
720 /* XPG3 defines the result of 'setlocale (category, NULL)' as:
721    "Directs 'setlocale()' to query 'category' and return the current
722     setting of 'local'."
723    However it does not specify the exact format.  Neither do SUSV2 and
724    ISO C 99.  So we can use this feature only on selected systems (e.g.
725    those using GNU C Library).  */
726 #if defined _LIBC || (defined __GNU_LIBRARY__ && __GNU_LIBRARY__ >= 2)
727 # define HAVE_LOCALE_NULL
728 #endif
729
730 /* Determine the current locale's name, and canonicalize it into XPG syntax
731      language[_territory[.codeset]][@modifier]
732    The codeset part in the result is not reliable; the locale_charset()
733    should be used for codeset information instead.
734    The result must not be freed; it is statically allocated.  */
735
736 static const char *
737 _nl_locale_name (int category, const char *categoryname)
738 {
739   const char *retval;
740
741 #ifndef HAVE_W32_SYSTEM
742
743   /* Use the POSIX methods of looking to 'LC_ALL', 'LC_xxx', and 'LANG'.
744      On some systems this can be done by the 'setlocale' function itself.  */
745 # if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
746   retval = setlocale (category, NULL);
747 # else
748   /* Setting of LC_ALL overwrites all other.  */
749   retval = getenv ("LC_ALL");
750   if (retval == NULL || retval[0] == '\0')
751     {
752       /* Next comes the name of the desired category.  */
753       retval = getenv (categoryname);
754       if (retval == NULL || retval[0] == '\0')
755         {
756           /* Last possibility is the LANG environment variable.  */
757           retval = getenv ("LANG");
758           if (retval == NULL || retval[0] == '\0')
759             /* We use C as the default domain.  POSIX says this is
760                implementation defined.  */
761             retval = "C";
762         }
763     }
764 # endif
765
766   return retval;
767
768 #else /* HAVE_W32_SYSTEM */
769
770   /* Return an XPG style locale name language[_territory][@modifier].
771      Don't even bother determining the codeset; it's not useful in this
772      context, because message catalogs are not specific to a single
773      codeset.  */
774
775   LCID lcid;
776   LANGID langid;
777   int primary, sub;
778
779   (void)category;
780
781   /* Let the user override the system settings through environment
782      variables, as on POSIX systems.  */
783   retval = getenv ("LC_ALL");
784   if (retval != NULL && retval[0] != '\0')
785     return retval;
786   retval = getenv (categoryname);
787   if (retval != NULL && retval[0] != '\0')
788     return retval;
789   retval = getenv ("LANG");
790   if (retval != NULL && retval[0] != '\0')
791     return retval;
792
793   /* Prefer the Ui language of Outlook. */
794 #ifndef BUILD_TESTS
795   lcid = get_ol_ui_language ();
796 #else
797   lcid = 0;
798 #endif
799
800   if (!lcid)
801     {
802       /* Use native Win32 API locale ID.  */
803       lcid = GetThreadLocale ();
804     }
805
806   /* Strip off the sorting rules, keep only the language part.  */
807   langid = LANGIDFROMLCID (lcid);
808
809   /* Split into language and territory part.  */
810   primary = PRIMARYLANGID (langid);
811   sub = SUBLANGID (langid);
812
813   /* Dispatch on language.
814      See also http://www.unicode.org/unicode/onlinedat/languages.html .
815      For details about languages, see http://www.ethnologue.com/ .  */
816   switch (primary)
817     {
818     case LANG_AFRIKAANS: return "af_ZA";
819     case LANG_ALBANIAN: return "sq_AL";
820     case LANG_AMHARIC: return "am_ET";
821     case LANG_ARABIC:
822       switch (sub)
823         {
824         case SUBLANG_ARABIC_SAUDI_ARABIA: return "ar_SA";
825         case SUBLANG_ARABIC_IRAQ: return "ar_IQ";
826         case SUBLANG_ARABIC_EGYPT: return "ar_EG";
827         case SUBLANG_ARABIC_LIBYA: return "ar_LY";
828         case SUBLANG_ARABIC_ALGERIA: return "ar_DZ";
829         case SUBLANG_ARABIC_MOROCCO: return "ar_MA";
830         case SUBLANG_ARABIC_TUNISIA: return "ar_TN";
831         case SUBLANG_ARABIC_OMAN: return "ar_OM";
832         case SUBLANG_ARABIC_YEMEN: return "ar_YE";
833         case SUBLANG_ARABIC_SYRIA: return "ar_SY";
834         case SUBLANG_ARABIC_JORDAN: return "ar_JO";
835         case SUBLANG_ARABIC_LEBANON: return "ar_LB";
836         case SUBLANG_ARABIC_KUWAIT: return "ar_KW";
837         case SUBLANG_ARABIC_UAE: return "ar_AE";
838         case SUBLANG_ARABIC_BAHRAIN: return "ar_BH";
839         case SUBLANG_ARABIC_QATAR: return "ar_QA";
840         }
841       return "ar";
842     case LANG_ARMENIAN: return "hy_AM";
843     case LANG_ASSAMESE: return "as_IN";
844     case LANG_AZERI:
845       switch (sub)
846         {
847         /* FIXME: Adjust this when Azerbaijani locales appear on Unix.  */
848         case SUBLANG_AZERI_LATIN: return "az_AZ@latin";
849         case SUBLANG_AZERI_CYRILLIC: return "az_AZ@cyrillic";
850         }
851       return "az";
852     case LANG_BASQUE:
853       return "eu"; /* Ambiguous: could be "eu_ES" or "eu_FR".  */
854     case LANG_BELARUSIAN: return "be_BY";
855     case LANG_BENGALI:
856       switch (sub)
857         {
858         case SUBLANG_BENGALI_INDIA: return "bn_IN";
859         case SUBLANG_BENGALI_BANGLADESH: return "bn_BD";
860         }
861       return "bn";
862     case LANG_BULGARIAN: return "bg_BG";
863     case LANG_BURMESE: return "my_MM";
864     case LANG_CAMBODIAN: return "km_KH";
865     case LANG_CATALAN: return "ca_ES";
866     case LANG_CHEROKEE: return "chr_US";
867     case LANG_CHINESE:
868       switch (sub)
869         {
870         case SUBLANG_CHINESE_TRADITIONAL: return "zh_TW";
871         case SUBLANG_CHINESE_SIMPLIFIED: return "zh_CN";
872         case SUBLANG_CHINESE_HONGKONG: return "zh_HK";
873         case SUBLANG_CHINESE_SINGAPORE: return "zh_SG";
874         case SUBLANG_CHINESE_MACAU: return "zh_MO";
875         }
876       return "zh";
877     case LANG_CROATIAN:         /* LANG_CROATIAN == LANG_SERBIAN
878                                  * What used to be called Serbo-Croatian
879                                  * should really now be two separate
880                                  * languages because of political reasons.
881                                  * (Says tml, who knows nothing about Serbian
882                                  * or Croatian.)
883                                  * (I can feel those flames coming already.)
884                                  */
885       switch (sub)
886         {
887         case SUBLANG_DEFAULT: return "hr_HR";
888         case SUBLANG_SERBIAN_LATIN: return "sr_CS";
889         case SUBLANG_SERBIAN_CYRILLIC: return "sr_CS@cyrillic";
890         }
891       return "hr";
892     case LANG_CZECH: return "cs_CZ";
893     case LANG_DANISH: return "da_DK";
894     case LANG_DIVEHI: return "div_MV";
895     case LANG_DUTCH:
896       switch (sub)
897         {
898         case SUBLANG_DUTCH: return "nl_NL";
899         case SUBLANG_DUTCH_BELGIAN: /* FLEMISH, VLAAMS */ return "nl_BE";
900         }
901       return "nl";
902     case LANG_EDO: return "bin_NG";
903     case LANG_ENGLISH:
904       switch (sub)
905         {
906         /* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought
907          * English was the language spoken in England.
908          * Oh well.
909          */
910         case SUBLANG_ENGLISH_US: return "en_US";
911         case SUBLANG_ENGLISH_UK: return "en_GB";
912         case SUBLANG_ENGLISH_AUS: return "en_AU";
913         case SUBLANG_ENGLISH_CAN: return "en_CA";
914         case SUBLANG_ENGLISH_NZ: return "en_NZ";
915         case SUBLANG_ENGLISH_EIRE: return "en_IE";
916         case SUBLANG_ENGLISH_SOUTH_AFRICA: return "en_ZA";
917         case SUBLANG_ENGLISH_JAMAICA: return "en_JM";
918         case SUBLANG_ENGLISH_CARIBBEAN: return "en_GD"; /* Grenada? */
919         case SUBLANG_ENGLISH_BELIZE: return "en_BZ";
920         case SUBLANG_ENGLISH_TRINIDAD: return "en_TT";
921         case SUBLANG_ENGLISH_ZIMBABWE: return "en_ZW";
922         case SUBLANG_ENGLISH_PHILIPPINES: return "en_PH";
923         case SUBLANG_ENGLISH_INDONESIA: return "en_ID";
924         case SUBLANG_ENGLISH_HONGKONG: return "en_HK";
925         case SUBLANG_ENGLISH_INDIA: return "en_IN";
926         case SUBLANG_ENGLISH_MALAYSIA: return "en_MY";
927         case SUBLANG_ENGLISH_SINGAPORE: return "en_SG";
928         }
929       return "en";
930     case LANG_ESTONIAN: return "et_EE";
931     case LANG_FAEROESE: return "fo_FO";
932     case LANG_FARSI: return "fa_IR";
933     case LANG_FINNISH: return "fi_FI";
934     case LANG_FRENCH:
935       switch (sub)
936         {
937         case SUBLANG_FRENCH: return "fr_FR";
938         case SUBLANG_FRENCH_BELGIAN: /* WALLOON */ return "fr_BE";
939         case SUBLANG_FRENCH_CANADIAN: return "fr_CA";
940         case SUBLANG_FRENCH_SWISS: return "fr_CH";
941         case SUBLANG_FRENCH_LUXEMBOURG: return "fr_LU";
942         case SUBLANG_FRENCH_MONACO: return "fr_MC";
943         case SUBLANG_FRENCH_WESTINDIES: return "fr"; /* Caribbean? */
944         case SUBLANG_FRENCH_REUNION: return "fr_RE";
945         case SUBLANG_FRENCH_CONGO: return "fr_CG";
946         case SUBLANG_FRENCH_SENEGAL: return "fr_SN";
947         case SUBLANG_FRENCH_CAMEROON: return "fr_CM";
948         case SUBLANG_FRENCH_COTEDIVOIRE: return "fr_CI";
949         case SUBLANG_FRENCH_MALI: return "fr_ML";
950         case SUBLANG_FRENCH_MOROCCO: return "fr_MA";
951         case SUBLANG_FRENCH_HAITI: return "fr_HT";
952         }
953       return "fr";
954     case LANG_FRISIAN: return "fy_NL";
955     case LANG_FULFULDE: return "ful_NG";
956     case LANG_GAELIC:
957       switch (sub)
958         {
959         case 0x01: /* SCOTTISH */ return "gd_GB";
960         case 0x02: /* IRISH */ return "ga_IE";
961         }
962       return "C";
963     case LANG_GALICIAN: return "gl_ES";
964     case LANG_GEORGIAN: return "ka_GE";
965     case LANG_GERMAN:
966       switch (sub)
967         {
968         case SUBLANG_GERMAN: return "de_DE";
969         case SUBLANG_GERMAN_SWISS: return "de_CH";
970         case SUBLANG_GERMAN_AUSTRIAN: return "de_AT";
971         case SUBLANG_GERMAN_LUXEMBOURG: return "de_LU";
972         case SUBLANG_GERMAN_LIECHTENSTEIN: return "de_LI";
973         }
974       return "de";
975     case LANG_GREEK: return "el_GR";
976     case LANG_GUARANI: return "gn_PY";
977     case LANG_GUJARATI: return "gu_IN";
978     case LANG_HAUSA: return "ha_NG";
979     case LANG_HAWAIIAN:
980       /* FIXME: Do they mean Hawaiian ("haw_US", 1000 speakers)
981          or Hawaii Creole English ("cpe_US", 600000 speakers)?  */
982       return "cpe_US";
983     case LANG_HEBREW: return "he_IL";
984     case LANG_HINDI: return "hi_IN";
985     case LANG_HUNGARIAN: return "hu_HU";
986     case LANG_IBIBIO: return "nic_NG";
987     case LANG_ICELANDIC: return "is_IS";
988     case LANG_IGBO: return "ibo_NG";
989     case LANG_INDONESIAN: return "id_ID";
990     case LANG_INUKTITUT: return "iu_CA";
991     case LANG_ITALIAN:
992       switch (sub)
993         {
994         case SUBLANG_ITALIAN: return "it_IT";
995         case SUBLANG_ITALIAN_SWISS: return "it_CH";
996         }
997       return "it";
998     case LANG_JAPANESE: return "ja_JP";
999     case LANG_KANNADA: return "kn_IN";
1000     case LANG_KANURI: return "kau_NG";
1001     case LANG_KASHMIRI:
1002       switch (sub)
1003         {
1004         case SUBLANG_DEFAULT: return "ks_PK";
1005         case SUBLANG_KASHMIRI_INDIA: return "ks_IN";
1006         }
1007       return "ks";
1008     case LANG_KAZAK: return "kk_KZ";
1009     case LANG_KONKANI:
1010       /* FIXME: Adjust this when such locales appear on Unix.  */
1011       return "kok_IN";
1012     case LANG_KOREAN: return "ko_KR";
1013     case LANG_KYRGYZ: return "ky_KG";
1014     case LANG_LAO: return "lo_LA";
1015     case LANG_LATIN: return "la_VA";
1016     case LANG_LATVIAN: return "lv_LV";
1017     case LANG_LITHUANIAN: return "lt_LT";
1018     case LANG_MACEDONIAN: return "mk_MK";
1019     case LANG_MALAY:
1020       switch (sub)
1021         {
1022         case SUBLANG_MALAY_MALAYSIA: return "ms_MY";
1023         case SUBLANG_MALAY_BRUNEI_DARUSSALAM: return "ms_BN";
1024         }
1025       return "ms";
1026     case LANG_MALAYALAM: return "ml_IN";
1027     case LANG_MALTESE: return "mt_MT";
1028     case LANG_MANIPURI:
1029       /* FIXME: Adjust this when such locales appear on Unix.  */
1030       return "mni_IN";
1031     case LANG_MARATHI: return "mr_IN";
1032     case LANG_MONGOLIAN:
1033       return "mn"; /* Ambiguous: could be "mn_CN" or "mn_MN".  */
1034     case LANG_NEPALI:
1035       switch (sub)
1036         {
1037         case SUBLANG_DEFAULT: return "ne_NP";
1038         case SUBLANG_NEPALI_INDIA: return "ne_IN";
1039         }
1040       return "ne";
1041     case LANG_NORWEGIAN:
1042       switch (sub)
1043         {
1044         case SUBLANG_NORWEGIAN_BOKMAL: return "no_NO";
1045         case SUBLANG_NORWEGIAN_NYNORSK: return "nn_NO";
1046         }
1047       return "no";
1048     case LANG_ORIYA: return "or_IN";
1049     case LANG_OROMO: return "om_ET";
1050     case LANG_PAPIAMENTU: return "pap_AN";
1051     case LANG_PASHTO:
1052       return "ps"; /* Ambiguous: could be "ps_PK" or "ps_AF".  */
1053     case LANG_POLISH: return "pl_PL";
1054     case LANG_PORTUGUESE:
1055       switch (sub)
1056         {
1057         case SUBLANG_PORTUGUESE: return "pt_PT";
1058         /* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT.
1059            Same phenomenon as SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. */
1060         case SUBLANG_PORTUGUESE_BRAZILIAN: return "pt_BR";
1061         }
1062       return "pt";
1063     case LANG_PUNJABI:
1064       switch (sub)
1065         {
1066         case SUBLANG_PUNJABI_INDIA: return "pa_IN"; /* Gurmukhi script */
1067         }
1068       return "pa";
1069     case LANG_RHAETO_ROMANCE: return "rm_CH";
1070     case LANG_ROMANIAN:
1071       switch (sub)
1072         {
1073         case SUBLANG_ROMANIAN_ROMANIA: return "ro_RO";
1074         }
1075       return "ro";
1076     case LANG_RUSSIAN:
1077       return "ru"; /* Ambiguous: could be "ru_RU" or "ru_UA" or "ru_MD".  */
1078     case LANG_SAAMI: /* actually Northern Sami */ return "se_NO";
1079     case LANG_SANSKRIT: return "sa_IN";
1080     case LANG_SINDHI:
1081       switch (sub)
1082         {
1083         case SUBLANG_SINDHI_INDIA: return "sd_IN";
1084         case SUBLANG_SINDHI_PAKISTAN: return "sd_PK";
1085         }
1086       return "sd";
1087     case LANG_SINHALESE: return "si_LK";
1088     case LANG_SLOVAK: return "sk_SK";
1089     case LANG_SLOVENIAN: return "sl_SI";
1090     case LANG_SOMALI: return "so_SO";
1091     case LANG_SORBIAN:
1092       /* FIXME: Adjust this when such locales appear on Unix.  */
1093       return "wen_DE";
1094     case LANG_SPANISH:
1095       switch (sub)
1096         {
1097         case SUBLANG_SPANISH: return "es_ES";
1098         case SUBLANG_SPANISH_MEXICAN: return "es_MX";
1099         case SUBLANG_SPANISH_MODERN:
1100           return "es_ES@modern";        /* not seen on Unix */
1101         case SUBLANG_SPANISH_GUATEMALA: return "es_GT";
1102         case SUBLANG_SPANISH_COSTA_RICA: return "es_CR";
1103         case SUBLANG_SPANISH_PANAMA: return "es_PA";
1104         case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: return "es_DO";
1105         case SUBLANG_SPANISH_VENEZUELA: return "es_VE";
1106         case SUBLANG_SPANISH_COLOMBIA: return "es_CO";
1107         case SUBLANG_SPANISH_PERU: return "es_PE";
1108         case SUBLANG_SPANISH_ARGENTINA: return "es_AR";
1109         case SUBLANG_SPANISH_ECUADOR: return "es_EC";
1110         case SUBLANG_SPANISH_CHILE: return "es_CL";
1111         case SUBLANG_SPANISH_URUGUAY: return "es_UY";
1112         case SUBLANG_SPANISH_PARAGUAY: return "es_PY";
1113         case SUBLANG_SPANISH_BOLIVIA: return "es_BO";
1114         case SUBLANG_SPANISH_EL_SALVADOR: return "es_SV";
1115         case SUBLANG_SPANISH_HONDURAS: return "es_HN";
1116         case SUBLANG_SPANISH_NICARAGUA: return "es_NI";
1117         case SUBLANG_SPANISH_PUERTO_RICO: return "es_PR";
1118         }
1119       return "es";
1120     case LANG_SUTU: return "bnt_TZ"; /* or "st_LS" or "nso_ZA"? */
1121     case LANG_SWAHILI: return "sw_KE";
1122     case LANG_SWEDISH:
1123       switch (sub)
1124         {
1125         case SUBLANG_DEFAULT: return "sv_SE";
1126         case SUBLANG_SWEDISH_FINLAND: return "sv_FI";
1127         }
1128       return "sv";
1129     case LANG_SYRIAC: return "syr_TR"; /* An extinct language.  */
1130     case LANG_TAGALOG: return "tl_PH";
1131     case LANG_TAJIK: return "tg_TJ";
1132     case LANG_TAMAZIGHT:
1133       switch (sub)
1134         {
1135         /* FIXME: Adjust this when Tamazight locales appear on Unix.  */
1136         case SUBLANG_TAMAZIGHT_ARABIC: return "ber_MA@arabic";
1137         case SUBLANG_TAMAZIGHT_LATIN: return "ber_MA@latin";
1138         }
1139       return "ber_MA";
1140     case LANG_TAMIL:
1141       return "ta"; /* Ambiguous: could be "ta_IN" or "ta_LK" or "ta_SG".  */
1142     case LANG_TATAR: return "tt_RU";
1143     case LANG_TELUGU: return "te_IN";
1144     case LANG_THAI: return "th_TH";
1145     case LANG_TIBETAN: return "bo_CN";
1146     case LANG_TIGRINYA:
1147       switch (sub)
1148         {
1149         case SUBLANG_TIGRINYA_ETHIOPIA: return "ti_ET";
1150         case SUBLANG_TIGRINYA_ERITREA: return "ti_ER";
1151         }
1152       return "ti";
1153     case LANG_TSONGA: return "ts_ZA";
1154     case LANG_TSWANA: return "tn_BW";
1155     case LANG_TURKISH: return "tr_TR";
1156     case LANG_TURKMEN: return "tk_TM";
1157     case LANG_UKRAINIAN: return "uk_UA";
1158     case LANG_URDU:
1159       switch (sub)
1160         {
1161         case SUBLANG_URDU_PAKISTAN: return "ur_PK";
1162         case SUBLANG_URDU_INDIA: return "ur_IN";
1163         }
1164       return "ur";
1165     case LANG_UZBEK:
1166       switch (sub)
1167         {
1168         case SUBLANG_UZBEK_LATIN: return "uz_UZ";
1169         case SUBLANG_UZBEK_CYRILLIC: return "uz_UZ@cyrillic";
1170         }
1171       return "uz";
1172     case LANG_VENDA:
1173       /* FIXME: It's not clear whether Venda has the ISO 639-2 two-letter code
1174          "ve" or not.
1175          http://www.loc.gov/standards/iso639-2/englangn.html has it, but
1176          http://lcweb.loc.gov/standards/iso639-2/codechanges.html doesn't,  */
1177       return "ven_ZA"; /* or "ve_ZA"? */
1178     case LANG_VIETNAMESE: return "vi_VN";
1179     case LANG_WELSH: return "cy_GB";
1180     case LANG_XHOSA: return "xh_ZA";
1181     case LANG_YI: return "sit_CN";
1182     case LANG_YIDDISH: return "yi_IL";
1183     case LANG_YORUBA: return "yo_NG";
1184     case LANG_ZULU: return "zu_ZA";
1185     default: return "C";
1186     }
1187
1188 #endif /* HAVE_W32_SYSTEM */
1189 }
1190
1191 /* localname.c from gettext END.  */
1192 \f
1193 /* Support functions.  */
1194
1195 typedef uint32_t u32;
1196 typedef unsigned long ulong;
1197
1198 static __inline__ u32
1199 do_swap_u32 (u32 i)
1200 {
1201   return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
1202 }
1203
1204 #define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data))
1205
1206
1207 /* We assume to have `unsigned long int' value with at least 32 bits.  */
1208 #define HASHWORDBITS 32
1209
1210 /* The so called `hashpjw' function by P.J. Weinberger
1211    [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
1212    1986, 1987 Bell Telephone Laboratories, Inc.]  */
1213
1214 static __inline__ ulong
1215 hash_string( const char *str_param )
1216 {
1217     unsigned long int hval, g;
1218     const char *str = str_param;
1219
1220     hval = 0;
1221     while (*str != '\0')
1222     {
1223         hval <<= 4;
1224         hval += (unsigned long int) *str++;
1225         g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
1226         if (g != 0)
1227         {
1228           hval ^= g >> (HASHWORDBITS - 8);
1229           hval ^= g;
1230         }
1231     }
1232     return hval;
1233 }
1234
1235 \f
1236 /* Generic message catalog and gettext stuff.  */
1237
1238 /* The magic number of the GNU message catalog format.  */
1239 #define MAGIC         0x950412de
1240 #define MAGIC_SWAPPED 0xde120495
1241
1242 /* Revision number of the currently used .mo (binary) file format.  */
1243 #define MO_REVISION_NUMBER 0
1244
1245 /* Header for binary .mo file format.  */
1246 struct mo_file_header
1247 {
1248   /* The magic number.  */
1249   u32 magic;
1250   /* The revision number of the file format.  */
1251   u32 revision;
1252   /* The number of strings pairs.  */
1253   u32 nstrings;
1254   /* Offset of table with start offsets of original strings.  */
1255   u32 orig_tab_offset;
1256   /* Offset of table with start offsets of translation strings.  */
1257   u32 trans_tab_offset;
1258   /* Size of hashing table.  */
1259   u32 hash_tab_size;
1260   /* Offset of first hashing entry.  */
1261   u32 hash_tab_offset;
1262 };
1263
1264 struct string_desc
1265 {
1266   /* Length of addressed string.  */
1267   u32 length;
1268   /* Offset of string in file.  */
1269   u32 offset;
1270 };
1271
1272
1273 struct overflow_space_s
1274 {
1275   struct overflow_space_s *next;
1276   u32 idx;
1277   char d[1];
1278 };
1279
1280 struct loaded_domain
1281 {
1282   char *data;
1283   int must_swap;
1284   u32 nstrings;
1285   char *mapped;  /* 0 = not yet mapped, 1 = mapped,
1286                     2 = mapped to
1287                     overflow space */
1288   struct overflow_space_s *overflow_space;
1289   struct string_desc *orig_tab;
1290   struct string_desc *trans_tab;
1291   u32 hash_size;
1292   u32 *hash_tab;
1293 };
1294
1295 \f
1296 /* Free the domain data.  */
1297 static void
1298 free_domain (struct loaded_domain *domain)
1299 {
1300   struct overflow_space_s *os, *os2;
1301   xfree (domain->data);
1302   xfree (domain->mapped);
1303   for (os = domain->overflow_space; os; os = os2)
1304     {
1305       os2 = os->next;
1306       xfree (os);
1307     }
1308   xfree (domain);
1309 }
1310
1311
1312 /* The gettext implementation; support functions.  */
1313 static struct loaded_domain *
1314 load_domain (const char *filename)
1315 {
1316   FILE *fp;
1317   size_t size;
1318   struct stat st;
1319   struct mo_file_header *data = NULL;
1320   struct loaded_domain *domain = NULL;
1321   size_t to_read;
1322   char *read_ptr;
1323
1324   fp = fopen (filename, "rb");
1325   if (!fp)
1326     return NULL;
1327
1328   /* Determine the file size.  */
1329   if (fstat (fileno (fp), &st)
1330       || (size = (size_t) st.st_size) != st.st_size
1331       || size < sizeof (struct mo_file_header))
1332     {
1333       fclose (fp);
1334       return NULL;
1335     }
1336
1337   data = (mo_file_header*) xmalloc (size);
1338   if (!data)
1339     {
1340       fclose (fp);
1341       return NULL;
1342     }
1343
1344   to_read = size;
1345   read_ptr = (char *) data;
1346   do
1347     {
1348       long int nb = fread (read_ptr, 1, to_read, fp);
1349       if (nb < to_read)
1350         {
1351           fclose (fp);
1352           xfree (data);
1353           return NULL;
1354         }
1355       read_ptr += nb;
1356       to_read -= nb;
1357     }
1358   while (to_read > 0);
1359   fclose (fp);
1360
1361   /* Using the magic number we can test whether it really is a message
1362      catalog file.  */
1363   if (data->magic != MAGIC && data->magic != MAGIC_SWAPPED)
1364     {
1365       /* The magic number is wrong: not a message catalog file.  */
1366       xfree (data);
1367       return NULL;
1368     }
1369
1370   domain = (loaded_domain *) xcalloc (1, sizeof *domain);
1371   if (!domain)
1372     {
1373       xfree (data);
1374       return NULL;
1375     }
1376   domain->data = (char *) data;
1377   domain->must_swap = data->magic != MAGIC;
1378
1379   /* Fill in the information about the available tables.  */
1380   switch (SWAPIT (domain->must_swap, data->revision))
1381     {
1382     case 0:
1383
1384       domain->nstrings = SWAPIT (domain->must_swap, data->nstrings);
1385       domain->orig_tab = (struct string_desc *)
1386         ((char *) data + SWAPIT (domain->must_swap, data->orig_tab_offset));
1387       domain->trans_tab = (struct string_desc *)
1388         ((char *) data + SWAPIT (domain->must_swap, data->trans_tab_offset));
1389       domain->hash_size = SWAPIT (domain->must_swap, data->hash_tab_size);
1390       domain->hash_tab = (u32 *)
1391         ((char *) data + SWAPIT (domain->must_swap, data->hash_tab_offset));
1392       break;
1393
1394     default:
1395       /* This is an invalid revision.   */
1396       xfree (data);
1397       xfree (domain);
1398       return NULL;
1399     }
1400
1401   /* Allocate an array to keep track of code page mappings.  */
1402   domain->mapped = (char *) xcalloc (1, domain->nstrings);
1403   if (!domain->mapped)
1404     {
1405       xfree (data);
1406       xfree (domain);
1407       return NULL;
1408     }
1409
1410   return domain;
1411 }
1412
1413
1414 /* Return a malloced string encoded in UTF-8 from the wide char input
1415    string STRING.  Caller must free this value. On failure returns
1416    NULL; caller may use GetLastError to get the actual error number.
1417    The result of calling this function with STRING set to NULL is not
1418    defined. */
1419 static char *
1420 wchar_to_native (const wchar_t *string)
1421 {
1422   int n;
1423   char *result;
1424
1425   n = WideCharToMultiByte (CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
1426   if (n < 0)
1427     return NULL;
1428
1429   result = (char*) xmalloc (n+1);
1430   if (!result)
1431     return NULL;
1432
1433   n = WideCharToMultiByte (CP_ACP, 0, string, -1, result, n, NULL, NULL);
1434   if (n < 0)
1435     {
1436       xfree (result);
1437       return NULL;
1438     }
1439   return result;
1440 }
1441
1442
1443 static wchar_t *
1444 native_to_wchar (const char *string)
1445 {
1446   int n;
1447   wchar_t *result;
1448
1449   n = MultiByteToWideChar (CP_ACP, 0, string, -1, NULL, 0);
1450   if (n < 0)
1451     return NULL;
1452
1453   result = (wchar_t *) xmalloc ((n+1) * sizeof *result);
1454   if (!result)
1455     return NULL;
1456
1457   n = MultiByteToWideChar (CP_ACP, 0, string, -1, result, n);
1458   if (n < 0)
1459     {
1460       xfree (result);
1461       return NULL;
1462     }
1463   return result;
1464 }
1465
1466
1467 /* Return a malloced wide char string from an UTF-8 encoded input
1468    string STRING.  Caller must free this value. On failure returns
1469    NULL; caller may use GetLastError to get the actual error number.
1470    The result of calling this function with STRING set to NULL is not
1471    defined. */
1472 wchar_t *
1473 _utf8_to_wchar (const char *string)
1474 {
1475   int n;
1476   wchar_t *result;
1477
1478   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
1479   if (n < 0)
1480     return NULL;
1481
1482   result = (wchar_t *) xmalloc ((n+1) * sizeof *result);
1483   if (!result)
1484     return NULL;
1485
1486   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
1487   if (n < 0)
1488     {
1489       xfree (result);
1490       return NULL;
1491     }
1492   return result;
1493 }
1494
1495
1496 /* Return a malloced string encoded in UTF-8 from the wide char input
1497    string STRING.  Caller must xfree this value. On failure returns
1498    NULL; caller may use GetLastError to get the actual error number.
1499    The result of calling this function with STRING set to NULL is not
1500    defined. */
1501 char *
1502 _wchar_to_utf8 (const wchar_t *string)
1503 {
1504   int n;
1505   char *result;
1506
1507   /* Note, that CP_UTF8 is not defined in Windows versions earlier
1508      than NT.*/
1509   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
1510   if (n < 0)
1511     return NULL;
1512
1513   result = (char *) xmalloc (n+1);
1514   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
1515   if (n < 0)
1516     {
1517       xfree (result);
1518       return NULL;
1519     }
1520   return result;
1521 }
1522
1523 std::string
1524 wchar_to_utf8_string (const wchar_t *string)
1525 {
1526   std::string ret;
1527   if (!string)
1528     {
1529       return ret;
1530     }
1531
1532   const auto utf8 = wchar_to_utf8 (string);
1533   if (!utf8)
1534     {
1535       return ret;
1536     }
1537   ret = utf8;
1538
1539   xfree (utf8);
1540   return ret;
1541 }
1542
1543
1544 /* Convert UTF8 to the native codepage.  This function is guaranteed
1545    to never return NULL.  Caller must xfree the return value. */
1546 char *
1547 utf8_to_native (const char *string)
1548 {
1549   wchar_t *wstring;
1550   char *result;
1551
1552   wstring = utf8_to_wchar (string);
1553   if (!wstring)
1554     return xstrdup ("[Error: utf8_to_wchar failed]");
1555
1556   result = wchar_to_native (wstring);
1557   xfree (wstring);
1558   if (!result)
1559     result = xstrdup ("[Error: wchar_to_native failed]");
1560
1561   return result;
1562 }
1563
1564
1565 /* Convert native character set to utf-8.  This is required if we want
1566    to get an utf-8 string from a gettext translated function which
1567    internally uses utf8_to_native.  It is guaranteed that NULL is
1568    never returned.  Caller must xfree the return value. */
1569 char *
1570 native_to_utf8 (const char *string)
1571 {
1572   char *result;
1573   wchar_t *wstring;
1574
1575   wstring = native_to_wchar (string);
1576   if (!wstring)
1577     return xstrdup ("[Error: native_to_wchar failed]");
1578
1579   result = wchar_to_utf8 (wstring);
1580   xfree (wstring);
1581   if (!result)
1582     result = xstrdup ("[Error: wchar_to_utf8 failed]");
1583
1584   return result;
1585 }
1586
1587
1588
1589 static const char*
1590 get_string (struct loaded_domain *domain, u32 idx, int utf8)
1591 {
1592   struct overflow_space_s *os;
1593   char *p;
1594
1595   p = domain->data + SWAPIT (domain->must_swap, domain->trans_tab[idx].offset);
1596   if (!domain->mapped[idx])
1597     {
1598       size_t plen, buflen;
1599       char *buf;
1600
1601       domain->mapped[idx] = 1;
1602
1603       plen = strlen (p);
1604       buf = utf8 ? xstrdup (p) : utf8_to_native (p);
1605       buflen = strlen (buf);
1606       if (buflen <= plen)
1607         strcpy (p, buf);
1608       else
1609         {
1610           /* There is not enough space for the translation - store it
1611              in the overflow_space else and mark that in the mapped
1612              array.  Because we expect that this won't happen too
1613              often, we use a simple linked list.  */
1614           os = (overflow_space_s *) xmalloc (sizeof *os + buflen);
1615           if (os)
1616             {
1617               os->idx = idx;
1618               strcpy (os->d, buf);
1619               os->next = domain->overflow_space;
1620               domain->overflow_space = os;
1621               p = os->d;
1622             }
1623           else
1624             p = (char *) "ERROR in GETTEXT MALLOC";
1625         }
1626       xfree (buf);
1627     }
1628   else if (domain->mapped[idx] == 2)
1629     {
1630       /* We need to get the string from the overflow_space.  */
1631       for (os=domain->overflow_space; os; os = os->next)
1632         if (os->idx == idx)
1633           return (const char*) os->d;
1634       p = (char *) "ERROR in GETTEXT\n";
1635     }
1636   return (const char*) p;
1637 }
1638
1639 \f
1640
1641 /* The domain we use.  We only support one domain at this point.  This
1642    is why this implementation can not be shared.  Bindtextdomain and
1643    dgettext will simply cheat and always use this one domain.  */
1644 static struct loaded_domain *the_domain;
1645
1646 \f
1647 /* Specify that the DOMAINNAME message catalog will be found
1648    in DIRNAME rather than in the system locale data base.  */
1649 char *
1650 bindtextdomain (const char *domainname, const char *dirname)
1651 {
1652   struct loaded_domain *domain = NULL;
1653   const char *catval_full;
1654   char *catval;
1655   char *fname;
1656
1657   /* DOMAINNAME is ignored.  We only support one domain.  */
1658
1659   /* DIRNAME is "$INSTALLDIR\share\locale".  */
1660
1661   /* First found out the category value.  */
1662   catval = NULL;
1663   catval_full = _nl_locale_name (LC_MESSAGES, "LC_MESSAGES");
1664
1665   /* Normally, we would have to loop over all returned locales, and
1666      search for the right file.  See gettext intl/dcigettext.c for all
1667      the gory details.  Here, we only support the basic category, and
1668      ignore everything else.  */
1669   if (catval_full)
1670     {
1671       char *p;
1672
1673       catval = (char *)xmalloc (strlen (catval_full) + 1);
1674       if (catval)
1675         {
1676           strcpy (catval, catval_full);
1677           p = strchr (catval, '_');
1678           if (p)
1679             *p = '\0';
1680         }
1681     }
1682   if (!catval)
1683     return NULL;
1684
1685   /* Now build the filename string.  The complete filename is this:
1686      DIRNAME + \ + CATVAL + \LC_MESSAGES\ + DOMAINNAME + .mo  */
1687   {
1688     int len = strlen (dirname) + 1 + strlen (catval) + 13
1689       + strlen (domainname) + 3 + 1;
1690     char *p;
1691
1692     fname = (char*) xmalloc (len);
1693     if (!fname)
1694       {
1695         xfree (catval);
1696         return NULL;
1697       }
1698
1699     p = fname;
1700     strcpy (p, dirname);
1701     p += strlen (dirname);
1702     *(p++) = '\\';
1703     strcpy (p, catval);
1704     p += strlen (catval);
1705     strcpy (p, "\\LC_MESSAGES\\");
1706     p += 13;
1707     strcpy (p, domainname);
1708     p += strlen (domainname);
1709     strcpy (p, ".mo");
1710   }
1711
1712   domain = load_domain (fname);
1713   xfree (catval);
1714   xfree (fname);
1715
1716   /* We should not be invoked twice, but this is how you would do
1717      it if it happened.  */
1718   if (the_domain)
1719     free_domain (the_domain);
1720   the_domain = domain;
1721
1722   /* For historic reasoins we are not allowed to return a const char*. */
1723   return (char*)dirname;
1724 }
1725
1726 static const char *
1727 internal_gettext (const char *msgid, int utf8)
1728 {
1729   struct loaded_domain *domain;
1730   size_t act = 0;
1731   size_t top, bottom;
1732
1733   if (!(domain = the_domain))
1734     goto not_found;
1735
1736   /* Locate the MSGID and its translation.  */
1737   if (domain->hash_size > 2 && domain->hash_tab)
1738     {
1739       /* Use the hashing table.  */
1740       u32 len = strlen (msgid);
1741       u32 hash_val = hash_string (msgid);
1742       u32 idx = hash_val % domain->hash_size;
1743       u32 incr = 1 + (hash_val % (domain->hash_size - 2));
1744       u32 nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);
1745
1746       if (!nstr)
1747         /* Hash table entry is empty.  */
1748         goto not_found;
1749
1750       if (SWAPIT (domain->must_swap,
1751                   domain->orig_tab[nstr - 1].length) == len
1752           && !strcmp (msgid,
1753                       domain->data
1754                       + SWAPIT (domain->must_swap,
1755                                 domain->orig_tab[nstr - 1].offset)))
1756         return get_string (domain, nstr - 1, utf8);
1757
1758       for(;;)
1759         {
1760           if (idx >= domain->hash_size - incr)
1761             idx -= domain->hash_size - incr;
1762           else
1763             idx += incr;
1764
1765           nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);
1766           if (!nstr)
1767             /* Hash table entry is empty.  */
1768             goto not_found;
1769
1770           if (SWAPIT (domain->must_swap,
1771                       domain->orig_tab[nstr - 1].length) == len
1772               && !strcmp (msgid,
1773                           domain->data
1774                           + SWAPIT (domain->must_swap,
1775                                     domain->orig_tab[nstr - 1].offset)))
1776             return get_string (domain, nstr-1, utf8);
1777         }
1778         /* NOTREACHED */
1779     }
1780
1781   /* Now we try the default method: binary search in the sorted array
1782      of messages.  */
1783   bottom = 0;
1784   top = domain->nstrings;
1785   while (bottom < top)
1786     {
1787       int cmp_val;
1788
1789       act = (bottom + top) / 2;
1790       cmp_val = strcmp(msgid, domain->data
1791                        + SWAPIT (domain->must_swap,
1792                                  domain->orig_tab[act].offset));
1793       if (cmp_val < 0)
1794         top = act;
1795       else if (cmp_val > 0)
1796         bottom = act + 1;
1797       else
1798         return get_string (domain, act, utf8);
1799     }
1800  not_found:
1801   return msgid;
1802 }
1803
1804 /** Get the localized string for msgid in the native 8 bit codepage. */
1805 const char *
1806 gettext (const char *msgid)
1807 {
1808   return internal_gettext (msgid, 0);
1809 }
1810
1811 /** Get the localized string for msgid as utf8 encoded value. */
1812 const char *
1813 utf8_gettext (const char *msgid)
1814 {
1815   return internal_gettext (msgid, 1);
1816 }
1817
1818
1819 char *
1820 textdomain (const char *domainname)
1821 {
1822   /* For now, support only one domain.  */
1823   return (char*)domainname;
1824 }
1825
1826 char *
1827 dgettext (const char *domainname, const char *msgid)
1828 {
1829   (void)domainname;
1830
1831   /* For now, support only one domain.  */
1832   return (char*)gettext (msgid);
1833 }
1834
1835 /* Return the locale name as used by gettext.  The return value will
1836    never be NULL. */
1837 const char *
1838 gettext_localename (void)
1839 {
1840   const char *s;
1841
1842   s = _nl_locale_name (LC_MESSAGES, "LC_MESSAGES");
1843   return s? s:"";
1844 }