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