malloc -> xmalloc
[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   lcid = get_ol_ui_language ();
795
796   if (!lcid)
797     {
798       /* Use native Win32 API locale ID.  */
799       lcid = GetThreadLocale ();
800     }
801
802   /* Strip off the sorting rules, keep only the language part.  */
803   langid = LANGIDFROMLCID (lcid);
804
805   /* Split into language and territory part.  */
806   primary = PRIMARYLANGID (langid);
807   sub = SUBLANGID (langid);
808
809   /* Dispatch on language.
810      See also http://www.unicode.org/unicode/onlinedat/languages.html .
811      For details about languages, see http://www.ethnologue.com/ .  */
812   switch (primary)
813     {
814     case LANG_AFRIKAANS: return "af_ZA";
815     case LANG_ALBANIAN: return "sq_AL";
816     case LANG_AMHARIC: return "am_ET";
817     case LANG_ARABIC:
818       switch (sub)
819         {
820         case SUBLANG_ARABIC_SAUDI_ARABIA: return "ar_SA";
821         case SUBLANG_ARABIC_IRAQ: return "ar_IQ";
822         case SUBLANG_ARABIC_EGYPT: return "ar_EG";
823         case SUBLANG_ARABIC_LIBYA: return "ar_LY";
824         case SUBLANG_ARABIC_ALGERIA: return "ar_DZ";
825         case SUBLANG_ARABIC_MOROCCO: return "ar_MA";
826         case SUBLANG_ARABIC_TUNISIA: return "ar_TN";
827         case SUBLANG_ARABIC_OMAN: return "ar_OM";
828         case SUBLANG_ARABIC_YEMEN: return "ar_YE";
829         case SUBLANG_ARABIC_SYRIA: return "ar_SY";
830         case SUBLANG_ARABIC_JORDAN: return "ar_JO";
831         case SUBLANG_ARABIC_LEBANON: return "ar_LB";
832         case SUBLANG_ARABIC_KUWAIT: return "ar_KW";
833         case SUBLANG_ARABIC_UAE: return "ar_AE";
834         case SUBLANG_ARABIC_BAHRAIN: return "ar_BH";
835         case SUBLANG_ARABIC_QATAR: return "ar_QA";
836         }
837       return "ar";
838     case LANG_ARMENIAN: return "hy_AM";
839     case LANG_ASSAMESE: return "as_IN";
840     case LANG_AZERI:
841       switch (sub)
842         {
843         /* FIXME: Adjust this when Azerbaijani locales appear on Unix.  */
844         case SUBLANG_AZERI_LATIN: return "az_AZ@latin";
845         case SUBLANG_AZERI_CYRILLIC: return "az_AZ@cyrillic";
846         }
847       return "az";
848     case LANG_BASQUE:
849       return "eu"; /* Ambiguous: could be "eu_ES" or "eu_FR".  */
850     case LANG_BELARUSIAN: return "be_BY";
851     case LANG_BENGALI:
852       switch (sub)
853         {
854         case SUBLANG_BENGALI_INDIA: return "bn_IN";
855         case SUBLANG_BENGALI_BANGLADESH: return "bn_BD";
856         }
857       return "bn";
858     case LANG_BULGARIAN: return "bg_BG";
859     case LANG_BURMESE: return "my_MM";
860     case LANG_CAMBODIAN: return "km_KH";
861     case LANG_CATALAN: return "ca_ES";
862     case LANG_CHEROKEE: return "chr_US";
863     case LANG_CHINESE:
864       switch (sub)
865         {
866         case SUBLANG_CHINESE_TRADITIONAL: return "zh_TW";
867         case SUBLANG_CHINESE_SIMPLIFIED: return "zh_CN";
868         case SUBLANG_CHINESE_HONGKONG: return "zh_HK";
869         case SUBLANG_CHINESE_SINGAPORE: return "zh_SG";
870         case SUBLANG_CHINESE_MACAU: return "zh_MO";
871         }
872       return "zh";
873     case LANG_CROATIAN:         /* LANG_CROATIAN == LANG_SERBIAN
874                                  * What used to be called Serbo-Croatian
875                                  * should really now be two separate
876                                  * languages because of political reasons.
877                                  * (Says tml, who knows nothing about Serbian
878                                  * or Croatian.)
879                                  * (I can feel those flames coming already.)
880                                  */
881       switch (sub)
882         {
883         case SUBLANG_DEFAULT: return "hr_HR";
884         case SUBLANG_SERBIAN_LATIN: return "sr_CS";
885         case SUBLANG_SERBIAN_CYRILLIC: return "sr_CS@cyrillic";
886         }
887       return "hr";
888     case LANG_CZECH: return "cs_CZ";
889     case LANG_DANISH: return "da_DK";
890     case LANG_DIVEHI: return "div_MV";
891     case LANG_DUTCH:
892       switch (sub)
893         {
894         case SUBLANG_DUTCH: return "nl_NL";
895         case SUBLANG_DUTCH_BELGIAN: /* FLEMISH, VLAAMS */ return "nl_BE";
896         }
897       return "nl";
898     case LANG_EDO: return "bin_NG";
899     case LANG_ENGLISH:
900       switch (sub)
901         {
902         /* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought
903          * English was the language spoken in England.
904          * Oh well.
905          */
906         case SUBLANG_ENGLISH_US: return "en_US";
907         case SUBLANG_ENGLISH_UK: return "en_GB";
908         case SUBLANG_ENGLISH_AUS: return "en_AU";
909         case SUBLANG_ENGLISH_CAN: return "en_CA";
910         case SUBLANG_ENGLISH_NZ: return "en_NZ";
911         case SUBLANG_ENGLISH_EIRE: return "en_IE";
912         case SUBLANG_ENGLISH_SOUTH_AFRICA: return "en_ZA";
913         case SUBLANG_ENGLISH_JAMAICA: return "en_JM";
914         case SUBLANG_ENGLISH_CARIBBEAN: return "en_GD"; /* Grenada? */
915         case SUBLANG_ENGLISH_BELIZE: return "en_BZ";
916         case SUBLANG_ENGLISH_TRINIDAD: return "en_TT";
917         case SUBLANG_ENGLISH_ZIMBABWE: return "en_ZW";
918         case SUBLANG_ENGLISH_PHILIPPINES: return "en_PH";
919         case SUBLANG_ENGLISH_INDONESIA: return "en_ID";
920         case SUBLANG_ENGLISH_HONGKONG: return "en_HK";
921         case SUBLANG_ENGLISH_INDIA: return "en_IN";
922         case SUBLANG_ENGLISH_MALAYSIA: return "en_MY";
923         case SUBLANG_ENGLISH_SINGAPORE: return "en_SG";
924         }
925       return "en";
926     case LANG_ESTONIAN: return "et_EE";
927     case LANG_FAEROESE: return "fo_FO";
928     case LANG_FARSI: return "fa_IR";
929     case LANG_FINNISH: return "fi_FI";
930     case LANG_FRENCH:
931       switch (sub)
932         {
933         case SUBLANG_FRENCH: return "fr_FR";
934         case SUBLANG_FRENCH_BELGIAN: /* WALLOON */ return "fr_BE";
935         case SUBLANG_FRENCH_CANADIAN: return "fr_CA";
936         case SUBLANG_FRENCH_SWISS: return "fr_CH";
937         case SUBLANG_FRENCH_LUXEMBOURG: return "fr_LU";
938         case SUBLANG_FRENCH_MONACO: return "fr_MC";
939         case SUBLANG_FRENCH_WESTINDIES: return "fr"; /* Caribbean? */
940         case SUBLANG_FRENCH_REUNION: return "fr_RE";
941         case SUBLANG_FRENCH_CONGO: return "fr_CG";
942         case SUBLANG_FRENCH_SENEGAL: return "fr_SN";
943         case SUBLANG_FRENCH_CAMEROON: return "fr_CM";
944         case SUBLANG_FRENCH_COTEDIVOIRE: return "fr_CI";
945         case SUBLANG_FRENCH_MALI: return "fr_ML";
946         case SUBLANG_FRENCH_MOROCCO: return "fr_MA";
947         case SUBLANG_FRENCH_HAITI: return "fr_HT";
948         }
949       return "fr";
950     case LANG_FRISIAN: return "fy_NL";
951     case LANG_FULFULDE: return "ful_NG";
952     case LANG_GAELIC:
953       switch (sub)
954         {
955         case 0x01: /* SCOTTISH */ return "gd_GB";
956         case 0x02: /* IRISH */ return "ga_IE";
957         }
958       return "C";
959     case LANG_GALICIAN: return "gl_ES";
960     case LANG_GEORGIAN: return "ka_GE";
961     case LANG_GERMAN:
962       switch (sub)
963         {
964         case SUBLANG_GERMAN: return "de_DE";
965         case SUBLANG_GERMAN_SWISS: return "de_CH";
966         case SUBLANG_GERMAN_AUSTRIAN: return "de_AT";
967         case SUBLANG_GERMAN_LUXEMBOURG: return "de_LU";
968         case SUBLANG_GERMAN_LIECHTENSTEIN: return "de_LI";
969         }
970       return "de";
971     case LANG_GREEK: return "el_GR";
972     case LANG_GUARANI: return "gn_PY";
973     case LANG_GUJARATI: return "gu_IN";
974     case LANG_HAUSA: return "ha_NG";
975     case LANG_HAWAIIAN:
976       /* FIXME: Do they mean Hawaiian ("haw_US", 1000 speakers)
977          or Hawaii Creole English ("cpe_US", 600000 speakers)?  */
978       return "cpe_US";
979     case LANG_HEBREW: return "he_IL";
980     case LANG_HINDI: return "hi_IN";
981     case LANG_HUNGARIAN: return "hu_HU";
982     case LANG_IBIBIO: return "nic_NG";
983     case LANG_ICELANDIC: return "is_IS";
984     case LANG_IGBO: return "ibo_NG";
985     case LANG_INDONESIAN: return "id_ID";
986     case LANG_INUKTITUT: return "iu_CA";
987     case LANG_ITALIAN:
988       switch (sub)
989         {
990         case SUBLANG_ITALIAN: return "it_IT";
991         case SUBLANG_ITALIAN_SWISS: return "it_CH";
992         }
993       return "it";
994     case LANG_JAPANESE: return "ja_JP";
995     case LANG_KANNADA: return "kn_IN";
996     case LANG_KANURI: return "kau_NG";
997     case LANG_KASHMIRI:
998       switch (sub)
999         {
1000         case SUBLANG_DEFAULT: return "ks_PK";
1001         case SUBLANG_KASHMIRI_INDIA: return "ks_IN";
1002         }
1003       return "ks";
1004     case LANG_KAZAK: return "kk_KZ";
1005     case LANG_KONKANI:
1006       /* FIXME: Adjust this when such locales appear on Unix.  */
1007       return "kok_IN";
1008     case LANG_KOREAN: return "ko_KR";
1009     case LANG_KYRGYZ: return "ky_KG";
1010     case LANG_LAO: return "lo_LA";
1011     case LANG_LATIN: return "la_VA";
1012     case LANG_LATVIAN: return "lv_LV";
1013     case LANG_LITHUANIAN: return "lt_LT";
1014     case LANG_MACEDONIAN: return "mk_MK";
1015     case LANG_MALAY:
1016       switch (sub)
1017         {
1018         case SUBLANG_MALAY_MALAYSIA: return "ms_MY";
1019         case SUBLANG_MALAY_BRUNEI_DARUSSALAM: return "ms_BN";
1020         }
1021       return "ms";
1022     case LANG_MALAYALAM: return "ml_IN";
1023     case LANG_MALTESE: return "mt_MT";
1024     case LANG_MANIPURI:
1025       /* FIXME: Adjust this when such locales appear on Unix.  */
1026       return "mni_IN";
1027     case LANG_MARATHI: return "mr_IN";
1028     case LANG_MONGOLIAN:
1029       return "mn"; /* Ambiguous: could be "mn_CN" or "mn_MN".  */
1030     case LANG_NEPALI:
1031       switch (sub)
1032         {
1033         case SUBLANG_DEFAULT: return "ne_NP";
1034         case SUBLANG_NEPALI_INDIA: return "ne_IN";
1035         }
1036       return "ne";
1037     case LANG_NORWEGIAN:
1038       switch (sub)
1039         {
1040         case SUBLANG_NORWEGIAN_BOKMAL: return "no_NO";
1041         case SUBLANG_NORWEGIAN_NYNORSK: return "nn_NO";
1042         }
1043       return "no";
1044     case LANG_ORIYA: return "or_IN";
1045     case LANG_OROMO: return "om_ET";
1046     case LANG_PAPIAMENTU: return "pap_AN";
1047     case LANG_PASHTO:
1048       return "ps"; /* Ambiguous: could be "ps_PK" or "ps_AF".  */
1049     case LANG_POLISH: return "pl_PL";
1050     case LANG_PORTUGUESE:
1051       switch (sub)
1052         {
1053         case SUBLANG_PORTUGUESE: return "pt_PT";
1054         /* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT.
1055            Same phenomenon as SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. */
1056         case SUBLANG_PORTUGUESE_BRAZILIAN: return "pt_BR";
1057         }
1058       return "pt";
1059     case LANG_PUNJABI:
1060       switch (sub)
1061         {
1062         case SUBLANG_PUNJABI_INDIA: return "pa_IN"; /* Gurmukhi script */
1063         }
1064       return "pa";
1065     case LANG_RHAETO_ROMANCE: return "rm_CH";
1066     case LANG_ROMANIAN:
1067       switch (sub)
1068         {
1069         case SUBLANG_ROMANIAN_ROMANIA: return "ro_RO";
1070         }
1071       return "ro";
1072     case LANG_RUSSIAN:
1073       return "ru"; /* Ambiguous: could be "ru_RU" or "ru_UA" or "ru_MD".  */
1074     case LANG_SAAMI: /* actually Northern Sami */ return "se_NO";
1075     case LANG_SANSKRIT: return "sa_IN";
1076     case LANG_SINDHI:
1077       switch (sub)
1078         {
1079         case SUBLANG_SINDHI_INDIA: return "sd_IN";
1080         case SUBLANG_SINDHI_PAKISTAN: return "sd_PK";
1081         }
1082       return "sd";
1083     case LANG_SINHALESE: return "si_LK";
1084     case LANG_SLOVAK: return "sk_SK";
1085     case LANG_SLOVENIAN: return "sl_SI";
1086     case LANG_SOMALI: return "so_SO";
1087     case LANG_SORBIAN:
1088       /* FIXME: Adjust this when such locales appear on Unix.  */
1089       return "wen_DE";
1090     case LANG_SPANISH:
1091       switch (sub)
1092         {
1093         case SUBLANG_SPANISH: return "es_ES";
1094         case SUBLANG_SPANISH_MEXICAN: return "es_MX";
1095         case SUBLANG_SPANISH_MODERN:
1096           return "es_ES@modern";        /* not seen on Unix */
1097         case SUBLANG_SPANISH_GUATEMALA: return "es_GT";
1098         case SUBLANG_SPANISH_COSTA_RICA: return "es_CR";
1099         case SUBLANG_SPANISH_PANAMA: return "es_PA";
1100         case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: return "es_DO";
1101         case SUBLANG_SPANISH_VENEZUELA: return "es_VE";
1102         case SUBLANG_SPANISH_COLOMBIA: return "es_CO";
1103         case SUBLANG_SPANISH_PERU: return "es_PE";
1104         case SUBLANG_SPANISH_ARGENTINA: return "es_AR";
1105         case SUBLANG_SPANISH_ECUADOR: return "es_EC";
1106         case SUBLANG_SPANISH_CHILE: return "es_CL";
1107         case SUBLANG_SPANISH_URUGUAY: return "es_UY";
1108         case SUBLANG_SPANISH_PARAGUAY: return "es_PY";
1109         case SUBLANG_SPANISH_BOLIVIA: return "es_BO";
1110         case SUBLANG_SPANISH_EL_SALVADOR: return "es_SV";
1111         case SUBLANG_SPANISH_HONDURAS: return "es_HN";
1112         case SUBLANG_SPANISH_NICARAGUA: return "es_NI";
1113         case SUBLANG_SPANISH_PUERTO_RICO: return "es_PR";
1114         }
1115       return "es";
1116     case LANG_SUTU: return "bnt_TZ"; /* or "st_LS" or "nso_ZA"? */
1117     case LANG_SWAHILI: return "sw_KE";
1118     case LANG_SWEDISH:
1119       switch (sub)
1120         {
1121         case SUBLANG_DEFAULT: return "sv_SE";
1122         case SUBLANG_SWEDISH_FINLAND: return "sv_FI";
1123         }
1124       return "sv";
1125     case LANG_SYRIAC: return "syr_TR"; /* An extinct language.  */
1126     case LANG_TAGALOG: return "tl_PH";
1127     case LANG_TAJIK: return "tg_TJ";
1128     case LANG_TAMAZIGHT:
1129       switch (sub)
1130         {
1131         /* FIXME: Adjust this when Tamazight locales appear on Unix.  */
1132         case SUBLANG_TAMAZIGHT_ARABIC: return "ber_MA@arabic";
1133         case SUBLANG_TAMAZIGHT_LATIN: return "ber_MA@latin";
1134         }
1135       return "ber_MA";
1136     case LANG_TAMIL:
1137       return "ta"; /* Ambiguous: could be "ta_IN" or "ta_LK" or "ta_SG".  */
1138     case LANG_TATAR: return "tt_RU";
1139     case LANG_TELUGU: return "te_IN";
1140     case LANG_THAI: return "th_TH";
1141     case LANG_TIBETAN: return "bo_CN";
1142     case LANG_TIGRINYA:
1143       switch (sub)
1144         {
1145         case SUBLANG_TIGRINYA_ETHIOPIA: return "ti_ET";
1146         case SUBLANG_TIGRINYA_ERITREA: return "ti_ER";
1147         }
1148       return "ti";
1149     case LANG_TSONGA: return "ts_ZA";
1150     case LANG_TSWANA: return "tn_BW";
1151     case LANG_TURKISH: return "tr_TR";
1152     case LANG_TURKMEN: return "tk_TM";
1153     case LANG_UKRAINIAN: return "uk_UA";
1154     case LANG_URDU:
1155       switch (sub)
1156         {
1157         case SUBLANG_URDU_PAKISTAN: return "ur_PK";
1158         case SUBLANG_URDU_INDIA: return "ur_IN";
1159         }
1160       return "ur";
1161     case LANG_UZBEK:
1162       switch (sub)
1163         {
1164         case SUBLANG_UZBEK_LATIN: return "uz_UZ";
1165         case SUBLANG_UZBEK_CYRILLIC: return "uz_UZ@cyrillic";
1166         }
1167       return "uz";
1168     case LANG_VENDA:
1169       /* FIXME: It's not clear whether Venda has the ISO 639-2 two-letter code
1170          "ve" or not.
1171          http://www.loc.gov/standards/iso639-2/englangn.html has it, but
1172          http://lcweb.loc.gov/standards/iso639-2/codechanges.html doesn't,  */
1173       return "ven_ZA"; /* or "ve_ZA"? */
1174     case LANG_VIETNAMESE: return "vi_VN";
1175     case LANG_WELSH: return "cy_GB";
1176     case LANG_XHOSA: return "xh_ZA";
1177     case LANG_YI: return "sit_CN";
1178     case LANG_YIDDISH: return "yi_IL";
1179     case LANG_YORUBA: return "yo_NG";
1180     case LANG_ZULU: return "zu_ZA";
1181     default: return "C";
1182     }
1183
1184 #endif /* HAVE_W32_SYSTEM */
1185 }
1186
1187 /* localname.c from gettext END.  */
1188 \f
1189 /* Support functions.  */
1190
1191 typedef uint32_t u32;
1192 typedef unsigned long ulong;
1193
1194 static __inline__ u32
1195 do_swap_u32 (u32 i)
1196 {
1197   return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
1198 }
1199
1200 #define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data))
1201
1202
1203 /* We assume to have `unsigned long int' value with at least 32 bits.  */
1204 #define HASHWORDBITS 32
1205
1206 /* The so called `hashpjw' function by P.J. Weinberger
1207    [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
1208    1986, 1987 Bell Telephone Laboratories, Inc.]  */
1209
1210 static __inline__ ulong
1211 hash_string( const char *str_param )
1212 {
1213     unsigned long int hval, g;
1214     const char *str = str_param;
1215
1216     hval = 0;
1217     while (*str != '\0')
1218     {
1219         hval <<= 4;
1220         hval += (unsigned long int) *str++;
1221         g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
1222         if (g != 0)
1223         {
1224           hval ^= g >> (HASHWORDBITS - 8);
1225           hval ^= g;
1226         }
1227     }
1228     return hval;
1229 }
1230
1231 \f
1232 /* Generic message catalog and gettext stuff.  */
1233
1234 /* The magic number of the GNU message catalog format.  */
1235 #define MAGIC         0x950412de
1236 #define MAGIC_SWAPPED 0xde120495
1237
1238 /* Revision number of the currently used .mo (binary) file format.  */
1239 #define MO_REVISION_NUMBER 0
1240
1241 /* Header for binary .mo file format.  */
1242 struct mo_file_header
1243 {
1244   /* The magic number.  */
1245   u32 magic;
1246   /* The revision number of the file format.  */
1247   u32 revision;
1248   /* The number of strings pairs.  */
1249   u32 nstrings;
1250   /* Offset of table with start offsets of original strings.  */
1251   u32 orig_tab_offset;
1252   /* Offset of table with start offsets of translation strings.  */
1253   u32 trans_tab_offset;
1254   /* Size of hashing table.  */
1255   u32 hash_tab_size;
1256   /* Offset of first hashing entry.  */
1257   u32 hash_tab_offset;
1258 };
1259
1260 struct string_desc
1261 {
1262   /* Length of addressed string.  */
1263   u32 length;
1264   /* Offset of string in file.  */
1265   u32 offset;
1266 };
1267
1268
1269 struct overflow_space_s
1270 {
1271   struct overflow_space_s *next;
1272   u32 idx;
1273   char d[1];
1274 };
1275
1276 struct loaded_domain
1277 {
1278   char *data;
1279   int must_swap;
1280   u32 nstrings;
1281   char *mapped;  /* 0 = not yet mapped, 1 = mapped,
1282                     2 = mapped to
1283                     overflow space */
1284   struct overflow_space_s *overflow_space;
1285   struct string_desc *orig_tab;
1286   struct string_desc *trans_tab;
1287   u32 hash_size;
1288   u32 *hash_tab;
1289 };
1290
1291 \f
1292 /* Free the domain data.  */
1293 static void
1294 free_domain (struct loaded_domain *domain)
1295 {
1296   struct overflow_space_s *os, *os2;
1297   xfree (domain->data);
1298   xfree (domain->mapped);
1299   for (os = domain->overflow_space; os; os = os2)
1300     {
1301       os2 = os->next;
1302       xfree (os);
1303     }
1304   xfree (domain);
1305 }
1306
1307
1308 /* The gettext implementation; support functions.  */
1309 static struct loaded_domain *
1310 load_domain (const char *filename)
1311 {
1312   FILE *fp;
1313   size_t size;
1314   struct stat st;
1315   struct mo_file_header *data = NULL;
1316   struct loaded_domain *domain = NULL;
1317   size_t to_read;
1318   char *read_ptr;
1319
1320   fp = fopen (filename, "rb");
1321   if (!fp)
1322     return NULL;
1323
1324   /* Determine the file size.  */
1325   if (fstat (fileno (fp), &st)
1326       || (size = (size_t) st.st_size) != st.st_size
1327       || size < sizeof (struct mo_file_header))
1328     {
1329       fclose (fp);
1330       return NULL;
1331     }
1332
1333   data = (mo_file_header*) xmalloc (size);
1334   if (!data)
1335     {
1336       fclose (fp);
1337       return NULL;
1338     }
1339
1340   to_read = size;
1341   read_ptr = (char *) data;
1342   do
1343     {
1344       long int nb = fread (read_ptr, 1, to_read, fp);
1345       if (nb < to_read)
1346         {
1347           fclose (fp);
1348           xfree (data);
1349           return NULL;
1350         }
1351       read_ptr += nb;
1352       to_read -= nb;
1353     }
1354   while (to_read > 0);
1355   fclose (fp);
1356
1357   /* Using the magic number we can test whether it really is a message
1358      catalog file.  */
1359   if (data->magic != MAGIC && data->magic != MAGIC_SWAPPED)
1360     {
1361       /* The magic number is wrong: not a message catalog file.  */
1362       xfree (data);
1363       return NULL;
1364     }
1365
1366   domain = (loaded_domain *) xcalloc (1, sizeof *domain);
1367   if (!domain)
1368     {
1369       xfree (data);
1370       return NULL;
1371     }
1372   domain->data = (char *) data;
1373   domain->must_swap = data->magic != MAGIC;
1374
1375   /* Fill in the information about the available tables.  */
1376   switch (SWAPIT (domain->must_swap, data->revision))
1377     {
1378     case 0:
1379
1380       domain->nstrings = SWAPIT (domain->must_swap, data->nstrings);
1381       domain->orig_tab = (struct string_desc *)
1382         ((char *) data + SWAPIT (domain->must_swap, data->orig_tab_offset));
1383       domain->trans_tab = (struct string_desc *)
1384         ((char *) data + SWAPIT (domain->must_swap, data->trans_tab_offset));
1385       domain->hash_size = SWAPIT (domain->must_swap, data->hash_tab_size);
1386       domain->hash_tab = (u32 *)
1387         ((char *) data + SWAPIT (domain->must_swap, data->hash_tab_offset));
1388       break;
1389
1390     default:
1391       /* This is an invalid revision.   */
1392       xfree (data);
1393       xfree (domain);
1394       return NULL;
1395     }
1396
1397   /* Allocate an array to keep track of code page mappings.  */
1398   domain->mapped = (char *) xcalloc (1, domain->nstrings);
1399   if (!domain->mapped)
1400     {
1401       xfree (data);
1402       xfree (domain);
1403       return NULL;
1404     }
1405
1406   return domain;
1407 }
1408
1409
1410 /* Return a malloced string encoded in UTF-8 from the wide char input
1411    string STRING.  Caller must free this value. On failure returns
1412    NULL; caller may use GetLastError to get the actual error number.
1413    The result of calling this function with STRING set to NULL is not
1414    defined. */
1415 static char *
1416 wchar_to_native (const wchar_t *string)
1417 {
1418   int n;
1419   char *result;
1420
1421   n = WideCharToMultiByte (CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
1422   if (n < 0)
1423     return NULL;
1424
1425   result = (char*) xmalloc (n+1);
1426   if (!result)
1427     return NULL;
1428
1429   n = WideCharToMultiByte (CP_ACP, 0, string, -1, result, n, NULL, NULL);
1430   if (n < 0)
1431     {
1432       xfree (result);
1433       return NULL;
1434     }
1435   return result;
1436 }
1437
1438
1439 static wchar_t *
1440 native_to_wchar (const char *string)
1441 {
1442   int n;
1443   wchar_t *result;
1444
1445   n = MultiByteToWideChar (CP_ACP, 0, string, -1, NULL, 0);
1446   if (n < 0)
1447     return NULL;
1448
1449   result = (wchar_t *) xmalloc ((n+1) * sizeof *result);
1450   if (!result)
1451     return NULL;
1452
1453   n = MultiByteToWideChar (CP_ACP, 0, string, -1, result, n);
1454   if (n < 0)
1455     {
1456       xfree (result);
1457       return NULL;
1458     }
1459   return result;
1460 }
1461
1462
1463 /* Return a malloced wide char string from an UTF-8 encoded input
1464    string STRING.  Caller must free this value. On failure returns
1465    NULL; caller may use GetLastError to get the actual error number.
1466    The result of calling this function with STRING set to NULL is not
1467    defined. */
1468 wchar_t *
1469 _utf8_to_wchar (const char *string)
1470 {
1471   int n;
1472   wchar_t *result;
1473
1474   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
1475   if (n < 0)
1476     return NULL;
1477
1478   result = (wchar_t *) xmalloc ((n+1) * sizeof *result);
1479   if (!result)
1480     return NULL;
1481
1482   n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
1483   if (n < 0)
1484     {
1485       xfree (result);
1486       return NULL;
1487     }
1488   return result;
1489 }
1490
1491
1492 /* Return a malloced string encoded in UTF-8 from the wide char input
1493    string STRING.  Caller must xfree this value. On failure returns
1494    NULL; caller may use GetLastError to get the actual error number.
1495    The result of calling this function with STRING set to NULL is not
1496    defined. */
1497 char *
1498 _wchar_to_utf8 (const wchar_t *string)
1499 {
1500   int n;
1501   char *result;
1502
1503   /* Note, that CP_UTF8 is not defined in Windows versions earlier
1504      than NT.*/
1505   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
1506   if (n < 0)
1507     return NULL;
1508
1509   result = (char *) xmalloc (n+1);
1510   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
1511   if (n < 0)
1512     {
1513       xfree (result);
1514       return NULL;
1515     }
1516   return result;
1517 }
1518
1519 std::string
1520 wchar_to_utf8_string (const wchar_t *string)
1521 {
1522   std::string ret;
1523   if (!string)
1524     {
1525       return ret;
1526     }
1527
1528   const auto utf8 = wchar_to_utf8 (string);
1529   if (!utf8)
1530     {
1531       return ret;
1532     }
1533   ret = utf8;
1534
1535   xfree (utf8);
1536   return ret;
1537 }
1538
1539
1540 /* Convert UTF8 to the native codepage.  This function is guaranteed
1541    to never return NULL.  Caller must xfree the return value. */
1542 char *
1543 utf8_to_native (const char *string)
1544 {
1545   wchar_t *wstring;
1546   char *result;
1547
1548   wstring = utf8_to_wchar (string);
1549   if (!wstring)
1550     return xstrdup ("[Error: utf8_to_wchar failed]");
1551
1552   result = wchar_to_native (wstring);
1553   xfree (wstring);
1554   if (!result)
1555     result = xstrdup ("[Error: wchar_to_native failed]");
1556
1557   return result;
1558 }
1559
1560
1561 /* Convert native character set to utf-8.  This is required if we want
1562    to get an utf-8 string from a gettext translated function which
1563    internally uses utf8_to_native.  It is guaranteed that NULL is
1564    never returned.  Caller must xfree the return value. */
1565 char *
1566 native_to_utf8 (const char *string)
1567 {
1568   char *result;
1569   wchar_t *wstring;
1570
1571   wstring = native_to_wchar (string);
1572   if (!wstring)
1573     return xstrdup ("[Error: native_to_wchar failed]");
1574
1575   result = wchar_to_utf8 (wstring);
1576   xfree (wstring);
1577   if (!result)
1578     result = xstrdup ("[Error: wchar_to_utf8 failed]");
1579
1580   return result;
1581 }
1582
1583
1584
1585 static const char*
1586 get_string (struct loaded_domain *domain, u32 idx, int utf8)
1587 {
1588   struct overflow_space_s *os;
1589   char *p;
1590
1591   p = domain->data + SWAPIT (domain->must_swap, domain->trans_tab[idx].offset);
1592   if (!domain->mapped[idx])
1593     {
1594       size_t plen, buflen;
1595       char *buf;
1596
1597       domain->mapped[idx] = 1;
1598
1599       plen = strlen (p);
1600       buf = utf8 ? xstrdup (p) : utf8_to_native (p);
1601       buflen = strlen (buf);
1602       if (buflen <= plen)
1603         strcpy (p, buf);
1604       else
1605         {
1606           /* There is not enough space for the translation - store it
1607              in the overflow_space else and mark that in the mapped
1608              array.  Because we expect that this won't happen too
1609              often, we use a simple linked list.  */
1610           os = (overflow_space_s *) xmalloc (sizeof *os + buflen);
1611           if (os)
1612             {
1613               os->idx = idx;
1614               strcpy (os->d, buf);
1615               os->next = domain->overflow_space;
1616               domain->overflow_space = os;
1617               p = os->d;
1618             }
1619           else
1620             p = (char *) "ERROR in GETTEXT MALLOC";
1621         }
1622       xfree (buf);
1623     }
1624   else if (domain->mapped[idx] == 2)
1625     {
1626       /* We need to get the string from the overflow_space.  */
1627       for (os=domain->overflow_space; os; os = os->next)
1628         if (os->idx == idx)
1629           return (const char*) os->d;
1630       p = (char *) "ERROR in GETTEXT\n";
1631     }
1632   return (const char*) p;
1633 }
1634
1635 \f
1636
1637 /* The domain we use.  We only support one domain at this point.  This
1638    is why this implementation can not be shared.  Bindtextdomain and
1639    dgettext will simply cheat and always use this one domain.  */
1640 static struct loaded_domain *the_domain;
1641
1642 \f
1643 /* Specify that the DOMAINNAME message catalog will be found
1644    in DIRNAME rather than in the system locale data base.  */
1645 char *
1646 bindtextdomain (const char *domainname, const char *dirname)
1647 {
1648   struct loaded_domain *domain = NULL;
1649   const char *catval_full;
1650   char *catval;
1651   char *fname;
1652
1653   /* DOMAINNAME is ignored.  We only support one domain.  */
1654
1655   /* DIRNAME is "$INSTALLDIR\share\locale".  */
1656
1657   /* First found out the category value.  */
1658   catval = NULL;
1659   catval_full = _nl_locale_name (LC_MESSAGES, "LC_MESSAGES");
1660
1661   /* Normally, we would have to loop over all returned locales, and
1662      search for the right file.  See gettext intl/dcigettext.c for all
1663      the gory details.  Here, we only support the basic category, and
1664      ignore everything else.  */
1665   if (catval_full)
1666     {
1667       char *p;
1668
1669       catval = (char *)xmalloc (strlen (catval_full) + 1);
1670       if (catval)
1671         {
1672           strcpy (catval, catval_full);
1673           p = strchr (catval, '_');
1674           if (p)
1675             *p = '\0';
1676         }
1677     }
1678   if (!catval)
1679     return NULL;
1680
1681   /* Now build the filename string.  The complete filename is this:
1682      DIRNAME + \ + CATVAL + \LC_MESSAGES\ + DOMAINNAME + .mo  */
1683   {
1684     int len = strlen (dirname) + 1 + strlen (catval) + 13
1685       + strlen (domainname) + 3 + 1;
1686     char *p;
1687
1688     fname = (char*) xmalloc (len);
1689     if (!fname)
1690       {
1691         xfree (catval);
1692         return NULL;
1693       }
1694
1695     p = fname;
1696     strcpy (p, dirname);
1697     p += strlen (dirname);
1698     *(p++) = '\\';
1699     strcpy (p, catval);
1700     p += strlen (catval);
1701     strcpy (p, "\\LC_MESSAGES\\");
1702     p += 13;
1703     strcpy (p, domainname);
1704     p += strlen (domainname);
1705     strcpy (p, ".mo");
1706   }
1707
1708   domain = load_domain (fname);
1709   xfree (catval);
1710   xfree (fname);
1711
1712   /* We should not be invoked twice, but this is how you would do
1713      it if it happened.  */
1714   if (the_domain)
1715     free_domain (the_domain);
1716   the_domain = domain;
1717
1718   /* For historic reasoins we are not allowed to return a const char*. */
1719   return (char*)dirname;
1720 }
1721
1722 static const char *
1723 internal_gettext (const char *msgid, int utf8)
1724 {
1725   struct loaded_domain *domain;
1726   size_t act = 0;
1727   size_t top, bottom;
1728
1729   if (!(domain = the_domain))
1730     goto not_found;
1731
1732   /* Locate the MSGID and its translation.  */
1733   if (domain->hash_size > 2 && domain->hash_tab)
1734     {
1735       /* Use the hashing table.  */
1736       u32 len = strlen (msgid);
1737       u32 hash_val = hash_string (msgid);
1738       u32 idx = hash_val % domain->hash_size;
1739       u32 incr = 1 + (hash_val % (domain->hash_size - 2));
1740       u32 nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);
1741
1742       if (!nstr)
1743         /* Hash table entry is empty.  */
1744         goto not_found;
1745
1746       if (SWAPIT (domain->must_swap,
1747                   domain->orig_tab[nstr - 1].length) == len
1748           && !strcmp (msgid,
1749                       domain->data
1750                       + SWAPIT (domain->must_swap,
1751                                 domain->orig_tab[nstr - 1].offset)))
1752         return get_string (domain, nstr - 1, utf8);
1753
1754       for(;;)
1755         {
1756           if (idx >= domain->hash_size - incr)
1757             idx -= domain->hash_size - incr;
1758           else
1759             idx += incr;
1760
1761           nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);
1762           if (!nstr)
1763             /* Hash table entry is empty.  */
1764             goto not_found;
1765
1766           if (SWAPIT (domain->must_swap,
1767                       domain->orig_tab[nstr - 1].length) == len
1768               && !strcmp (msgid,
1769                           domain->data
1770                           + SWAPIT (domain->must_swap,
1771                                     domain->orig_tab[nstr - 1].offset)))
1772             return get_string (domain, nstr-1, utf8);
1773         }
1774         /* NOTREACHED */
1775     }
1776
1777   /* Now we try the default method: binary search in the sorted array
1778      of messages.  */
1779   bottom = 0;
1780   top = domain->nstrings;
1781   while (bottom < top)
1782     {
1783       int cmp_val;
1784
1785       act = (bottom + top) / 2;
1786       cmp_val = strcmp(msgid, domain->data
1787                        + SWAPIT (domain->must_swap,
1788                                  domain->orig_tab[act].offset));
1789       if (cmp_val < 0)
1790         top = act;
1791       else if (cmp_val > 0)
1792         bottom = act + 1;
1793       else
1794         return get_string (domain, act, utf8);
1795     }
1796  not_found:
1797   return msgid;
1798 }
1799
1800 /** Get the localized string for msgid in the native 8 bit codepage. */
1801 const char *
1802 gettext (const char *msgid)
1803 {
1804   return internal_gettext (msgid, 0);
1805 }
1806
1807 /** Get the localized string for msgid as utf8 encoded value. */
1808 const char *
1809 utf8_gettext (const char *msgid)
1810 {
1811   return internal_gettext (msgid, 1);
1812 }
1813
1814
1815 char *
1816 textdomain (const char *domainname)
1817 {
1818   /* For now, support only one domain.  */
1819   return (char*)domainname;
1820 }
1821
1822 char *
1823 dgettext (const char *domainname, const char *msgid)
1824 {
1825   (void)domainname;
1826
1827   /* For now, support only one domain.  */
1828   return (char*)gettext (msgid);
1829 }
1830
1831 /* Return the locale name as used by gettext.  The return value will
1832    never be NULL. */
1833 const char *
1834 gettext_localename (void)
1835 {
1836   const char *s;
1837
1838   s = _nl_locale_name (LC_MESSAGES, "LC_MESSAGES");
1839   return s? s:"";
1840 }