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