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