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