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