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