agent/
[gnupg.git] / jnlib / w32-gettext.c
blob834b2aa17694e2293e2356469e04e2abc813d49c
1 /* w32-gettext.h - A simple gettext implementation for Windows targets.
2 Copyright (C) 1995, 1996, 1997, 1999, 2005, 2007,
3 2008 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public License
7 as published by the Free Software Foundation; either version 2.1 of
8 the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this program; if not, see <http://www.gnu.org/licenses/>.
19 #if HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 #if !defined (_WIN32) && !defined (__CYGWIN32__)
23 # error This module may only be build for Windows or Cygwin32
24 #endif
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <ctype.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <stdint.h>
34 #include <locale.h>
35 #include <windows.h>
37 #ifdef JNLIB_IN_JNLIB
38 #include "libjnlib-config.h"
39 #endif
41 #ifndef jnlib_malloc
42 # define jnlib_malloc(a) malloc ((a))
43 # define jnlib_calloc(a,b) calloc ((a), (b))
44 # define jnlib_free(a) free ((a))
45 # define jnlib_xstrdup(a) my_xstrdup(a)
46 #endif /*!jnlib_malloc*/
50 /* localname.c from gettext BEGIN. */
52 /* Determine the current selected locale.
53 Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
55 This program is free software; you can redistribute it and/or modify it
56 under the terms of the GNU Library General Public License as published
57 by the Free Software Foundation; either version 2, or (at your option)
58 any later version.
60 This program is distributed in the hope that it will be useful,
61 but WITHOUT ANY WARRANTY; without even the implied warranty of
62 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
63 Library General Public License for more details.
65 You should have received a copy of the GNU Library General Public
66 License along with this program; if not, write to the Free Software
67 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
68 USA. */
70 /* Written by Ulrich Drepper <drepper@gnu.org>, 1995. */
71 /* Win32 code written by Tor Lillqvist <tml@iki.fi>. */
72 /* Renamed _nl_locale_name, removed unsed args, removed include files,
73 non-W32 code and changed comments <wk@gnupg.org>. */
75 /* Mingw headers don't have latest language and sublanguage codes. */
76 #ifndef LANG_AFRIKAANS
77 #define LANG_AFRIKAANS 0x36
78 #endif
79 #ifndef LANG_ALBANIAN
80 #define LANG_ALBANIAN 0x1c
81 #endif
82 #ifndef LANG_AMHARIC
83 #define LANG_AMHARIC 0x5e
84 #endif
85 #ifndef LANG_ARABIC
86 #define LANG_ARABIC 0x01
87 #endif
88 #ifndef LANG_ARMENIAN
89 #define LANG_ARMENIAN 0x2b
90 #endif
91 #ifndef LANG_ASSAMESE
92 #define LANG_ASSAMESE 0x4d
93 #endif
94 #ifndef LANG_AZERI
95 #define LANG_AZERI 0x2c
96 #endif
97 #ifndef LANG_BASQUE
98 #define LANG_BASQUE 0x2d
99 #endif
100 #ifndef LANG_BELARUSIAN
101 #define LANG_BELARUSIAN 0x23
102 #endif
103 #ifndef LANG_BENGALI
104 #define LANG_BENGALI 0x45
105 #endif
106 #ifndef LANG_BURMESE
107 #define LANG_BURMESE 0x55
108 #endif
109 #ifndef LANG_CAMBODIAN
110 #define LANG_CAMBODIAN 0x53
111 #endif
112 #ifndef LANG_CATALAN
113 #define LANG_CATALAN 0x03
114 #endif
115 #ifndef LANG_CHEROKEE
116 #define LANG_CHEROKEE 0x5c
117 #endif
118 #ifndef LANG_DIVEHI
119 #define LANG_DIVEHI 0x65
120 #endif
121 #ifndef LANG_EDO
122 #define LANG_EDO 0x66
123 #endif
124 #ifndef LANG_ESTONIAN
125 #define LANG_ESTONIAN 0x25
126 #endif
127 #ifndef LANG_FAEROESE
128 #define LANG_FAEROESE 0x38
129 #endif
130 #ifndef LANG_FARSI
131 #define LANG_FARSI 0x29
132 #endif
133 #ifndef LANG_FRISIAN
134 #define LANG_FRISIAN 0x62
135 #endif
136 #ifndef LANG_FULFULDE
137 #define LANG_FULFULDE 0x67
138 #endif
139 #ifndef LANG_GAELIC
140 #define LANG_GAELIC 0x3c
141 #endif
142 #ifndef LANG_GALICIAN
143 #define LANG_GALICIAN 0x56
144 #endif
145 #ifndef LANG_GEORGIAN
146 #define LANG_GEORGIAN 0x37
147 #endif
148 #ifndef LANG_GUARANI
149 #define LANG_GUARANI 0x74
150 #endif
151 #ifndef LANG_GUJARATI
152 #define LANG_GUJARATI 0x47
153 #endif
154 #ifndef LANG_HAUSA
155 #define LANG_HAUSA 0x68
156 #endif
157 #ifndef LANG_HAWAIIAN
158 #define LANG_HAWAIIAN 0x75
159 #endif
160 #ifndef LANG_HEBREW
161 #define LANG_HEBREW 0x0d
162 #endif
163 #ifndef LANG_HINDI
164 #define LANG_HINDI 0x39
165 #endif
166 #ifndef LANG_IBIBIO
167 #define LANG_IBIBIO 0x69
168 #endif
169 #ifndef LANG_IGBO
170 #define LANG_IGBO 0x70
171 #endif
172 #ifndef LANG_INDONESIAN
173 #define LANG_INDONESIAN 0x21
174 #endif
175 #ifndef LANG_INUKTITUT
176 #define LANG_INUKTITUT 0x5d
177 #endif
178 #ifndef LANG_KANNADA
179 #define LANG_KANNADA 0x4b
180 #endif
181 #ifndef LANG_KANURI
182 #define LANG_KANURI 0x71
183 #endif
184 #ifndef LANG_KASHMIRI
185 #define LANG_KASHMIRI 0x60
186 #endif
187 #ifndef LANG_KAZAK
188 #define LANG_KAZAK 0x3f
189 #endif
190 #ifndef LANG_KONKANI
191 #define LANG_KONKANI 0x57
192 #endif
193 #ifndef LANG_KYRGYZ
194 #define LANG_KYRGYZ 0x40
195 #endif
196 #ifndef LANG_LAO
197 #define LANG_LAO 0x54
198 #endif
199 #ifndef LANG_LATIN
200 #define LANG_LATIN 0x76
201 #endif
202 #ifndef LANG_LATVIAN
203 #define LANG_LATVIAN 0x26
204 #endif
205 #ifndef LANG_LITHUANIAN
206 #define LANG_LITHUANIAN 0x27
207 #endif
208 #ifndef LANG_MACEDONIAN
209 #define LANG_MACEDONIAN 0x2f
210 #endif
211 #ifndef LANG_MALAY
212 #define LANG_MALAY 0x3e
213 #endif
214 #ifndef LANG_MALAYALAM
215 #define LANG_MALAYALAM 0x4c
216 #endif
217 #ifndef LANG_MALTESE
218 #define LANG_MALTESE 0x3a
219 #endif
220 #ifndef LANG_MANIPURI
221 #define LANG_MANIPURI 0x58
222 #endif
223 #ifndef LANG_MARATHI
224 #define LANG_MARATHI 0x4e
225 #endif
226 #ifndef LANG_MONGOLIAN
227 #define LANG_MONGOLIAN 0x50
228 #endif
229 #ifndef LANG_NEPALI
230 #define LANG_NEPALI 0x61
231 #endif
232 #ifndef LANG_ORIYA
233 #define LANG_ORIYA 0x48
234 #endif
235 #ifndef LANG_OROMO
236 #define LANG_OROMO 0x72
237 #endif
238 #ifndef LANG_PAPIAMENTU
239 #define LANG_PAPIAMENTU 0x79
240 #endif
241 #ifndef LANG_PASHTO
242 #define LANG_PASHTO 0x63
243 #endif
244 #ifndef LANG_PUNJABI
245 #define LANG_PUNJABI 0x46
246 #endif
247 #ifndef LANG_RHAETO_ROMANCE
248 #define LANG_RHAETO_ROMANCE 0x17
249 #endif
250 #ifndef LANG_SAAMI
251 #define LANG_SAAMI 0x3b
252 #endif
253 #ifndef LANG_SANSKRIT
254 #define LANG_SANSKRIT 0x4f
255 #endif
256 #ifndef LANG_SERBIAN
257 #define LANG_SERBIAN 0x1a
258 #endif
259 #ifndef LANG_SINDHI
260 #define LANG_SINDHI 0x59
261 #endif
262 #ifndef LANG_SINHALESE
263 #define LANG_SINHALESE 0x5b
264 #endif
265 #ifndef LANG_SLOVAK
266 #define LANG_SLOVAK 0x1b
267 #endif
268 #ifndef LANG_SOMALI
269 #define LANG_SOMALI 0x77
270 #endif
271 #ifndef LANG_SORBIAN
272 #define LANG_SORBIAN 0x2e
273 #endif
274 #ifndef LANG_SUTU
275 #define LANG_SUTU 0x30
276 #endif
277 #ifndef LANG_SWAHILI
278 #define LANG_SWAHILI 0x41
279 #endif
280 #ifndef LANG_SYRIAC
281 #define LANG_SYRIAC 0x5a
282 #endif
283 #ifndef LANG_TAGALOG
284 #define LANG_TAGALOG 0x64
285 #endif
286 #ifndef LANG_TAJIK
287 #define LANG_TAJIK 0x28
288 #endif
289 #ifndef LANG_TAMAZIGHT
290 #define LANG_TAMAZIGHT 0x5f
291 #endif
292 #ifndef LANG_TAMIL
293 #define LANG_TAMIL 0x49
294 #endif
295 #ifndef LANG_TATAR
296 #define LANG_TATAR 0x44
297 #endif
298 #ifndef LANG_TELUGU
299 #define LANG_TELUGU 0x4a
300 #endif
301 #ifndef LANG_THAI
302 #define LANG_THAI 0x1e
303 #endif
304 #ifndef LANG_TIBETAN
305 #define LANG_TIBETAN 0x51
306 #endif
307 #ifndef LANG_TIGRINYA
308 #define LANG_TIGRINYA 0x73
309 #endif
310 #ifndef LANG_TSONGA
311 #define LANG_TSONGA 0x31
312 #endif
313 #ifndef LANG_TSWANA
314 #define LANG_TSWANA 0x32
315 #endif
316 #ifndef LANG_TURKMEN
317 #define LANG_TURKMEN 0x42
318 #endif
319 #ifndef LANG_UKRAINIAN
320 #define LANG_UKRAINIAN 0x22
321 #endif
322 #ifndef LANG_URDU
323 #define LANG_URDU 0x20
324 #endif
325 #ifndef LANG_UZBEK
326 #define LANG_UZBEK 0x43
327 #endif
328 #ifndef LANG_VENDA
329 #define LANG_VENDA 0x33
330 #endif
331 #ifndef LANG_VIETNAMESE
332 #define LANG_VIETNAMESE 0x2a
333 #endif
334 #ifndef LANG_WELSH
335 #define LANG_WELSH 0x52
336 #endif
337 #ifndef LANG_XHOSA
338 #define LANG_XHOSA 0x34
339 #endif
340 #ifndef LANG_YI
341 #define LANG_YI 0x78
342 #endif
343 #ifndef LANG_YIDDISH
344 #define LANG_YIDDISH 0x3d
345 #endif
346 #ifndef LANG_YORUBA
347 #define LANG_YORUBA 0x6a
348 #endif
349 #ifndef LANG_ZULU
350 #define LANG_ZULU 0x35
351 #endif
352 #ifndef SUBLANG_ARABIC_SAUDI_ARABIA
353 #define SUBLANG_ARABIC_SAUDI_ARABIA 0x01
354 #endif
355 #ifndef SUBLANG_ARABIC_IRAQ
356 #define SUBLANG_ARABIC_IRAQ 0x02
357 #endif
358 #ifndef SUBLANG_ARABIC_EGYPT
359 #define SUBLANG_ARABIC_EGYPT 0x03
360 #endif
361 #ifndef SUBLANG_ARABIC_LIBYA
362 #define SUBLANG_ARABIC_LIBYA 0x04
363 #endif
364 #ifndef SUBLANG_ARABIC_ALGERIA
365 #define SUBLANG_ARABIC_ALGERIA 0x05
366 #endif
367 #ifndef SUBLANG_ARABIC_MOROCCO
368 #define SUBLANG_ARABIC_MOROCCO 0x06
369 #endif
370 #ifndef SUBLANG_ARABIC_TUNISIA
371 #define SUBLANG_ARABIC_TUNISIA 0x07
372 #endif
373 #ifndef SUBLANG_ARABIC_OMAN
374 #define SUBLANG_ARABIC_OMAN 0x08
375 #endif
376 #ifndef SUBLANG_ARABIC_YEMEN
377 #define SUBLANG_ARABIC_YEMEN 0x09
378 #endif
379 #ifndef SUBLANG_ARABIC_SYRIA
380 #define SUBLANG_ARABIC_SYRIA 0x0a
381 #endif
382 #ifndef SUBLANG_ARABIC_JORDAN
383 #define SUBLANG_ARABIC_JORDAN 0x0b
384 #endif
385 #ifndef SUBLANG_ARABIC_LEBANON
386 #define SUBLANG_ARABIC_LEBANON 0x0c
387 #endif
388 #ifndef SUBLANG_ARABIC_KUWAIT
389 #define SUBLANG_ARABIC_KUWAIT 0x0d
390 #endif
391 #ifndef SUBLANG_ARABIC_UAE
392 #define SUBLANG_ARABIC_UAE 0x0e
393 #endif
394 #ifndef SUBLANG_ARABIC_BAHRAIN
395 #define SUBLANG_ARABIC_BAHRAIN 0x0f
396 #endif
397 #ifndef SUBLANG_ARABIC_QATAR
398 #define SUBLANG_ARABIC_QATAR 0x10
399 #endif
400 #ifndef SUBLANG_AZERI_LATIN
401 #define SUBLANG_AZERI_LATIN 0x01
402 #endif
403 #ifndef SUBLANG_AZERI_CYRILLIC
404 #define SUBLANG_AZERI_CYRILLIC 0x02
405 #endif
406 #ifndef SUBLANG_BENGALI_INDIA
407 #define SUBLANG_BENGALI_INDIA 0x01
408 #endif
409 #ifndef SUBLANG_BENGALI_BANGLADESH
410 #define SUBLANG_BENGALI_BANGLADESH 0x02
411 #endif
412 #ifndef SUBLANG_CHINESE_MACAU
413 #define SUBLANG_CHINESE_MACAU 0x05
414 #endif
415 #ifndef SUBLANG_ENGLISH_SOUTH_AFRICA
416 #define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07
417 #endif
418 #ifndef SUBLANG_ENGLISH_JAMAICA
419 #define SUBLANG_ENGLISH_JAMAICA 0x08
420 #endif
421 #ifndef SUBLANG_ENGLISH_CARIBBEAN
422 #define SUBLANG_ENGLISH_CARIBBEAN 0x09
423 #endif
424 #ifndef SUBLANG_ENGLISH_BELIZE
425 #define SUBLANG_ENGLISH_BELIZE 0x0a
426 #endif
427 #ifndef SUBLANG_ENGLISH_TRINIDAD
428 #define SUBLANG_ENGLISH_TRINIDAD 0x0b
429 #endif
430 #ifndef SUBLANG_ENGLISH_ZIMBABWE
431 #define SUBLANG_ENGLISH_ZIMBABWE 0x0c
432 #endif
433 #ifndef SUBLANG_ENGLISH_PHILIPPINES
434 #define SUBLANG_ENGLISH_PHILIPPINES 0x0d
435 #endif
436 #ifndef SUBLANG_ENGLISH_INDONESIA
437 #define SUBLANG_ENGLISH_INDONESIA 0x0e
438 #endif
439 #ifndef SUBLANG_ENGLISH_HONGKONG
440 #define SUBLANG_ENGLISH_HONGKONG 0x0f
441 #endif
442 #ifndef SUBLANG_ENGLISH_INDIA
443 #define SUBLANG_ENGLISH_INDIA 0x10
444 #endif
445 #ifndef SUBLANG_ENGLISH_MALAYSIA
446 #define SUBLANG_ENGLISH_MALAYSIA 0x11
447 #endif
448 #ifndef SUBLANG_ENGLISH_SINGAPORE
449 #define SUBLANG_ENGLISH_SINGAPORE 0x12
450 #endif
451 #ifndef SUBLANG_FRENCH_LUXEMBOURG
452 #define SUBLANG_FRENCH_LUXEMBOURG 0x05
453 #endif
454 #ifndef SUBLANG_FRENCH_MONACO
455 #define SUBLANG_FRENCH_MONACO 0x06
456 #endif
457 #ifndef SUBLANG_FRENCH_WESTINDIES
458 #define SUBLANG_FRENCH_WESTINDIES 0x07
459 #endif
460 #ifndef SUBLANG_FRENCH_REUNION
461 #define SUBLANG_FRENCH_REUNION 0x08
462 #endif
463 #ifndef SUBLANG_FRENCH_CONGO
464 #define SUBLANG_FRENCH_CONGO 0x09
465 #endif
466 #ifndef SUBLANG_FRENCH_SENEGAL
467 #define SUBLANG_FRENCH_SENEGAL 0x0a
468 #endif
469 #ifndef SUBLANG_FRENCH_CAMEROON
470 #define SUBLANG_FRENCH_CAMEROON 0x0b
471 #endif
472 #ifndef SUBLANG_FRENCH_COTEDIVOIRE
473 #define SUBLANG_FRENCH_COTEDIVOIRE 0x0c
474 #endif
475 #ifndef SUBLANG_FRENCH_MALI
476 #define SUBLANG_FRENCH_MALI 0x0d
477 #endif
478 #ifndef SUBLANG_FRENCH_MOROCCO
479 #define SUBLANG_FRENCH_MOROCCO 0x0e
480 #endif
481 #ifndef SUBLANG_FRENCH_HAITI
482 #define SUBLANG_FRENCH_HAITI 0x0f
483 #endif
484 #ifndef SUBLANG_GERMAN_LUXEMBOURG
485 #define SUBLANG_GERMAN_LUXEMBOURG 0x04
486 #endif
487 #ifndef SUBLANG_GERMAN_LIECHTENSTEIN
488 #define SUBLANG_GERMAN_LIECHTENSTEIN 0x05
489 #endif
490 #ifndef SUBLANG_KASHMIRI_INDIA
491 #define SUBLANG_KASHMIRI_INDIA 0x02
492 #endif
493 #ifndef SUBLANG_MALAY_MALAYSIA
494 #define SUBLANG_MALAY_MALAYSIA 0x01
495 #endif
496 #ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
497 #define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02
498 #endif
499 #ifndef SUBLANG_NEPALI_INDIA
500 #define SUBLANG_NEPALI_INDIA 0x02
501 #endif
502 #ifndef SUBLANG_PUNJABI_INDIA
503 #define SUBLANG_PUNJABI_INDIA 0x01
504 #endif
505 #ifndef SUBLANG_ROMANIAN_ROMANIA
506 #define SUBLANG_ROMANIAN_ROMANIA 0x01
507 #endif
508 #ifndef SUBLANG_SERBIAN_LATIN
509 #define SUBLANG_SERBIAN_LATIN 0x02
510 #endif
511 #ifndef SUBLANG_SERBIAN_CYRILLIC
512 #define SUBLANG_SERBIAN_CYRILLIC 0x03
513 #endif
514 #ifndef SUBLANG_SINDHI_INDIA
515 #define SUBLANG_SINDHI_INDIA 0x00
516 #endif
517 #ifndef SUBLANG_SINDHI_PAKISTAN
518 #define SUBLANG_SINDHI_PAKISTAN 0x01
519 #endif
520 #ifndef SUBLANG_SPANISH_GUATEMALA
521 #define SUBLANG_SPANISH_GUATEMALA 0x04
522 #endif
523 #ifndef SUBLANG_SPANISH_COSTA_RICA
524 #define SUBLANG_SPANISH_COSTA_RICA 0x05
525 #endif
526 #ifndef SUBLANG_SPANISH_PANAMA
527 #define SUBLANG_SPANISH_PANAMA 0x06
528 #endif
529 #ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC
530 #define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07
531 #endif
532 #ifndef SUBLANG_SPANISH_VENEZUELA
533 #define SUBLANG_SPANISH_VENEZUELA 0x08
534 #endif
535 #ifndef SUBLANG_SPANISH_COLOMBIA
536 #define SUBLANG_SPANISH_COLOMBIA 0x09
537 #endif
538 #ifndef SUBLANG_SPANISH_PERU
539 #define SUBLANG_SPANISH_PERU 0x0a
540 #endif
541 #ifndef SUBLANG_SPANISH_ARGENTINA
542 #define SUBLANG_SPANISH_ARGENTINA 0x0b
543 #endif
544 #ifndef SUBLANG_SPANISH_ECUADOR
545 #define SUBLANG_SPANISH_ECUADOR 0x0c
546 #endif
547 #ifndef SUBLANG_SPANISH_CHILE
548 #define SUBLANG_SPANISH_CHILE 0x0d
549 #endif
550 #ifndef SUBLANG_SPANISH_URUGUAY
551 #define SUBLANG_SPANISH_URUGUAY 0x0e
552 #endif
553 #ifndef SUBLANG_SPANISH_PARAGUAY
554 #define SUBLANG_SPANISH_PARAGUAY 0x0f
555 #endif
556 #ifndef SUBLANG_SPANISH_BOLIVIA
557 #define SUBLANG_SPANISH_BOLIVIA 0x10
558 #endif
559 #ifndef SUBLANG_SPANISH_EL_SALVADOR
560 #define SUBLANG_SPANISH_EL_SALVADOR 0x11
561 #endif
562 #ifndef SUBLANG_SPANISH_HONDURAS
563 #define SUBLANG_SPANISH_HONDURAS 0x12
564 #endif
565 #ifndef SUBLANG_SPANISH_NICARAGUA
566 #define SUBLANG_SPANISH_NICARAGUA 0x13
567 #endif
568 #ifndef SUBLANG_SPANISH_PUERTO_RICO
569 #define SUBLANG_SPANISH_PUERTO_RICO 0x14
570 #endif
571 #ifndef SUBLANG_SWEDISH_FINLAND
572 #define SUBLANG_SWEDISH_FINLAND 0x02
573 #endif
574 #ifndef SUBLANG_TAMAZIGHT_ARABIC
575 #define SUBLANG_TAMAZIGHT_ARABIC 0x01
576 #endif
577 #ifndef SUBLANG_TAMAZIGHT_LATIN
578 #define SUBLANG_TAMAZIGHT_LATIN 0x02
579 #endif
580 #ifndef SUBLANG_TIGRINYA_ETHIOPIA
581 #define SUBLANG_TIGRINYA_ETHIOPIA 0x00
582 #endif
583 #ifndef SUBLANG_TIGRINYA_ERITREA
584 #define SUBLANG_TIGRINYA_ERITREA 0x01
585 #endif
586 #ifndef SUBLANG_URDU_PAKISTAN
587 #define SUBLANG_URDU_PAKISTAN 0x01
588 #endif
589 #ifndef SUBLANG_URDU_INDIA
590 #define SUBLANG_URDU_INDIA 0x02
591 #endif
592 #ifndef SUBLANG_UZBEK_LATIN
593 #define SUBLANG_UZBEK_LATIN 0x01
594 #endif
595 #ifndef SUBLANG_UZBEK_CYRILLIC
596 #define SUBLANG_UZBEK_CYRILLIC 0x02
597 #endif
599 /* Return an XPG style locale name
600 language[_territory[.codeset]][@modifier].
601 Don't even bother determining the codeset; it's not useful in this
602 context, because message catalogs are not specific to a single
603 codeset. The result must not be freed; it is statically
604 allocated. */
605 static const char *
606 my_nl_locale_name (const char *categoryname)
608 const char *retval;
609 LCID lcid;
610 LANGID langid;
611 int primary, sub;
613 /* Let the user override the system settings through environment
614 variables, as on POSIX systems. */
615 retval = getenv ("LC_ALL");
616 if (retval != NULL && retval[0] != '\0')
617 return retval;
618 retval = getenv (categoryname);
619 if (retval != NULL && retval[0] != '\0')
620 return retval;
621 retval = getenv ("LANG");
622 if (retval != NULL && retval[0] != '\0')
623 return retval;
625 /* Use native Win32 API locale ID. */
626 lcid = GetThreadLocale ();
628 /* Strip off the sorting rules, keep only the language part. */
629 langid = LANGIDFROMLCID (lcid);
631 /* Split into language and territory part. */
632 primary = PRIMARYLANGID (langid);
633 sub = SUBLANGID (langid);
635 /* Dispatch on language.
636 See also http://www.unicode.org/unicode/onlinedat/languages.html .
637 For details about languages, see http://www.ethnologue.com/ . */
638 switch (primary)
640 case LANG_AFRIKAANS: return "af_ZA";
641 case LANG_ALBANIAN: return "sq_AL";
642 case LANG_AMHARIC: return "am_ET";
643 case LANG_ARABIC:
644 switch (sub)
646 case SUBLANG_ARABIC_SAUDI_ARABIA: return "ar_SA";
647 case SUBLANG_ARABIC_IRAQ: return "ar_IQ";
648 case SUBLANG_ARABIC_EGYPT: return "ar_EG";
649 case SUBLANG_ARABIC_LIBYA: return "ar_LY";
650 case SUBLANG_ARABIC_ALGERIA: return "ar_DZ";
651 case SUBLANG_ARABIC_MOROCCO: return "ar_MA";
652 case SUBLANG_ARABIC_TUNISIA: return "ar_TN";
653 case SUBLANG_ARABIC_OMAN: return "ar_OM";
654 case SUBLANG_ARABIC_YEMEN: return "ar_YE";
655 case SUBLANG_ARABIC_SYRIA: return "ar_SY";
656 case SUBLANG_ARABIC_JORDAN: return "ar_JO";
657 case SUBLANG_ARABIC_LEBANON: return "ar_LB";
658 case SUBLANG_ARABIC_KUWAIT: return "ar_KW";
659 case SUBLANG_ARABIC_UAE: return "ar_AE";
660 case SUBLANG_ARABIC_BAHRAIN: return "ar_BH";
661 case SUBLANG_ARABIC_QATAR: return "ar_QA";
663 return "ar";
664 case LANG_ARMENIAN: return "hy_AM";
665 case LANG_ASSAMESE: return "as_IN";
666 case LANG_AZERI:
667 switch (sub)
669 /* FIXME: Adjust this when Azerbaijani locales appear on Unix. */
670 case SUBLANG_AZERI_LATIN: return "az_AZ@latin";
671 case SUBLANG_AZERI_CYRILLIC: return "az_AZ@cyrillic";
673 return "az";
674 case LANG_BASQUE:
675 return "eu"; /* Ambiguous: could be "eu_ES" or "eu_FR". */
676 case LANG_BELARUSIAN: return "be_BY";
677 case LANG_BENGALI:
678 switch (sub)
680 case SUBLANG_BENGALI_INDIA: return "bn_IN";
681 case SUBLANG_BENGALI_BANGLADESH: return "bn_BD";
683 return "bn";
684 case LANG_BULGARIAN: return "bg_BG";
685 case LANG_BURMESE: return "my_MM";
686 case LANG_CAMBODIAN: return "km_KH";
687 case LANG_CATALAN: return "ca_ES";
688 case LANG_CHEROKEE: return "chr_US";
689 case LANG_CHINESE:
690 switch (sub)
692 case SUBLANG_CHINESE_TRADITIONAL: return "zh_TW";
693 case SUBLANG_CHINESE_SIMPLIFIED: return "zh_CN";
694 case SUBLANG_CHINESE_HONGKONG: return "zh_HK";
695 case SUBLANG_CHINESE_SINGAPORE: return "zh_SG";
696 case SUBLANG_CHINESE_MACAU: return "zh_MO";
698 return "zh";
699 case LANG_CROATIAN: /* LANG_CROATIAN == LANG_SERBIAN
700 * What used to be called Serbo-Croatian
701 * should really now be two separate
702 * languages because of political reasons.
703 * (Says tml, who knows nothing about Serbian
704 * or Croatian.)
705 * (I can feel those flames coming already.)
707 switch (sub)
709 case SUBLANG_DEFAULT: return "hr_HR";
710 case SUBLANG_SERBIAN_LATIN: return "sr_CS";
711 case SUBLANG_SERBIAN_CYRILLIC: return "sr_CS@cyrillic";
713 return "hr";
714 case LANG_CZECH: return "cs_CZ";
715 case LANG_DANISH: return "da_DK";
716 case LANG_DIVEHI: return "div_MV";
717 case LANG_DUTCH:
718 switch (sub)
720 case SUBLANG_DUTCH: return "nl_NL";
721 case SUBLANG_DUTCH_BELGIAN: /* FLEMISH, VLAAMS */ return "nl_BE";
723 return "nl";
724 case LANG_EDO: return "bin_NG";
725 case LANG_ENGLISH:
726 switch (sub)
728 /* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought
729 * English was the language spoken in England.
730 * Oh well.
732 case SUBLANG_ENGLISH_US: return "en_US";
733 case SUBLANG_ENGLISH_UK: return "en_GB";
734 case SUBLANG_ENGLISH_AUS: return "en_AU";
735 case SUBLANG_ENGLISH_CAN: return "en_CA";
736 case SUBLANG_ENGLISH_NZ: return "en_NZ";
737 case SUBLANG_ENGLISH_EIRE: return "en_IE";
738 case SUBLANG_ENGLISH_SOUTH_AFRICA: return "en_ZA";
739 case SUBLANG_ENGLISH_JAMAICA: return "en_JM";
740 case SUBLANG_ENGLISH_CARIBBEAN: return "en_GD"; /* Grenada? */
741 case SUBLANG_ENGLISH_BELIZE: return "en_BZ";
742 case SUBLANG_ENGLISH_TRINIDAD: return "en_TT";
743 case SUBLANG_ENGLISH_ZIMBABWE: return "en_ZW";
744 case SUBLANG_ENGLISH_PHILIPPINES: return "en_PH";
745 case SUBLANG_ENGLISH_INDONESIA: return "en_ID";
746 case SUBLANG_ENGLISH_HONGKONG: return "en_HK";
747 case SUBLANG_ENGLISH_INDIA: return "en_IN";
748 case SUBLANG_ENGLISH_MALAYSIA: return "en_MY";
749 case SUBLANG_ENGLISH_SINGAPORE: return "en_SG";
751 return "en";
752 case LANG_ESTONIAN: return "et_EE";
753 case LANG_FAEROESE: return "fo_FO";
754 case LANG_FARSI: return "fa_IR";
755 case LANG_FINNISH: return "fi_FI";
756 case LANG_FRENCH:
757 switch (sub)
759 case SUBLANG_FRENCH: return "fr_FR";
760 case SUBLANG_FRENCH_BELGIAN: /* WALLOON */ return "fr_BE";
761 case SUBLANG_FRENCH_CANADIAN: return "fr_CA";
762 case SUBLANG_FRENCH_SWISS: return "fr_CH";
763 case SUBLANG_FRENCH_LUXEMBOURG: return "fr_LU";
764 case SUBLANG_FRENCH_MONACO: return "fr_MC";
765 case SUBLANG_FRENCH_WESTINDIES: return "fr"; /* Caribbean? */
766 case SUBLANG_FRENCH_REUNION: return "fr_RE";
767 case SUBLANG_FRENCH_CONGO: return "fr_CG";
768 case SUBLANG_FRENCH_SENEGAL: return "fr_SN";
769 case SUBLANG_FRENCH_CAMEROON: return "fr_CM";
770 case SUBLANG_FRENCH_COTEDIVOIRE: return "fr_CI";
771 case SUBLANG_FRENCH_MALI: return "fr_ML";
772 case SUBLANG_FRENCH_MOROCCO: return "fr_MA";
773 case SUBLANG_FRENCH_HAITI: return "fr_HT";
775 return "fr";
776 case LANG_FRISIAN: return "fy_NL";
777 case LANG_FULFULDE: return "ful_NG";
778 case LANG_GAELIC:
779 switch (sub)
781 case 0x01: /* SCOTTISH */ return "gd_GB";
782 case 0x02: /* IRISH */ return "ga_IE";
784 return "C";
785 case LANG_GALICIAN: return "gl_ES";
786 case LANG_GEORGIAN: return "ka_GE";
787 case LANG_GERMAN:
788 switch (sub)
790 case SUBLANG_GERMAN: return "de_DE";
791 case SUBLANG_GERMAN_SWISS: return "de_CH";
792 case SUBLANG_GERMAN_AUSTRIAN: return "de_AT";
793 case SUBLANG_GERMAN_LUXEMBOURG: return "de_LU";
794 case SUBLANG_GERMAN_LIECHTENSTEIN: return "de_LI";
796 return "de";
797 case LANG_GREEK: return "el_GR";
798 case LANG_GUARANI: return "gn_PY";
799 case LANG_GUJARATI: return "gu_IN";
800 case LANG_HAUSA: return "ha_NG";
801 case LANG_HAWAIIAN:
802 /* FIXME: Do they mean Hawaiian ("haw_US", 1000 speakers)
803 or Hawaii Creole English ("cpe_US", 600000 speakers)? */
804 return "cpe_US";
805 case LANG_HEBREW: return "he_IL";
806 case LANG_HINDI: return "hi_IN";
807 case LANG_HUNGARIAN: return "hu_HU";
808 case LANG_IBIBIO: return "nic_NG";
809 case LANG_ICELANDIC: return "is_IS";
810 case LANG_IGBO: return "ibo_NG";
811 case LANG_INDONESIAN: return "id_ID";
812 case LANG_INUKTITUT: return "iu_CA";
813 case LANG_ITALIAN:
814 switch (sub)
816 case SUBLANG_ITALIAN: return "it_IT";
817 case SUBLANG_ITALIAN_SWISS: return "it_CH";
819 return "it";
820 case LANG_JAPANESE: return "ja_JP";
821 case LANG_KANNADA: return "kn_IN";
822 case LANG_KANURI: return "kau_NG";
823 case LANG_KASHMIRI:
824 switch (sub)
826 case SUBLANG_DEFAULT: return "ks_PK";
827 case SUBLANG_KASHMIRI_INDIA: return "ks_IN";
829 return "ks";
830 case LANG_KAZAK: return "kk_KZ";
831 case LANG_KONKANI:
832 /* FIXME: Adjust this when such locales appear on Unix. */
833 return "kok_IN";
834 case LANG_KOREAN: return "ko_KR";
835 case LANG_KYRGYZ: return "ky_KG";
836 case LANG_LAO: return "lo_LA";
837 case LANG_LATIN: return "la_VA";
838 case LANG_LATVIAN: return "lv_LV";
839 case LANG_LITHUANIAN: return "lt_LT";
840 case LANG_MACEDONIAN: return "mk_MK";
841 case LANG_MALAY:
842 switch (sub)
844 case SUBLANG_MALAY_MALAYSIA: return "ms_MY";
845 case SUBLANG_MALAY_BRUNEI_DARUSSALAM: return "ms_BN";
847 return "ms";
848 case LANG_MALAYALAM: return "ml_IN";
849 case LANG_MALTESE: return "mt_MT";
850 case LANG_MANIPURI:
851 /* FIXME: Adjust this when such locales appear on Unix. */
852 return "mni_IN";
853 case LANG_MARATHI: return "mr_IN";
854 case LANG_MONGOLIAN:
855 return "mn"; /* Ambiguous: could be "mn_CN" or "mn_MN". */
856 case LANG_NEPALI:
857 switch (sub)
859 case SUBLANG_DEFAULT: return "ne_NP";
860 case SUBLANG_NEPALI_INDIA: return "ne_IN";
862 return "ne";
863 case LANG_NORWEGIAN:
864 switch (sub)
866 case SUBLANG_NORWEGIAN_BOKMAL: return "no_NO";
867 case SUBLANG_NORWEGIAN_NYNORSK: return "nn_NO";
869 return "no";
870 case LANG_ORIYA: return "or_IN";
871 case LANG_OROMO: return "om_ET";
872 case LANG_PAPIAMENTU: return "pap_AN";
873 case LANG_PASHTO:
874 return "ps"; /* Ambiguous: could be "ps_PK" or "ps_AF". */
875 case LANG_POLISH: return "pl_PL";
876 case LANG_PORTUGUESE:
877 switch (sub)
879 case SUBLANG_PORTUGUESE: return "pt_PT";
880 /* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT.
881 Same phenomenon as SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. */
882 case SUBLANG_PORTUGUESE_BRAZILIAN: return "pt_BR";
884 return "pt";
885 case LANG_PUNJABI:
886 switch (sub)
888 case SUBLANG_PUNJABI_INDIA: return "pa_IN"; /* Gurmukhi script */
890 return "pa";
891 case LANG_RHAETO_ROMANCE: return "rm_CH";
892 case LANG_ROMANIAN:
893 switch (sub)
895 case SUBLANG_ROMANIAN_ROMANIA: return "ro_RO";
897 return "ro";
898 case LANG_RUSSIAN:
899 return "ru"; /* Ambiguous: could be "ru_RU" or "ru_UA" or "ru_MD". */
900 case LANG_SAAMI: /* actually Northern Sami */ return "se_NO";
901 case LANG_SANSKRIT: return "sa_IN";
902 case LANG_SINDHI:
903 switch (sub)
905 case SUBLANG_SINDHI_INDIA: return "sd_IN";
906 case SUBLANG_SINDHI_PAKISTAN: return "sd_PK";
908 return "sd";
909 case LANG_SINHALESE: return "si_LK";
910 case LANG_SLOVAK: return "sk_SK";
911 case LANG_SLOVENIAN: return "sl_SI";
912 case LANG_SOMALI: return "so_SO";
913 case LANG_SORBIAN:
914 /* FIXME: Adjust this when such locales appear on Unix. */
915 return "wen_DE";
916 case LANG_SPANISH:
917 switch (sub)
919 case SUBLANG_SPANISH: return "es_ES";
920 case SUBLANG_SPANISH_MEXICAN: return "es_MX";
921 case SUBLANG_SPANISH_MODERN:
922 return "es_ES@modern"; /* not seen on Unix */
923 case SUBLANG_SPANISH_GUATEMALA: return "es_GT";
924 case SUBLANG_SPANISH_COSTA_RICA: return "es_CR";
925 case SUBLANG_SPANISH_PANAMA: return "es_PA";
926 case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: return "es_DO";
927 case SUBLANG_SPANISH_VENEZUELA: return "es_VE";
928 case SUBLANG_SPANISH_COLOMBIA: return "es_CO";
929 case SUBLANG_SPANISH_PERU: return "es_PE";
930 case SUBLANG_SPANISH_ARGENTINA: return "es_AR";
931 case SUBLANG_SPANISH_ECUADOR: return "es_EC";
932 case SUBLANG_SPANISH_CHILE: return "es_CL";
933 case SUBLANG_SPANISH_URUGUAY: return "es_UY";
934 case SUBLANG_SPANISH_PARAGUAY: return "es_PY";
935 case SUBLANG_SPANISH_BOLIVIA: return "es_BO";
936 case SUBLANG_SPANISH_EL_SALVADOR: return "es_SV";
937 case SUBLANG_SPANISH_HONDURAS: return "es_HN";
938 case SUBLANG_SPANISH_NICARAGUA: return "es_NI";
939 case SUBLANG_SPANISH_PUERTO_RICO: return "es_PR";
941 return "es";
942 case LANG_SUTU: return "bnt_TZ"; /* or "st_LS" or "nso_ZA"? */
943 case LANG_SWAHILI: return "sw_KE";
944 case LANG_SWEDISH:
945 switch (sub)
947 case SUBLANG_DEFAULT: return "sv_SE";
948 case SUBLANG_SWEDISH_FINLAND: return "sv_FI";
950 return "sv";
951 case LANG_SYRIAC: return "syr_TR"; /* An extinct language. */
952 case LANG_TAGALOG: return "tl_PH";
953 case LANG_TAJIK: return "tg_TJ";
954 case LANG_TAMAZIGHT:
955 switch (sub)
957 /* FIXME: Adjust this when Tamazight locales appear on Unix. */
958 case SUBLANG_TAMAZIGHT_ARABIC: return "ber_MA@arabic";
959 case SUBLANG_TAMAZIGHT_LATIN: return "ber_MA@latin";
961 return "ber_MA";
962 case LANG_TAMIL:
963 return "ta"; /* Ambiguous: could be "ta_IN" or "ta_LK" or "ta_SG". */
964 case LANG_TATAR: return "tt_RU";
965 case LANG_TELUGU: return "te_IN";
966 case LANG_THAI: return "th_TH";
967 case LANG_TIBETAN: return "bo_CN";
968 case LANG_TIGRINYA:
969 switch (sub)
971 case SUBLANG_TIGRINYA_ETHIOPIA: return "ti_ET";
972 case SUBLANG_TIGRINYA_ERITREA: return "ti_ER";
974 return "ti";
975 case LANG_TSONGA: return "ts_ZA";
976 case LANG_TSWANA: return "tn_BW";
977 case LANG_TURKISH: return "tr_TR";
978 case LANG_TURKMEN: return "tk_TM";
979 case LANG_UKRAINIAN: return "uk_UA";
980 case LANG_URDU:
981 switch (sub)
983 case SUBLANG_URDU_PAKISTAN: return "ur_PK";
984 case SUBLANG_URDU_INDIA: return "ur_IN";
986 return "ur";
987 case LANG_UZBEK:
988 switch (sub)
990 case SUBLANG_UZBEK_LATIN: return "uz_UZ";
991 case SUBLANG_UZBEK_CYRILLIC: return "uz_UZ@cyrillic";
993 return "uz";
994 case LANG_VENDA:
995 /* FIXME: It's not clear whether Venda has the ISO 639-2 two-letter code
996 "ve" or not.
997 http://www.loc.gov/standards/iso639-2/englangn.html has it, but
998 http://lcweb.loc.gov/standards/iso639-2/codechanges.html doesn't, */
999 return "ven_ZA"; /* or "ve_ZA"? */
1000 case LANG_VIETNAMESE: return "vi_VN";
1001 case LANG_WELSH: return "cy_GB";
1002 case LANG_XHOSA: return "xh_ZA";
1003 case LANG_YI: return "sit_CN";
1004 case LANG_YIDDISH: return "yi_IL";
1005 case LANG_YORUBA: return "yo_NG";
1006 case LANG_ZULU: return "zu_ZA";
1007 default: return "C";
1011 /* localname.c from gettext END. */
1015 /* Support functions. */
1017 static __inline__ uint32_t
1018 do_swap_u32 (uint32_t i)
1020 return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
1023 #define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data))
1026 /* We assume to have `unsigned long int' value with at least 32 bits. */
1027 #define HASHWORDBITS 32
1029 /* The so called `hashpjw' function by P.J. Weinberger
1030 [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
1031 1986, 1987 Bell Telephone Laboratories, Inc.] */
1032 static __inline__ unsigned long
1033 hash_string( const char *str_param )
1035 unsigned long int hval, g;
1036 const char *str = str_param;
1038 hval = 0;
1039 while (*str != '\0')
1041 hval <<= 4;
1042 hval += (unsigned long int) *str++;
1043 g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
1044 if (g != 0)
1046 hval ^= g >> (HASHWORDBITS - 8);
1047 hval ^= g;
1050 return hval;
1053 /* static char * */
1054 /* my_xstrdup (const char *s) */
1055 /* { */
1056 /* size_t n = strlen (s) + 1; */
1057 /* char *p = jnlib_malloc (n); */
1058 /* if (!p) */
1059 /* abort (); */
1060 /* strcpy (p, s); */
1061 /* return p; */
1062 /* } */
1066 /* Generic message catalog and gettext stuff. */
1068 /* The magic number of the GNU message catalog format. */
1069 #define MAGIC 0x950412de
1070 #define MAGIC_SWAPPED 0xde120495
1072 /* Revision number of the currently used .mo (binary) file format. */
1073 #define MO_REVISION_NUMBER 0
1076 /* Header for binary .mo file format. */
1077 struct mo_file_header
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;
1096 struct string_desc
1098 /* Length of addressed string. */
1099 uint32_t length;
1100 /* Offset of string in file. */
1101 uint32_t offset;
1105 struct overflow_space_s
1107 struct overflow_space_s *next;
1108 uint32_t idx;
1109 uint32_t length;
1110 char d[1];
1113 struct loaded_domain
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 uint32_t nstrings;
1120 uint32_t *mapped; /* 0 := Not mapped (original utf8).
1121 1 := Mapped to native encoding in overflow space.
1122 >=2 := Mapped to native encoding. The values
1123 gives the length of the mapped string.
1124 becuase the 0 is included and an empty
1125 string is not allowed we will enver get
1126 values 0 and 1. */
1127 struct overflow_space_s *overflow_space;
1128 struct string_desc *orig_tab;
1129 struct string_desc *trans_tab;
1130 uint32_t hash_size;
1131 uint32_t *hash_tab;
1135 /* The domain we use. We only support one domain at this point. This
1136 is why this implementation can not be shared. Bindtextdomain and
1137 dgettext will simply cheat and always use this one domain. */
1138 static struct loaded_domain *the_domain;
1140 /* Global flag to switch gettext into an utf8 mode. */
1141 static int want_utf8;
1145 /* Free the domain data. */
1146 static void
1147 free_domain (struct loaded_domain *domain)
1149 struct overflow_space_s *os, *os2;
1151 jnlib_free (domain->data);
1152 jnlib_free (domain->mapped);
1153 for (os = domain->overflow_space; os; os = os2)
1155 os2 = os->next;
1156 jnlib_free (os);
1158 jnlib_free (domain);
1162 static struct loaded_domain *
1163 load_domain (const char *filename)
1165 FILE *fp;
1166 size_t size;
1167 struct stat st;
1168 struct mo_file_header *data = NULL;
1169 struct loaded_domain *domain = NULL;
1170 size_t to_read;
1171 char *read_ptr;
1173 fp = fopen (filename, "rb");
1174 if (!fp)
1175 return NULL;
1177 /* Determine the file size. */
1178 if (fstat (fileno (fp), &st)
1179 || (size = (size_t) st.st_size) != st.st_size
1180 || size < sizeof (struct mo_file_header))
1182 fclose (fp);
1183 return NULL;
1186 data = (2*size <= size)? NULL : jnlib_malloc (2*size);
1187 if (!data)
1189 fclose (fp);
1190 return NULL;
1193 to_read = size;
1194 read_ptr = (char *) data;
1197 long int nb = fread (read_ptr, 1, to_read, fp);
1198 if (nb < to_read)
1200 fclose (fp);
1201 jnlib_free (data);
1202 return NULL;
1204 read_ptr += nb;
1205 to_read -= nb;
1207 while (to_read > 0);
1208 fclose (fp);
1210 /* Using the magic number we can test whether it really is a message
1211 catalog file. */
1212 if (data->magic != MAGIC && data->magic != MAGIC_SWAPPED)
1214 /* The magic number is wrong: not a message catalog file. */
1215 jnlib_free (data);
1216 return NULL;
1219 domain = jnlib_calloc (1, sizeof *domain);
1220 if (!domain)
1222 jnlib_free (data);
1223 return NULL;
1225 domain->data = (char *) data;
1226 domain->data_native = (char *) data + size;
1227 domain->must_swap = data->magic != MAGIC;
1229 /* Fill in the information about the available tables. */
1230 switch (SWAPIT (domain->must_swap, data->revision))
1232 case MO_REVISION_NUMBER:
1233 domain->nstrings = SWAPIT (domain->must_swap, data->nstrings);
1234 domain->orig_tab = (struct string_desc *)
1235 ((char *) data + SWAPIT (domain->must_swap, data->orig_tab_offset));
1236 domain->trans_tab = (struct string_desc *)
1237 ((char *) data + SWAPIT (domain->must_swap, data->trans_tab_offset));
1238 domain->hash_size = SWAPIT (domain->must_swap, data->hash_tab_size);
1239 domain->hash_tab = (uint32_t *)
1240 ((char *) data + SWAPIT (domain->must_swap, data->hash_tab_offset));
1241 break;
1243 default:
1244 /* This is an invalid revision. */
1245 jnlib_free (data);
1246 jnlib_free (domain);
1247 return NULL;
1250 /* Allocate an array to keep track of code page mappings. */
1251 domain->mapped = jnlib_calloc (domain->nstrings, sizeof *domain->mapped);
1252 if (!domain->mapped)
1254 jnlib_free (data);
1255 jnlib_free (domain);
1256 return NULL;
1259 return domain;
1263 /* Return a malloced wide char string from an UTF-8 encoded input
1264 string STRING. Caller must free this value. On failure returns
1265 NULL. The result of calling this function with STRING set to NULL
1266 is not defined. */
1267 static wchar_t *
1268 utf8_to_wchar (const char *string, size_t length, size_t *retlen)
1270 int n;
1271 wchar_t *result;
1272 size_t nbytes;
1274 n = MultiByteToWideChar (CP_UTF8, 0, string, length, NULL, 0);
1275 if (n < 0 || (n+1) <= 0)
1276 return NULL;
1278 nbytes = (size_t)(n+1) * sizeof(*result);
1279 if (nbytes / sizeof(*result) != (n+1))
1281 errno = ENOMEM;
1282 return NULL;
1284 result = jnlib_malloc (nbytes);
1285 if (!result)
1286 return NULL;
1288 n = MultiByteToWideChar (CP_UTF8, 0, string, length, result, n);
1289 if (n < 0)
1291 jnlib_free (result);
1292 return NULL;
1294 *retlen = n;
1295 return result;
1299 /* Return a malloced string encoded in UTF-8 from the wide char input
1300 string STRING. Caller must free this value. On failure returns
1301 NULL. The result of calling this function with STRING set to NULL
1302 is not defined. */
1303 static char *
1304 wchar_to_native (const wchar_t *string, size_t length, size_t *retlen)
1306 int n;
1307 char *result;
1309 n = WideCharToMultiByte (CP_ACP, 0, string, length, NULL, 0, NULL, NULL);
1310 if (n < 0 || (n+1) <= 0)
1311 return NULL;
1313 result = jnlib_malloc (n+1);
1314 if (!result)
1315 return NULL;
1317 n = WideCharToMultiByte (CP_ACP, 0, string, length, result, n, NULL, NULL);
1318 if (n < 0)
1320 jnlib_free (result);
1321 return NULL;
1323 *retlen = n;
1324 return result;
1328 /* Convert UTF8 to the native codepage. Caller must free the return value. */
1329 static char *
1330 utf8_to_native (const char *string, size_t length, size_t *retlen)
1332 wchar_t *wstring;
1333 char *result;
1334 size_t newlen;
1336 wstring = utf8_to_wchar (string, length, &newlen);
1337 if (wstring)
1339 result = wchar_to_native (wstring, newlen, &newlen);
1340 jnlib_free (wstring);
1342 else
1343 result = NULL;
1344 *retlen = result? newlen : 0;
1345 return result;
1351 /* Specify that the DOMAINNAME message catalog will be found
1352 in DIRNAME rather than in the system locale data base. */
1353 char *
1354 bindtextdomain (const char *domainname, const char *dirname)
1356 struct loaded_domain *domain = NULL;
1357 const char *catval_full;
1358 char *catval;
1359 char *fname;
1361 /* DOMAINNAME is ignored. We only support one domain. */
1363 /* DIRNAME is "$INSTALLDIR\share\locale". */
1365 /* First find out the category value. */
1366 catval = NULL;
1367 catval_full = my_nl_locale_name ("LC_MESSAGES");
1369 /* Normally, we would have to loop over all returned locales, and
1370 search for the right file. See gettext intl/dcigettext.c for all
1371 the gory details. Here, we only support the basic category, and
1372 ignore everything else. */
1373 if (catval_full)
1375 char *p;
1377 catval = jnlib_malloc (strlen (catval_full) + 1);
1378 if (catval)
1380 strcpy (catval, catval_full);
1381 p = strchr (catval, '_');
1382 if (p)
1383 *p = '\0';
1386 if (!catval)
1387 return NULL;
1389 /* Now build the filename string. The complete filename is this:
1390 DIRNAME + \ + CATVAL + \LC_MESSAGES\ + DOMAINNAME + .mo */
1392 int len = strlen (dirname) + 1 + strlen (catval) + 13
1393 + strlen (domainname) + 3 + 1;
1394 char *p;
1396 fname = jnlib_malloc (len);
1397 if (!fname)
1399 jnlib_free (catval);
1400 return NULL;
1403 p = fname;
1404 strcpy (p, dirname);
1405 p += strlen (dirname);
1406 *(p++) = '\\';
1407 strcpy (p, catval);
1408 p += strlen (catval);
1409 strcpy (p, "\\LC_MESSAGES\\");
1410 p += 13;
1411 strcpy (p, domainname);
1412 p += strlen (domainname);
1413 strcpy (p, ".mo");
1416 domain = load_domain (fname);
1417 jnlib_free (catval);
1418 jnlib_free (fname);
1420 /* We should not be invoked twice, but this is how you would do
1421 it if it happened. */
1422 if (the_domain)
1423 free_domain (the_domain);
1424 the_domain = domain;
1426 /* For historic reasons we are not allowed to return a const char*. */
1427 return (char*)dirname;
1433 static const char *
1434 get_plural (const char *data, size_t datalen, unsigned long nplural)
1436 const char *p;
1437 int idx;
1439 /* We only support the Germanic rule. */
1440 idx = (nplural == 1? 0 : 1);
1442 for (; idx; idx--)
1444 p = strchr (data, 0) + 1;
1445 if (p >= data+datalen)
1446 return "ERROR in GETTEXT (bad plural entry)";
1447 datalen -= (p-data);
1448 data = p;
1450 return data;
1454 static const char*
1455 get_string (struct loaded_domain *domain, uint32_t idx,
1456 int use_plural, unsigned long nplural)
1458 struct overflow_space_s *os;
1459 const char *trans; /* Pointer to the translated entry. */
1460 size_t translen; /* Length of that entry. */
1462 if (want_utf8)
1464 trans = (domain->data
1465 + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
1466 translen = SWAPIT(domain->must_swap, domain->trans_tab[idx].length);
1468 else if (!domain->mapped[idx])
1470 /* Not yet mapped. Map from utf-8 to native encoding now. */
1471 const char *p_utf8;
1472 size_t plen_utf8, buflen;
1473 char *buf;
1475 p_utf8 = (domain->data
1476 + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
1477 plen_utf8 = SWAPIT(domain->must_swap, domain->trans_tab[idx].length);
1479 buf = utf8_to_native (p_utf8, plen_utf8, &buflen);
1480 if (!buf)
1482 trans = "ERROR in GETTEXT MALLOC";
1483 translen = 0;
1485 else if (buflen <= plen_utf8 && buflen > 1)
1487 /* Copy into the DATA_NATIVE area. */
1488 char *p_tmp;
1490 p_tmp = (domain->data_native
1491 + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
1492 memcpy (p_tmp, buf, buflen);
1493 domain->mapped[idx] = buflen;
1494 trans = p_tmp;
1495 translen = buflen;
1497 else
1499 /* There is not enough space for the translation (or for
1500 whatever reason an empry string is used): Store it in the
1501 overflow_space and mark that in the mapped array.
1502 Because UTF-8 strings are in general longer than the
1503 Windows 2 byte encodings, we expect that this won't
1504 happen too often (if at all) and thus we use a linked
1505 list to manage this space. */
1506 os = jnlib_malloc (sizeof *os + buflen);
1507 if (os)
1509 os->idx = idx;
1510 memcpy (os->d, buf, buflen);
1511 os->length = buflen;
1512 os->next = domain->overflow_space;
1513 domain->overflow_space = os;
1514 domain->mapped[idx] = 1;
1515 trans = os->d;
1516 translen = os->length;
1518 else
1520 trans = "ERROR in GETTEXT MALLOC";
1521 translen = 0;
1524 jnlib_free (buf);
1526 else if (domain->mapped[idx] == 1)
1528 /* The translated string is in the overflow_space. */
1529 for (os=domain->overflow_space; os; os = os->next)
1530 if (os->idx == idx)
1531 break;
1532 if (os)
1534 trans = os->d;
1535 translen = os->length;
1537 else
1539 trans = "ERROR in GETTEXT (overflow space)\n";
1540 translen = 0;
1543 else
1545 trans = (domain->data_native
1546 + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset));
1547 translen = domain->mapped[idx];
1550 if (use_plural && translen)
1551 return get_plural (trans, translen, nplural);
1552 else
1553 return trans;
1557 static const char *
1558 do_gettext (const char *msgid, const char *msgid2, unsigned long nplural)
1560 struct loaded_domain *domain;
1561 uint32_t top, bottom, nstr;
1563 if (!(domain = the_domain))
1564 goto not_found;
1566 /* First try to use the hash table. */
1567 if (domain->hash_size > 2 && domain->hash_tab)
1569 /* Use the hashing table. */
1570 uint32_t len = strlen (msgid);
1571 uint32_t hash_val = hash_string (msgid);
1572 uint32_t idx = hash_val % domain->hash_size;
1573 uint32_t incr = 1 + (hash_val % (domain->hash_size - 2));
1575 while ( (nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx])) )
1577 nstr--;
1578 if (nstr < domain->nstrings
1579 && SWAPIT(domain->must_swap,
1580 domain->orig_tab[nstr].length) >= len
1581 && !strcmp (msgid, (domain->data
1582 + SWAPIT(domain->must_swap,
1583 domain->orig_tab[nstr].offset))))
1585 return get_string (domain, nstr, !!msgid2, nplural);
1588 if (idx >= domain->hash_size - incr)
1589 idx -= domain->hash_size - incr;
1590 else
1591 idx += incr;
1595 /* Now we try the default method: binary search in the sorted array
1596 of messages. */
1597 bottom = 0;
1598 top = domain->nstrings;
1599 while (bottom < top)
1601 int cmp_val;
1603 nstr = (bottom + top) / 2;
1604 cmp_val = strcmp (msgid, (domain->data
1605 + SWAPIT(domain->must_swap,
1606 domain->orig_tab[nstr].offset)));
1607 if (cmp_val < 0)
1608 top = nstr;
1609 else if (cmp_val > 0)
1610 bottom = nstr + 1;
1611 else
1612 return get_string (domain, nstr, !!msgid2, nplural);
1615 not_found:
1616 /* We use the standard Germanic rule if plural has been requested. */
1617 return msgid2? (nplural == 1? msgid : msgid2) : msgid;
1621 char *
1622 textdomain (const char *domainname)
1624 /* For now, support only one domain. */
1625 return (char*)domainname;
1629 const char *
1630 gettext (const char *msgid)
1632 return do_gettext (msgid, NULL, 0);
1635 char *
1636 dgettext (const char *domainname, const char *msgid)
1638 (void)domainname;
1640 /* For now, support only one domain. */
1641 return (char*)do_gettext (msgid, NULL, 0);
1644 const char *
1645 ngettext (const char *msgid1, const char *msgid2, unsigned long int n)
1647 /* We use the simple Germanic plural rule. */
1648 return do_gettext (msgid1, msgid2, n);
1652 /* Return the locale name as used by gettext. The return value will
1653 never be NULL. */
1654 const char *
1655 gettext_localename (void)
1657 const char *s;
1659 s = my_nl_locale_name ("LC_MESSAGES");
1660 return s? s:"";
1663 void
1664 gettext_select_utf8 (int value)
1666 want_utf8 = value;
1670 #ifdef TEST
1672 main (int argc, char **argv)
1674 const char atext1[] =
1675 "Warning: You have entered an insecure passphrase.%%0A"
1676 "A passphrase should be at least %u character long.";
1677 const char atext2[] =
1678 "Warning: You have entered an insecure passphrase.%%0A"
1679 "A passphrase should be at least %u characters long.";
1681 if (argc)
1683 argc--;
1684 argv++;
1687 bindtextdomain ("gnupg2", "c:/programme/gnu/gnupg/share/locale");
1689 printf ("locale is `%s'\n", gettext_localename ());
1690 fputs ("text with N=1:\n", stdout);
1691 fputs (ngettext (atext1, atext2, 1), stdout);
1692 fputs ("\n\ntext with N=2:\n", stdout);
1693 fputs (ngettext (atext1, atext2, 2), stdout);
1694 fputs ("\nready\n", stdout);
1696 return 0;
1699 * Local Variables:
1700 * compile-command: "i586-mingw32msvc-gcc -DTEST -Wall -g w32-gettext.c"
1701 * End:
1703 #endif /*TEST*/