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.
5 This file is part of libgpg-error.
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.
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.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this program; if not, see <http://www.gnu.org/licenses/>.
24 #if !defined (_WIN32) && !defined (__CYGWIN32__)
25 # error This module may only be build for Windows or Cygwin32
33 #ifdef HAVE_SYS_TYPES_H
34 #include <sys/types.h>
37 #ifndef HAVE_W32CE_SYSTEM
39 #endif /*HAVE_W32CE_SYSTEM*/
43 #include "libjnlib-config.h"
47 # define jnlib_malloc(a) malloc ((a))
48 # define jnlib_calloc(a,b) calloc ((a), (b))
49 # define jnlib_free(a) free ((a))
50 # define jnlib_xstrdup(a) not_used
51 #endif /*!jnlib_malloc*/
54 #include "gpg-error.h"
56 #ifdef HAVE_W32CE_SYSTEM
57 /* Forward declaration. */
58 static wchar_t *utf8_to_wchar (const char *string, size_t length, size_t *retlen);
61 MyCreateFileA (LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwSharedMode,
62 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
63 DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
71 filename = utf8_to_wchar (lpFileName, -1, &size);
73 return INVALID_HANDLE_VALUE;
75 result = CreateFileW (filename, dwDesiredAccess, dwSharedMode,
76 lpSecurityAttributes, dwCreationDisposition,
77 dwFlagsAndAttributes, hTemplateFile);
79 err = GetLastError ();
85 #define CreateFileA MyCreateFileA
89 /* localname.c from gettext BEGIN. */
91 /* Determine the current selected locale.
92 Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
94 This program is free software; you can redistribute it and/or modify it
95 under the terms of the GNU Library General Public License as published
96 by the Free Software Foundation; either version 2, or (at your option)
99 This program is distributed in the hope that it will be useful,
100 but WITHOUT ANY WARRANTY; without even the implied warranty of
101 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
102 Library General Public License for more details.
104 You should have received a copy of the GNU Library General Public
105 License along with this program; if not, write to the Free Software
106 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
109 /* Written by Ulrich Drepper <drepper@gnu.org>, 1995. */
110 /* Win32 code written by Tor Lillqvist <tml@iki.fi>. */
111 /* Renamed _nl_locale_name, removed unsed args, removed include files,
112 non-W32 code and changed comments <wk@gnupg.org>. */
114 /* Mingw headers don't have latest language and sublanguage codes. */
115 #ifndef LANG_AFRIKAANS
116 #define LANG_AFRIKAANS 0x36
118 #ifndef LANG_ALBANIAN
119 #define LANG_ALBANIAN 0x1c
122 #define LANG_AMHARIC 0x5e
125 #define LANG_ARABIC 0x01
127 #ifndef LANG_ARMENIAN
128 #define LANG_ARMENIAN 0x2b
130 #ifndef LANG_ASSAMESE
131 #define LANG_ASSAMESE 0x4d
134 #define LANG_AZERI 0x2c
137 #define LANG_BASQUE 0x2d
139 #ifndef LANG_BELARUSIAN
140 #define LANG_BELARUSIAN 0x23
143 #define LANG_BENGALI 0x45
146 #define LANG_BURMESE 0x55
148 #ifndef LANG_CAMBODIAN
149 #define LANG_CAMBODIAN 0x53
152 #define LANG_CATALAN 0x03
154 #ifndef LANG_CHEROKEE
155 #define LANG_CHEROKEE 0x5c
158 #define LANG_DIVEHI 0x65
161 #define LANG_EDO 0x66
163 #ifndef LANG_ESTONIAN
164 #define LANG_ESTONIAN 0x25
166 #ifndef LANG_FAEROESE
167 #define LANG_FAEROESE 0x38
170 #define LANG_FARSI 0x29
173 #define LANG_FRISIAN 0x62
175 #ifndef LANG_FULFULDE
176 #define LANG_FULFULDE 0x67
179 #define LANG_GAELIC 0x3c
181 #ifndef LANG_GALICIAN
182 #define LANG_GALICIAN 0x56
184 #ifndef LANG_GEORGIAN
185 #define LANG_GEORGIAN 0x37
188 #define LANG_GUARANI 0x74
190 #ifndef LANG_GUJARATI
191 #define LANG_GUJARATI 0x47
194 #define LANG_HAUSA 0x68
196 #ifndef LANG_HAWAIIAN
197 #define LANG_HAWAIIAN 0x75
200 #define LANG_HEBREW 0x0d
203 #define LANG_HINDI 0x39
206 #define LANG_IBIBIO 0x69
209 #define LANG_IGBO 0x70
211 #ifndef LANG_INDONESIAN
212 #define LANG_INDONESIAN 0x21
214 #ifndef LANG_INUKTITUT
215 #define LANG_INUKTITUT 0x5d
218 #define LANG_KANNADA 0x4b
221 #define LANG_KANURI 0x71
223 #ifndef LANG_KASHMIRI
224 #define LANG_KASHMIRI 0x60
227 #define LANG_KAZAK 0x3f
230 #define LANG_KONKANI 0x57
233 #define LANG_KYRGYZ 0x40
236 #define LANG_LAO 0x54
239 #define LANG_LATIN 0x76
242 #define LANG_LATVIAN 0x26
244 #ifndef LANG_LITHUANIAN
245 #define LANG_LITHUANIAN 0x27
247 #ifndef LANG_MACEDONIAN
248 #define LANG_MACEDONIAN 0x2f
251 #define LANG_MALAY 0x3e
253 #ifndef LANG_MALAYALAM
254 #define LANG_MALAYALAM 0x4c
257 #define LANG_MALTESE 0x3a
259 #ifndef LANG_MANIPURI
260 #define LANG_MANIPURI 0x58
263 #define LANG_MARATHI 0x4e
265 #ifndef LANG_MONGOLIAN
266 #define LANG_MONGOLIAN 0x50
269 #define LANG_NEPALI 0x61
272 #define LANG_ORIYA 0x48
275 #define LANG_OROMO 0x72
277 #ifndef LANG_PAPIAMENTU
278 #define LANG_PAPIAMENTU 0x79
281 #define LANG_PASHTO 0x63
284 #define LANG_PUNJABI 0x46
286 #ifndef LANG_RHAETO_ROMANCE
287 #define LANG_RHAETO_ROMANCE 0x17
290 #define LANG_SAAMI 0x3b
292 #ifndef LANG_SANSKRIT
293 #define LANG_SANSKRIT 0x4f
296 #define LANG_SERBIAN 0x1a
299 #define LANG_SINDHI 0x59
301 #ifndef LANG_SINHALESE
302 #define LANG_SINHALESE 0x5b
305 #define LANG_SLOVAK 0x1b
308 #define LANG_SOMALI 0x77
311 #define LANG_SORBIAN 0x2e
314 #define LANG_SUTU 0x30
317 #define LANG_SWAHILI 0x41
320 #define LANG_SYRIAC 0x5a
323 #define LANG_TAGALOG 0x64
326 #define LANG_TAJIK 0x28
328 #ifndef LANG_TAMAZIGHT
329 #define LANG_TAMAZIGHT 0x5f
332 #define LANG_TAMIL 0x49
335 #define LANG_TATAR 0x44
338 #define LANG_TELUGU 0x4a
341 #define LANG_THAI 0x1e
344 #define LANG_TIBETAN 0x51
346 #ifndef LANG_TIGRINYA
347 #define LANG_TIGRINYA 0x73
350 #define LANG_TSONGA 0x31
353 #define LANG_TSWANA 0x32
356 #define LANG_TURKMEN 0x42
358 #ifndef LANG_UKRAINIAN
359 #define LANG_UKRAINIAN 0x22
362 #define LANG_URDU 0x20
365 #define LANG_UZBEK 0x43
368 #define LANG_VENDA 0x33
370 #ifndef LANG_VIETNAMESE
371 #define LANG_VIETNAMESE 0x2a
374 #define LANG_WELSH 0x52
377 #define LANG_XHOSA 0x34
383 #define LANG_YIDDISH 0x3d
386 #define LANG_YORUBA 0x6a
389 #define LANG_ZULU 0x35
391 #ifndef SUBLANG_ARABIC_SAUDI_ARABIA
392 #define SUBLANG_ARABIC_SAUDI_ARABIA 0x01
394 #ifndef SUBLANG_ARABIC_IRAQ
395 #define SUBLANG_ARABIC_IRAQ 0x02
397 #ifndef SUBLANG_ARABIC_EGYPT
398 #define SUBLANG_ARABIC_EGYPT 0x03
400 #ifndef SUBLANG_ARABIC_LIBYA
401 #define SUBLANG_ARABIC_LIBYA 0x04
403 #ifndef SUBLANG_ARABIC_ALGERIA
404 #define SUBLANG_ARABIC_ALGERIA 0x05
406 #ifndef SUBLANG_ARABIC_MOROCCO
407 #define SUBLANG_ARABIC_MOROCCO 0x06
409 #ifndef SUBLANG_ARABIC_TUNISIA
410 #define SUBLANG_ARABIC_TUNISIA 0x07
412 #ifndef SUBLANG_ARABIC_OMAN
413 #define SUBLANG_ARABIC_OMAN 0x08
415 #ifndef SUBLANG_ARABIC_YEMEN
416 #define SUBLANG_ARABIC_YEMEN 0x09
418 #ifndef SUBLANG_ARABIC_SYRIA
419 #define SUBLANG_ARABIC_SYRIA 0x0a
421 #ifndef SUBLANG_ARABIC_JORDAN
422 #define SUBLANG_ARABIC_JORDAN 0x0b
424 #ifndef SUBLANG_ARABIC_LEBANON
425 #define SUBLANG_ARABIC_LEBANON 0x0c
427 #ifndef SUBLANG_ARABIC_KUWAIT
428 #define SUBLANG_ARABIC_KUWAIT 0x0d
430 #ifndef SUBLANG_ARABIC_UAE
431 #define SUBLANG_ARABIC_UAE 0x0e
433 #ifndef SUBLANG_ARABIC_BAHRAIN
434 #define SUBLANG_ARABIC_BAHRAIN 0x0f
436 #ifndef SUBLANG_ARABIC_QATAR
437 #define SUBLANG_ARABIC_QATAR 0x10
439 #ifndef SUBLANG_AZERI_LATIN
440 #define SUBLANG_AZERI_LATIN 0x01
442 #ifndef SUBLANG_AZERI_CYRILLIC
443 #define SUBLANG_AZERI_CYRILLIC 0x02
445 #ifndef SUBLANG_BENGALI_INDIA
446 #define SUBLANG_BENGALI_INDIA 0x01
448 #ifndef SUBLANG_BENGALI_BANGLADESH
449 #define SUBLANG_BENGALI_BANGLADESH 0x02
451 #ifndef SUBLANG_CHINESE_MACAU
452 #define SUBLANG_CHINESE_MACAU 0x05
454 #ifndef SUBLANG_ENGLISH_SOUTH_AFRICA
455 #define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07
457 #ifndef SUBLANG_ENGLISH_JAMAICA
458 #define SUBLANG_ENGLISH_JAMAICA 0x08
460 #ifndef SUBLANG_ENGLISH_CARIBBEAN
461 #define SUBLANG_ENGLISH_CARIBBEAN 0x09
463 #ifndef SUBLANG_ENGLISH_BELIZE
464 #define SUBLANG_ENGLISH_BELIZE 0x0a
466 #ifndef SUBLANG_ENGLISH_TRINIDAD
467 #define SUBLANG_ENGLISH_TRINIDAD 0x0b
469 #ifndef SUBLANG_ENGLISH_ZIMBABWE
470 #define SUBLANG_ENGLISH_ZIMBABWE 0x0c
472 #ifndef SUBLANG_ENGLISH_PHILIPPINES
473 #define SUBLANG_ENGLISH_PHILIPPINES 0x0d
475 #ifndef SUBLANG_ENGLISH_INDONESIA
476 #define SUBLANG_ENGLISH_INDONESIA 0x0e
478 #ifndef SUBLANG_ENGLISH_HONGKONG
479 #define SUBLANG_ENGLISH_HONGKONG 0x0f
481 #ifndef SUBLANG_ENGLISH_INDIA
482 #define SUBLANG_ENGLISH_INDIA 0x10
484 #ifndef SUBLANG_ENGLISH_MALAYSIA
485 #define SUBLANG_ENGLISH_MALAYSIA 0x11
487 #ifndef SUBLANG_ENGLISH_SINGAPORE
488 #define SUBLANG_ENGLISH_SINGAPORE 0x12
490 #ifndef SUBLANG_FRENCH_LUXEMBOURG
491 #define SUBLANG_FRENCH_LUXEMBOURG 0x05
493 #ifndef SUBLANG_FRENCH_MONACO
494 #define SUBLANG_FRENCH_MONACO 0x06
496 #ifndef SUBLANG_FRENCH_WESTINDIES
497 #define SUBLANG_FRENCH_WESTINDIES 0x07
499 #ifndef SUBLANG_FRENCH_REUNION
500 #define SUBLANG_FRENCH_REUNION 0x08
502 #ifndef SUBLANG_FRENCH_CONGO
503 #define SUBLANG_FRENCH_CONGO 0x09
505 #ifndef SUBLANG_FRENCH_SENEGAL
506 #define SUBLANG_FRENCH_SENEGAL 0x0a
508 #ifndef SUBLANG_FRENCH_CAMEROON
509 #define SUBLANG_FRENCH_CAMEROON 0x0b
511 #ifndef SUBLANG_FRENCH_COTEDIVOIRE
512 #define SUBLANG_FRENCH_COTEDIVOIRE 0x0c
514 #ifndef SUBLANG_FRENCH_MALI
515 #define SUBLANG_FRENCH_MALI 0x0d
517 #ifndef SUBLANG_FRENCH_MOROCCO
518 #define SUBLANG_FRENCH_MOROCCO 0x0e
520 #ifndef SUBLANG_FRENCH_HAITI
521 #define SUBLANG_FRENCH_HAITI 0x0f
523 #ifndef SUBLANG_GERMAN_LUXEMBOURG
524 #define SUBLANG_GERMAN_LUXEMBOURG 0x04
526 #ifndef SUBLANG_GERMAN_LIECHTENSTEIN
527 #define SUBLANG_GERMAN_LIECHTENSTEIN 0x05
529 #ifndef SUBLANG_KASHMIRI_INDIA
530 #define SUBLANG_KASHMIRI_INDIA 0x02
532 #ifndef SUBLANG_MALAY_MALAYSIA
533 #define SUBLANG_MALAY_MALAYSIA 0x01
535 #ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
536 #define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02
538 #ifndef SUBLANG_NEPALI_INDIA
539 #define SUBLANG_NEPALI_INDIA 0x02
541 #ifndef SUBLANG_PUNJABI_INDIA
542 #define SUBLANG_PUNJABI_INDIA 0x01
544 #ifndef SUBLANG_ROMANIAN_ROMANIA
545 #define SUBLANG_ROMANIAN_ROMANIA 0x01
547 #ifndef SUBLANG_SERBIAN_LATIN
548 #define SUBLANG_SERBIAN_LATIN 0x02
550 #ifndef SUBLANG_SERBIAN_CYRILLIC
551 #define SUBLANG_SERBIAN_CYRILLIC 0x03
553 #ifndef SUBLANG_SINDHI_INDIA
554 #define SUBLANG_SINDHI_INDIA 0x00
556 #ifndef SUBLANG_SINDHI_PAKISTAN
557 #define SUBLANG_SINDHI_PAKISTAN 0x01
559 #ifndef SUBLANG_SPANISH_GUATEMALA
560 #define SUBLANG_SPANISH_GUATEMALA 0x04
562 #ifndef SUBLANG_SPANISH_COSTA_RICA
563 #define SUBLANG_SPANISH_COSTA_RICA 0x05
565 #ifndef SUBLANG_SPANISH_PANAMA
566 #define SUBLANG_SPANISH_PANAMA 0x06
568 #ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC
569 #define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07
571 #ifndef SUBLANG_SPANISH_VENEZUELA
572 #define SUBLANG_SPANISH_VENEZUELA 0x08
574 #ifndef SUBLANG_SPANISH_COLOMBIA
575 #define SUBLANG_SPANISH_COLOMBIA 0x09
577 #ifndef SUBLANG_SPANISH_PERU
578 #define SUBLANG_SPANISH_PERU 0x0a
580 #ifndef SUBLANG_SPANISH_ARGENTINA
581 #define SUBLANG_SPANISH_ARGENTINA 0x0b
583 #ifndef SUBLANG_SPANISH_ECUADOR
584 #define SUBLANG_SPANISH_ECUADOR 0x0c
586 #ifndef SUBLANG_SPANISH_CHILE
587 #define SUBLANG_SPANISH_CHILE 0x0d
589 #ifndef SUBLANG_SPANISH_URUGUAY
590 #define SUBLANG_SPANISH_URUGUAY 0x0e
592 #ifndef SUBLANG_SPANISH_PARAGUAY
593 #define SUBLANG_SPANISH_PARAGUAY 0x0f
595 #ifndef SUBLANG_SPANISH_BOLIVIA
596 #define SUBLANG_SPANISH_BOLIVIA 0x10
598 #ifndef SUBLANG_SPANISH_EL_SALVADOR
599 #define SUBLANG_SPANISH_EL_SALVADOR 0x11
601 #ifndef SUBLANG_SPANISH_HONDURAS
602 #define SUBLANG_SPANISH_HONDURAS 0x12
604 #ifndef SUBLANG_SPANISH_NICARAGUA
605 #define SUBLANG_SPANISH_NICARAGUA 0x13
607 #ifndef SUBLANG_SPANISH_PUERTO_RICO
608 #define SUBLANG_SPANISH_PUERTO_RICO 0x14
610 #ifndef SUBLANG_SWEDISH_FINLAND
611 #define SUBLANG_SWEDISH_FINLAND 0x02
613 #ifndef SUBLANG_TAMAZIGHT_ARABIC
614 #define SUBLANG_TAMAZIGHT_ARABIC 0x01
616 #ifndef SUBLANG_TAMAZIGHT_LATIN
617 #define SUBLANG_TAMAZIGHT_LATIN 0x02
619 #ifndef SUBLANG_TIGRINYA_ETHIOPIA
620 #define SUBLANG_TIGRINYA_ETHIOPIA 0x00
622 #ifndef SUBLANG_TIGRINYA_ERITREA
623 #define SUBLANG_TIGRINYA_ERITREA 0x01
625 #ifndef SUBLANG_URDU_PAKISTAN
626 #define SUBLANG_URDU_PAKISTAN 0x01
628 #ifndef SUBLANG_URDU_INDIA
629 #define SUBLANG_URDU_INDIA 0x02
631 #ifndef SUBLANG_UZBEK_LATIN
632 #define SUBLANG_UZBEK_LATIN 0x01
634 #ifndef SUBLANG_UZBEK_CYRILLIC
635 #define SUBLANG_UZBEK_CYRILLIC 0x02
638 /* Return an XPG style locale name
639 language[_territory[.codeset]][@modifier].
640 Don't even bother determining the codeset; it's not useful in this
641 context, because message catalogs are not specific to a single
642 codeset. The result must not be freed; it is statically
645 my_nl_locale_name (const char *categoryname)
647 #ifndef HAVE_W32CE_SYSTEM
654 /* Let the user override the system settings through environment
655 variables, as on POSIX systems. */
656 #ifndef HAVE_W32CE_SYSTEM
657 retval = getenv ("LC_ALL");
658 if (retval != NULL && retval[0] != '\0')
660 retval = getenv (categoryname);
661 if (retval != NULL && retval[0] != '\0')
663 retval = getenv ("LANG");
664 if (retval != NULL && retval[0] != '\0')
666 #endif /*!HAVE_W32CE_SYSTEM*/
668 /* Use native Win32 API locale ID. */
669 #ifdef HAVE_W32CE_SYSTEM
670 lcid = GetSystemDefaultLCID ();
672 lcid = GetThreadLocale ();
675 /* Strip off the sorting rules, keep only the language part. */
676 langid = LANGIDFROMLCID (lcid);
678 /* Split into language and territory part. */
679 primary = PRIMARYLANGID (langid);
680 sub = SUBLANGID (langid);
682 /* Dispatch on language.
683 See also http://www.unicode.org/unicode/onlinedat/languages.html .
684 For details about languages, see http://www.ethnologue.com/ . */
687 case LANG_AFRIKAANS: return "af_ZA";
688 case LANG_ALBANIAN: return "sq_AL";
689 case LANG_AMHARIC: return "am_ET";
693 case SUBLANG_ARABIC_SAUDI_ARABIA: return "ar_SA";
694 case SUBLANG_ARABIC_IRAQ: return "ar_IQ";
695 case SUBLANG_ARABIC_EGYPT: return "ar_EG";
696 case SUBLANG_ARABIC_LIBYA: return "ar_LY";
697 case SUBLANG_ARABIC_ALGERIA: return "ar_DZ";
698 case SUBLANG_ARABIC_MOROCCO: return "ar_MA";
699 case SUBLANG_ARABIC_TUNISIA: return "ar_TN";
700 case SUBLANG_ARABIC_OMAN: return "ar_OM";
701 case SUBLANG_ARABIC_YEMEN: return "ar_YE";
702 case SUBLANG_ARABIC_SYRIA: return "ar_SY";
703 case SUBLANG_ARABIC_JORDAN: return "ar_JO";
704 case SUBLANG_ARABIC_LEBANON: return "ar_LB";
705 case SUBLANG_ARABIC_KUWAIT: return "ar_KW";
706 case SUBLANG_ARABIC_UAE: return "ar_AE";
707 case SUBLANG_ARABIC_BAHRAIN: return "ar_BH";
708 case SUBLANG_ARABIC_QATAR: return "ar_QA";
711 case LANG_ARMENIAN: return "hy_AM";
712 case LANG_ASSAMESE: return "as_IN";
716 /* FIXME: Adjust this when Azerbaijani locales appear on Unix. */
717 case SUBLANG_AZERI_LATIN: return "az_AZ@latin";
718 case SUBLANG_AZERI_CYRILLIC: return "az_AZ@cyrillic";
722 return "eu"; /* Ambiguous: could be "eu_ES" or "eu_FR". */
723 case LANG_BELARUSIAN: return "be_BY";
727 case SUBLANG_BENGALI_INDIA: return "bn_IN";
728 case SUBLANG_BENGALI_BANGLADESH: return "bn_BD";
731 case LANG_BULGARIAN: return "bg_BG";
732 case LANG_BURMESE: return "my_MM";
733 case LANG_CAMBODIAN: return "km_KH";
734 case LANG_CATALAN: return "ca_ES";
735 case LANG_CHEROKEE: return "chr_US";
739 case SUBLANG_CHINESE_TRADITIONAL: return "zh_TW";
740 case SUBLANG_CHINESE_SIMPLIFIED: return "zh_CN";
741 case SUBLANG_CHINESE_HONGKONG: return "zh_HK";
742 case SUBLANG_CHINESE_SINGAPORE: return "zh_SG";
743 case SUBLANG_CHINESE_MACAU: return "zh_MO";
746 case LANG_CROATIAN: /* LANG_CROATIAN == LANG_SERBIAN
747 * What used to be called Serbo-Croatian
748 * should really now be two separate
749 * languages because of political reasons.
750 * (Says tml, who knows nothing about Serbian
752 * (I can feel those flames coming already.)
756 case SUBLANG_DEFAULT: return "hr_HR";
757 case SUBLANG_SERBIAN_LATIN: return "sr_CS";
758 case SUBLANG_SERBIAN_CYRILLIC: return "sr_CS@cyrillic";
761 case LANG_CZECH: return "cs_CZ";
762 case LANG_DANISH: return "da_DK";
763 case LANG_DIVEHI: return "div_MV";
767 case SUBLANG_DUTCH: return "nl_NL";
768 case SUBLANG_DUTCH_BELGIAN: /* FLEMISH, VLAAMS */ return "nl_BE";
771 case LANG_EDO: return "bin_NG";
775 /* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought
776 * English was the language spoken in England.
779 case SUBLANG_ENGLISH_US: return "en_US";
780 case SUBLANG_ENGLISH_UK: return "en_GB";
781 case SUBLANG_ENGLISH_AUS: return "en_AU";
782 case SUBLANG_ENGLISH_CAN: return "en_CA";
783 case SUBLANG_ENGLISH_NZ: return "en_NZ";
784 case SUBLANG_ENGLISH_EIRE: return "en_IE";
785 case SUBLANG_ENGLISH_SOUTH_AFRICA: return "en_ZA";
786 case SUBLANG_ENGLISH_JAMAICA: return "en_JM";
787 case SUBLANG_ENGLISH_CARIBBEAN: return "en_GD"; /* Grenada? */
788 case SUBLANG_ENGLISH_BELIZE: return "en_BZ";
789 case SUBLANG_ENGLISH_TRINIDAD: return "en_TT";
790 case SUBLANG_ENGLISH_ZIMBABWE: return "en_ZW";
791 case SUBLANG_ENGLISH_PHILIPPINES: return "en_PH";
792 case SUBLANG_ENGLISH_INDONESIA: return "en_ID";
793 case SUBLANG_ENGLISH_HONGKONG: return "en_HK";
794 case SUBLANG_ENGLISH_INDIA: return "en_IN";
795 case SUBLANG_ENGLISH_MALAYSIA: return "en_MY";
796 case SUBLANG_ENGLISH_SINGAPORE: return "en_SG";
799 case LANG_ESTONIAN: return "et_EE";
800 case LANG_FAEROESE: return "fo_FO";
801 case LANG_FARSI: return "fa_IR";
802 case LANG_FINNISH: return "fi_FI";
806 case SUBLANG_FRENCH: return "fr_FR";
807 case SUBLANG_FRENCH_BELGIAN: /* WALLOON */ return "fr_BE";
808 case SUBLANG_FRENCH_CANADIAN: return "fr_CA";
809 case SUBLANG_FRENCH_SWISS: return "fr_CH";
810 case SUBLANG_FRENCH_LUXEMBOURG: return "fr_LU";
811 case SUBLANG_FRENCH_MONACO: return "fr_MC";
812 case SUBLANG_FRENCH_WESTINDIES: return "fr"; /* Caribbean? */
813 case SUBLANG_FRENCH_REUNION: return "fr_RE";
814 case SUBLANG_FRENCH_CONGO: return "fr_CG";
815 case SUBLANG_FRENCH_SENEGAL: return "fr_SN";
816 case SUBLANG_FRENCH_CAMEROON: return "fr_CM";
817 case SUBLANG_FRENCH_COTEDIVOIRE: return "fr_CI";
818 case SUBLANG_FRENCH_MALI: return "fr_ML";
819 case SUBLANG_FRENCH_MOROCCO: return "fr_MA";
820 case SUBLANG_FRENCH_HAITI: return "fr_HT";
823 case LANG_FRISIAN: return "fy_NL";
824 case LANG_FULFULDE: return "ful_NG";
828 case 0x01: /* SCOTTISH */ return "gd_GB";
829 case 0x02: /* IRISH */ return "ga_IE";
832 case LANG_GALICIAN: return "gl_ES";
833 case LANG_GEORGIAN: return "ka_GE";
837 case SUBLANG_GERMAN: return "de_DE";
838 case SUBLANG_GERMAN_SWISS: return "de_CH";
839 case SUBLANG_GERMAN_AUSTRIAN: return "de_AT";
840 case SUBLANG_GERMAN_LUXEMBOURG: return "de_LU";
841 case SUBLANG_GERMAN_LIECHTENSTEIN: return "de_LI";
844 case LANG_GREEK: return "el_GR";
845 case LANG_GUARANI: return "gn_PY";
846 case LANG_GUJARATI: return "gu_IN";
847 case LANG_HAUSA: return "ha_NG";
849 /* FIXME: Do they mean Hawaiian ("haw_US", 1000 speakers)
850 or Hawaii Creole English ("cpe_US", 600000 speakers)? */
852 case LANG_HEBREW: return "he_IL";
853 case LANG_HINDI: return "hi_IN";
854 case LANG_HUNGARIAN: return "hu_HU";
855 case LANG_IBIBIO: return "nic_NG";
856 case LANG_ICELANDIC: return "is_IS";
857 case LANG_IGBO: return "ibo_NG";
858 case LANG_INDONESIAN: return "id_ID";
859 case LANG_INUKTITUT: return "iu_CA";
863 case SUBLANG_ITALIAN: return "it_IT";
864 case SUBLANG_ITALIAN_SWISS: return "it_CH";
867 case LANG_JAPANESE: return "ja_JP";
868 case LANG_KANNADA: return "kn_IN";
869 case LANG_KANURI: return "kau_NG";
873 case SUBLANG_DEFAULT: return "ks_PK";
874 case SUBLANG_KASHMIRI_INDIA: return "ks_IN";
877 case LANG_KAZAK: return "kk_KZ";
879 /* FIXME: Adjust this when such locales appear on Unix. */
881 case LANG_KOREAN: return "ko_KR";
882 case LANG_KYRGYZ: return "ky_KG";
883 case LANG_LAO: return "lo_LA";
884 case LANG_LATIN: return "la_VA";
885 case LANG_LATVIAN: return "lv_LV";
886 case LANG_LITHUANIAN: return "lt_LT";
887 case LANG_MACEDONIAN: return "mk_MK";
891 case SUBLANG_MALAY_MALAYSIA: return "ms_MY";
892 case SUBLANG_MALAY_BRUNEI_DARUSSALAM: return "ms_BN";
895 case LANG_MALAYALAM: return "ml_IN";
896 case LANG_MALTESE: return "mt_MT";
898 /* FIXME: Adjust this when such locales appear on Unix. */
900 case LANG_MARATHI: return "mr_IN";
902 return "mn"; /* Ambiguous: could be "mn_CN" or "mn_MN". */
906 case SUBLANG_DEFAULT: return "ne_NP";
907 case SUBLANG_NEPALI_INDIA: return "ne_IN";
913 case SUBLANG_NORWEGIAN_BOKMAL: return "no_NO";
914 case SUBLANG_NORWEGIAN_NYNORSK: return "nn_NO";
917 case LANG_ORIYA: return "or_IN";
918 case LANG_OROMO: return "om_ET";
919 case LANG_PAPIAMENTU: return "pap_AN";
921 return "ps"; /* Ambiguous: could be "ps_PK" or "ps_AF". */
922 case LANG_POLISH: return "pl_PL";
923 case LANG_PORTUGUESE:
926 case SUBLANG_PORTUGUESE: return "pt_PT";
927 /* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT.
928 Same phenomenon as SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. */
929 case SUBLANG_PORTUGUESE_BRAZILIAN: return "pt_BR";
935 case SUBLANG_PUNJABI_INDIA: return "pa_IN"; /* Gurmukhi script */
938 case LANG_RHAETO_ROMANCE: return "rm_CH";
942 case SUBLANG_ROMANIAN_ROMANIA: return "ro_RO";
946 return "ru"; /* Ambiguous: could be "ru_RU" or "ru_UA" or "ru_MD". */
947 case LANG_SAAMI: /* actually Northern Sami */ return "se_NO";
948 case LANG_SANSKRIT: return "sa_IN";
952 case SUBLANG_SINDHI_INDIA: return "sd_IN";
953 case SUBLANG_SINDHI_PAKISTAN: return "sd_PK";
956 case LANG_SINHALESE: return "si_LK";
957 case LANG_SLOVAK: return "sk_SK";
958 case LANG_SLOVENIAN: return "sl_SI";
959 case LANG_SOMALI: return "so_SO";
961 /* FIXME: Adjust this when such locales appear on Unix. */
966 case SUBLANG_SPANISH: return "es_ES";
967 case SUBLANG_SPANISH_MEXICAN: return "es_MX";
968 case SUBLANG_SPANISH_MODERN:
969 return "es_ES@modern"; /* not seen on Unix */
970 case SUBLANG_SPANISH_GUATEMALA: return "es_GT";
971 case SUBLANG_SPANISH_COSTA_RICA: return "es_CR";
972 case SUBLANG_SPANISH_PANAMA: return "es_PA";
973 case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: return "es_DO";
974 case SUBLANG_SPANISH_VENEZUELA: return "es_VE";
975 case SUBLANG_SPANISH_COLOMBIA: return "es_CO";
976 case SUBLANG_SPANISH_PERU: return "es_PE";
977 case SUBLANG_SPANISH_ARGENTINA: return "es_AR";
978 case SUBLANG_SPANISH_ECUADOR: return "es_EC";
979 case SUBLANG_SPANISH_CHILE: return "es_CL";
980 case SUBLANG_SPANISH_URUGUAY: return "es_UY";
981 case SUBLANG_SPANISH_PARAGUAY: return "es_PY";
982 case SUBLANG_SPANISH_BOLIVIA: return "es_BO";
983 case SUBLANG_SPANISH_EL_SALVADOR: return "es_SV";
984 case SUBLANG_SPANISH_HONDURAS: return "es_HN";
985 case SUBLANG_SPANISH_NICARAGUA: return "es_NI";
986 case SUBLANG_SPANISH_PUERTO_RICO: return "es_PR";
989 case LANG_SUTU: return "bnt_TZ"; /* or "st_LS" or "nso_ZA"? */
990 case LANG_SWAHILI: return "sw_KE";
994 case SUBLANG_DEFAULT: return "sv_SE";
995 case SUBLANG_SWEDISH_FINLAND: return "sv_FI";
998 case LANG_SYRIAC: return "syr_TR"; /* An extinct language. */
999 case LANG_TAGALOG: return "tl_PH";
1000 case LANG_TAJIK: return "tg_TJ";
1001 case LANG_TAMAZIGHT:
1004 /* FIXME: Adjust this when Tamazight locales appear on Unix. */
1005 case SUBLANG_TAMAZIGHT_ARABIC: return "ber_MA@arabic";
1006 case SUBLANG_TAMAZIGHT_LATIN: return "ber_MA@latin";
1010 return "ta"; /* Ambiguous: could be "ta_IN" or "ta_LK" or "ta_SG". */
1011 case LANG_TATAR: return "tt_RU";
1012 case LANG_TELUGU: return "te_IN";
1013 case LANG_THAI: return "th_TH";
1014 case LANG_TIBETAN: return "bo_CN";
1018 case SUBLANG_TIGRINYA_ETHIOPIA: return "ti_ET";
1019 case SUBLANG_TIGRINYA_ERITREA: return "ti_ER";
1022 case LANG_TSONGA: return "ts_ZA";
1023 case LANG_TSWANA: return "tn_BW";
1024 case LANG_TURKISH: return "tr_TR";
1025 case LANG_TURKMEN: return "tk_TM";
1026 case LANG_UKRAINIAN: return "uk_UA";
1030 case SUBLANG_URDU_PAKISTAN: return "ur_PK";
1031 case SUBLANG_URDU_INDIA: return "ur_IN";
1037 case SUBLANG_UZBEK_LATIN: return "uz_UZ";
1038 case SUBLANG_UZBEK_CYRILLIC: return "uz_UZ@cyrillic";
1042 /* FIXME: It's not clear whether Venda has the ISO 639-2 two-letter code
1044 http://www.loc.gov/standards/iso639-2/englangn.html has it, but
1045 http://lcweb.loc.gov/standards/iso639-2/codechanges.html doesn't, */
1046 return "ven_ZA"; /* or "ve_ZA"? */
1047 case LANG_VIETNAMESE: return "vi_VN";
1048 case LANG_WELSH: return "cy_GB";
1049 case LANG_XHOSA: return "xh_ZA";
1050 case LANG_YI: return "sit_CN";
1051 case LANG_YIDDISH: return "yi_IL";
1052 case LANG_YORUBA: return "yo_NG";
1053 case LANG_ZULU: return "zu_ZA";
1054 default: return "C";
1058 /* localname.c from gettext END. */
1062 /* Support functions. */
1064 static GPG_ERR_INLINE uint32_t
1065 do_swap_u32 (uint32_t i)
1067 return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
1070 #define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data))
1073 /* We assume to have `unsigned long int' value with at least 32 bits. */
1074 #define HASHWORDBITS 32
1076 /* The so called `hashpjw' function by P.J. Weinberger
1077 [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
1078 1986, 1987 Bell Telephone Laboratories, Inc.] */
1079 static GPG_ERR_INLINE unsigned long
1080 hash_string (const char *str_param)
1082 unsigned long int hval, g;
1083 const char *str = str_param;
1086 while (*str != '\0')
1089 hval += (unsigned long int) *str++;
1090 g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
1093 hval ^= g >> (HASHWORDBITS - 8);
1101 /* Generic message catalog and gettext stuff. */
1103 /* The magic number of the GNU message catalog format. */
1104 #define MAGIC 0x950412de
1105 #define MAGIC_SWAPPED 0xde120495
1107 /* Revision number of the currently used .mo (binary) file format. */
1108 #define MO_REVISION_NUMBER 0
1111 /* Header for binary .mo file format. */
1112 struct mo_file_header
1114 /* The magic number. */
1116 /* The revision number of the file format. */
1118 /* The number of strings pairs. */
1120 /* Offset of table with start offsets of original strings. */
1121 uint32_t orig_tab_offset;
1122 /* Offset of table with start offsets of translation strings. */
1123 uint32_t trans_tab_offset;
1124 /* Size of hashing table. */
1125 uint32_t hash_tab_size;
1126 /* Offset of first hashing entry. */
1127 uint32_t hash_tab_offset;
1133 /* Length of addressed string. */
1135 /* Offset of string in file. */
1140 struct overflow_space_s
1142 struct overflow_space_s *next;
1148 struct loaded_domain
1151 char *data_native; /* Data mapped to the native version of the
1152 string. (Allocated along with DATA). */
1154 uint16_t nstrings; /* Number of strings. */
1155 uint16_t *mapped; /* Array of mapping indicators:
1156 0 := Not mapped (original utf8).
1157 1 := Mapped to native encoding in overflow space.
1158 >=2 := Mapped to native encoding. The value
1159 gives the length of the mapped string.
1160 Because the terminating nul is included
1161 in the length and an empty string is
1162 not allowed, values are always > 1. */
1163 struct overflow_space_s *overflow_space;
1164 struct string_desc *orig_tab;
1165 struct string_desc *trans_tab;
1171 /* The list of domains we we are aware of. This list is protected by
1172 the criticla section DOMAINLIST_ACCESS_CS. */
1173 static struct domainlist_s *domainlist;
1175 /* A critical section to guard access to the domainlist. */
1176 static CRITICAL_SECTION domainlist_access_cs;
1178 /* The name of the current domain. This is a malloced string. This
1179 is a gobal variable which is not thread-safe. */
1180 static char *current_domainname;
1184 /* Constructor for this module. This can only be used if we are a
1185 DLL. If used as a static lib we can't control the process set; for
1186 example it might be used with a main module which is not build with
1187 mingw and thus does not know how to call the constructors. */
1189 static void module_init (void) _GPG_ERR_CONSTRUCTOR;
1194 static int init_done;
1198 InitializeCriticalSection (&domainlist_access_cs);
1203 #if !defined(DLL_EXPORT) || !defined(_GPG_ERR_HAVE_CONSTRUCTOR)
1205 _gpg_w32__init_gettext_module (void)
1212 /* Free the domain data. */
1214 free_domain (struct loaded_domain *domain)
1216 struct overflow_space_s *os, *os2;
1218 jnlib_free (domain->data);
1219 jnlib_free (domain->mapped);
1220 for (os = domain->overflow_space; os; os = os2)
1225 jnlib_free (domain);
1229 static struct loaded_domain *
1230 load_domain (const char *filename)
1234 struct mo_file_header *data = NULL;
1235 struct loaded_domain *domain = NULL;
1239 fh = CreateFileA (filename, GENERIC_READ, FILE_SHARE_WRITE, NULL,
1240 OPEN_EXISTING, 0, NULL);
1241 if (fh == INVALID_HANDLE_VALUE)
1244 size = GetFileSize (fh, NULL);
1245 if (size == INVALID_FILE_SIZE)
1251 data = (2*size <= size)? NULL : jnlib_malloc (2*size);
1259 read_ptr = (char *) data;
1265 res = ReadFile (fh, read_ptr, to_read, &nb, NULL);
1266 if (! res || nb < to_read)
1275 while (to_read > 0);
1278 /* Using the magic number we can test whether it really is a message
1280 if (data->magic != MAGIC && data->magic != MAGIC_SWAPPED)
1282 /* The magic number is wrong: not a message catalog file. */
1287 domain = jnlib_calloc (1, sizeof *domain);
1293 domain->data = (char *) data;
1294 domain->data_native = (char *) data + size;
1295 domain->must_swap = data->magic != MAGIC;
1297 /* Fill in the information about the available tables. */
1298 switch (SWAPIT (domain->must_swap, data->revision))
1300 case MO_REVISION_NUMBER:
1304 /* Because we use 16 bit values for the mapping array, we
1305 can't support more that 65534 strings (65535 would be okay,
1306 but it is often used as a special value). A PO file with
1307 that many translations is very unlikely given that GnuPG
1308 with its very large number of strings has only about 1600
1309 strings + variants. */
1310 nstrings = SWAPIT (domain->must_swap, data->nstrings);
1311 if (nstrings > 65534)
1313 domain->nstrings = nstrings;
1314 domain->orig_tab = (struct string_desc *)
1315 ((char *) data + SWAPIT (domain->must_swap, data->orig_tab_offset));
1316 domain->trans_tab = (struct string_desc *)
1317 ((char *) data + SWAPIT (domain->must_swap, data->trans_tab_offset));
1318 domain->hash_size = SWAPIT (domain->must_swap, data->hash_tab_size);
1319 domain->hash_tab = (uint32_t *)
1320 ((char *) data + SWAPIT (domain->must_swap, data->hash_tab_offset));
1324 default: /* This is an invalid revision. */
1328 /* Allocate an array to keep track of code page mappings. */
1329 domain->mapped = jnlib_calloc (domain->nstrings, sizeof *domain->mapped);
1331 return domain; /* Okay. */
1335 jnlib_free (domain);
1340 /* Return a malloced wide char string from an UTF-8 encoded input
1341 string STRING. Caller must free this value. On failure returns
1342 NULL. The result of calling this function with STRING set to NULL
1345 utf8_to_wchar (const char *string, size_t length, size_t *retlen)
1351 n = MultiByteToWideChar (CP_UTF8, 0, string, length, NULL, 0);
1352 if (n < 0 || (n+1) <= 0)
1355 nbytes = (size_t)(n+1) * sizeof(*result);
1356 if (nbytes / sizeof(*result) != (n+1))
1358 gpg_err_set_errno (ENOMEM);
1361 result = jnlib_malloc (nbytes);
1365 n = MultiByteToWideChar (CP_UTF8, 0, string, length, result, n);
1368 jnlib_free (result);
1376 /* Return a malloced string encoded in UTF-8 from the wide char input
1377 string STRING. Caller must free this value. On failure returns
1378 NULL. The result of calling this function with STRING set to NULL
1381 wchar_to_native (const wchar_t *string, size_t length, size_t *retlen)
1386 n = WideCharToMultiByte (CP_ACP, 0, string, length, NULL, 0, NULL, NULL);
1387 if (n < 0 || (n+1) <= 0)
1390 result = jnlib_malloc (n+1);
1394 n = WideCharToMultiByte (CP_ACP, 0, string, length, result, n, NULL, NULL);
1397 jnlib_free (result);
1405 /* Convert UTF8 to the native codepage. Caller must free the return value. */
1407 utf8_to_native (const char *string, size_t length, size_t *retlen)
1413 wstring = utf8_to_wchar (string, length, &newlen);
1416 result = wchar_to_native (wstring, newlen, &newlen);
1417 jnlib_free (wstring);
1421 *retlen = result? newlen : 0;
1428 /* Specify that the DOMAINNAME message catalog will be found
1429 in DIRNAME rather than in the system locale data base. */
1431 _gpg_w32_bindtextdomain (const char *domainname, const char *dirname)
1433 const char *catval_full;
1436 const char *retvalue;
1440 struct domainlist_s *dl;
1443 EnterCriticalSection (&domainlist_access_cs);
1445 for (dl = domainlist; dl; dl = dl->next)
1446 if (!strcmp (dl->name, domainname))
1448 retvalue = dl->dname;
1452 LeaveCriticalSection (&domainlist_access_cs);
1456 /* DIRNAME is "$INSTALLDIR\share\locale". */
1458 /* First find out the category value. */
1460 catval_full = my_nl_locale_name ("LC_MESSAGES");
1462 /* Normally we would have to loop over all returned locales and
1463 search for the right file. See gettext intl/dcigettext.c for all
1464 the gory details. Here, we only support the basic category, and
1465 ignore everything else. */
1470 catval = jnlib_malloc (strlen (catval_full) + 1);
1473 strcpy (catval, catval_full);
1474 p = strchr (catval, '_');
1482 /* Now build the filename string. The complete filename is this:
1483 DIRNAME + \ + CATVAL + \LC_MESSAGES\ + DOMAINNAME + .mo */
1485 int len = (strlen (dirname) + 1 + strlen (catval) + 13
1486 + strlen (domainname) + 3 + 1);
1489 fname = jnlib_malloc (len);
1492 jnlib_free (catval);
1497 strcpy (p, dirname);
1498 p += strlen (dirname);
1501 p += strlen (catval);
1502 strcpy (p, "\\LC_MESSAGES\\");
1504 strcpy (p, domainname);
1505 p += strlen (domainname);
1509 jnlib_free (catval);
1511 /* Store the domain information in the domainlist. */
1513 struct domainlist_s *item, *dl;
1514 char *rel_ptr1 = NULL;
1515 char *rel_ptr2 = NULL;
1517 item = jnlib_calloc (1, sizeof *dl + strlen (domainname));
1523 strcpy (item->name, domainname);
1524 item->dname = jnlib_malloc (strlen (dirname) +1);
1531 strcpy (item->dname, dirname);
1532 retvalue = item->dname;
1534 EnterCriticalSection (&domainlist_access_cs);
1536 for (dl = domainlist; dl; dl = dl->next)
1537 if (!strcmp (dl->name, domainname))
1539 if (!dl) /* First time called for this domainname. */
1541 item->fname = fname;
1543 item->next = domainlist;
1547 else /* Update only. */
1549 rel_ptr1 = dl->fname;
1552 rel_ptr2 = dl->dname;
1553 dl->dname = item->dname;
1557 LeaveCriticalSection (&domainlist_access_cs);
1560 jnlib_free (rel_ptr1);
1561 jnlib_free (rel_ptr2);
1571 get_plural (const char *data, size_t datalen, unsigned long nplural)
1576 /* We only support the Germanic rule. */
1577 idx = (nplural == 1? 0 : 1);
1581 p = strchr (data, 0) + 1;
1582 if (p >= data+datalen)
1583 return "ERROR in GETTEXT (bad plural entry)";
1584 datalen -= (p-data);
1592 get_string (struct loaded_domain *domain, uint32_t idx,
1593 int use_plural, unsigned long nplural)
1595 struct tls_space_s *tls = get_tls ();
1596 struct overflow_space_s *os;
1597 const char *trans; /* Pointer to the translated entry. */
1598 size_t translen; /* Length of that entry. */
1601 return "ERROR in GETTEXT (too many strings)";
1603 if (tls->gt_use_utf8)
1605 trans = (domain->data
1606 + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
1607 translen = SWAPIT(domain->must_swap, domain->trans_tab[idx].length);
1609 else if (!domain->mapped[idx])
1611 /* Not yet mapped. Map from utf-8 to native encoding now. */
1613 size_t plen_utf8, buflen;
1616 p_utf8 = (domain->data
1617 + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
1618 plen_utf8 = SWAPIT(domain->must_swap, domain->trans_tab[idx].length);
1620 /* We need to include the nul, so that the utf8->wchar->native
1621 conversion chain works correctly and the nul is stored after
1623 if (p_utf8[plen_utf8])
1625 trans = "ERROR in MO file"; /* Terminating zero is missing. */
1631 buf = utf8_to_native (p_utf8, plen_utf8, &buflen);
1634 trans = "ERROR in GETTEXT MALLOC";
1637 else if (buflen <= plen_utf8 && buflen > 1)
1639 /* Copy into the DATA_NATIVE area. */
1642 p_tmp = (domain->data_native
1643 + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
1644 memcpy (p_tmp, buf, buflen);
1645 domain->mapped[idx] = buflen;
1651 /* There is not enough space for the translation (or for
1652 whatever reason an empty string is used): Store it in the
1653 overflow_space and mark that in the mapped array.
1654 Because UTF-8 strings are in general longer than the
1655 Windows native encoding, we expect that this won't happen
1656 too often and thus we use a linked list to manage this
1658 os = jnlib_malloc (sizeof *os + buflen);
1662 memcpy (os->d, buf, buflen);
1663 os->length = buflen;
1664 os->next = domain->overflow_space;
1665 domain->overflow_space = os;
1666 domain->mapped[idx] = 1;
1668 translen = os->length;
1672 trans = "ERROR in GETTEXT MALLOC";
1677 translen--; /* TRANSLEN shall be the size without the nul. */
1680 else if (domain->mapped[idx] == 1)
1682 /* The translated string is in the overflow_space. */
1683 for (os=domain->overflow_space; os; os = os->next)
1689 translen = os->length;
1693 trans = "ERROR in GETTEXT (overflow space)\n";
1699 trans = (domain->data_native
1700 + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
1701 translen = domain->mapped[idx];
1705 if (use_plural && translen)
1706 return get_plural (trans, translen, nplural);
1713 do_gettext (const char *domainname,
1714 const char *msgid, const char *msgid2, unsigned long nplural)
1716 struct domainlist_s *dl;
1717 struct loaded_domain *domain;
1719 uint32_t top, bottom, nstr;
1723 domainname = current_domainname? current_domainname : "";
1725 /* FIXME: The whole locking stuff is a bit questionable because
1726 gettext does not claim to be thread-safe. We need to investigate
1732 EnterCriticalSection (&domainlist_access_cs);
1734 for (dl = domainlist; dl; dl = dl->next)
1735 if (!strcmp (dl->name, domainname))
1737 load_failed = dl->load_failed;
1738 domain = dl->domain;
1741 if (dl && !domain && !load_failed && dl->fname)
1743 filename = jnlib_malloc (strlen (dl->fname) + 1);
1745 strcpy (filename, dl->fname);
1748 LeaveCriticalSection (&domainlist_access_cs);
1750 goto not_found; /* DOMAINNAME not bound. */
1753 /* No attempt so far to load the MO file. Try now. */
1756 domain = load_domain (filename);
1757 jnlib_free (filename);
1759 EnterCriticalSection (&domainlist_access_cs);
1761 for (dl = domainlist; dl; dl = dl->next)
1762 if (!strcmp (dl->name, domainname))
1765 dl->domain = domain;
1767 dl->load_failed = 1;
1772 LeaveCriticalSection (&domainlist_access_cs);
1775 /* Ooops - lost the domain. */
1776 free_domain (domain);
1782 goto not_found; /* No MO file. */
1784 /* First try to use the hash table. */
1785 if (domain->hash_size > 2 && domain->hash_tab)
1787 /* Use the hashing table. */
1788 uint32_t len = strlen (msgid);
1789 uint32_t hash_val = hash_string (msgid);
1790 uint32_t idx = hash_val % domain->hash_size;
1791 uint32_t incr = 1 + (hash_val % (domain->hash_size - 2));
1793 while ( (nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx])) )
1796 if (nstr < domain->nstrings
1797 && SWAPIT(domain->must_swap,
1798 domain->orig_tab[nstr].length) >= len
1799 && !strcmp (msgid, (domain->data
1800 + SWAPIT(domain->must_swap,
1801 domain->orig_tab[nstr].offset))))
1803 return get_string (domain, nstr, !!msgid2, nplural);
1806 if (idx >= domain->hash_size - incr)
1807 idx -= domain->hash_size - incr;
1813 /* Now we try the default method: binary search in the sorted array
1816 top = domain->nstrings;
1817 while (bottom < top)
1821 nstr = (bottom + top) / 2;
1822 cmp_val = strcmp (msgid, (domain->data
1823 + SWAPIT(domain->must_swap,
1824 domain->orig_tab[nstr].offset)));
1827 else if (cmp_val > 0)
1831 return get_string (domain, nstr, !!msgid2, nplural);
1836 /* We use the standard Germanic rule if plural has been requested. */
1837 return msgid2? (nplural == 1? msgid : msgid2) : msgid;
1842 _gpg_w32_textdomain (const char *domainname)
1848 if (!current_domainname)
1849 gpg_err_set_errno (0);
1853 string = malloc (strlen (domainname) + 1);
1856 strcpy (string, domainname);
1857 current_domainname = string;
1859 return current_domainname;
1863 /* A direct implementation of gettext instead of a macro calling
1864 dngettext. This is so that the caller does not need to push dummy
1865 values on the stack. The used domain is the first one registered
1866 with bindtextdomain. */
1868 _gpg_w32_gettext (const char *msgid)
1870 return do_gettext (NULL, msgid, NULL, 0);
1874 /* A direct implementation of dgettext instead of a macro calling
1875 dngettext. This is so that the caller does not need to push dummy
1876 values on the stack. */
1878 _gpg_w32_dgettext (const char *domainname, const char *msgid)
1880 return do_gettext (domainname, msgid, NULL, 0);
1884 /* Our implementation of dngettext. This is the most genereic
1885 function we have; a macro implements ngettext. */
1887 _gpg_w32_dngettext (const char *domainname, const char *msgid1,
1888 const char *msgid2, unsigned long int n)
1890 /* We use the simple Germanic plural rule. */
1891 return do_gettext (domainname, msgid1, msgid2, n);
1895 /* Return the locale name as used by gettext. The return value will
1898 _gpg_w32_gettext_localename (void)
1902 s = my_nl_locale_name ("LC_MESSAGES");
1907 /* With a VALUE of 1 switch the gettext functions into utf8 mode.
1908 That is the strings are returned without translation to the native
1909 charset. A VALUE of 0 switches back to translated strings. A VALUE
1910 of -1 returns the current value. */
1912 _gpg_w32_gettext_use_utf8 (int value)
1914 struct tls_space_s *tls = get_tls ();
1915 int last = tls->gt_use_utf8;
1917 tls->gt_use_utf8 = value;
1924 main (int argc, char **argv)
1926 const char atext1[] =
1927 "Warning: You have entered an insecure passphrase.%%0A"
1928 "A passphrase should be at least %u character long.";
1929 const char atext2[] =
1930 "Warning: You have entered an insecure passphrase.%%0A"
1931 "A passphrase should be at least %u characters long.";
1939 _gpg_err_w32_bindtextdomain ("gnupg2", "c:/programme/gnu/gnupg/share/locale");
1941 printf ("locale is `%s'\n", _gpg_err_w32_gettext_localename ());
1942 fputs ("text with N=1:\n", stdout);
1943 fputs (_gpg_err_w32_ngettext (atext1, atext2, 1), stdout);
1944 fputs ("\n\ntext with N=2:\n", stdout);
1945 fputs (_gpg_err_w32_ngettext (atext1, atext2, 2), stdout);
1946 fputs ("\nready\n", stdout);
1952 * compile-command: "i586-mingw32msvc-gcc -DTEST -Wall -g w32-gettext.c"