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