diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /pcp/intl/setlocale.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'pcp/intl/setlocale.c')
| -rw-r--r-- | pcp/intl/setlocale.c | 1059 | 
1 files changed, 1059 insertions, 0 deletions
| diff --git a/pcp/intl/setlocale.c b/pcp/intl/setlocale.c new file mode 100644 index 0000000..b33bff5 --- /dev/null +++ b/pcp/intl/setlocale.c @@ -0,0 +1,1059 @@ +/* setlocale() function that respects the locale chosen by the user. +   Copyright (C) 2009 Free Software Foundation, Inc. +   Written by Bruno Haible <bruno@clisp.org>, 2009. + +   This program is free software: you can redistribute it and/or modify +   it under the terms of the GNU Lesser General Public License as published by +   the Free Software Foundation; either version 2.1 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public License +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* Override setlocale() and newlocale() so that when the default locale is +   requested (locale = "") and no relevant environment variable is set, the +   locale chosen by the user is used. +   This matters on MacOS X 10 and Windows. +   See the comments in localename.c, function gl_locale_name_default.  */ + +#include <locale.h> +#include <stdlib.h> +#include <string.h> + +/* When building a DLL, we must export some functions.  Note that because +   the functions are only defined for binary backward compatibility, we +   don't need to use __declspec(dllimport) in any case.  */ +#if HAVE_VISIBILITY && BUILDING_DLL +# define DLL_EXPORTED __attribute__((__visibility__("default"))) +#elif defined _MSC_VER && BUILDING_DLL +# define DLL_EXPORTED __declspec(dllexport) +#else +# define DLL_EXPORTED +#endif + +#include "gettextP.h" + +#if (defined __APPLE__ && defined __MACH__) || defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ + +# undef setlocale +# undef newlocale + +/* Return string representation of locale category CATEGORY.  */ +static const char * +category_to_name (int category) +{ +  const char *retval; + +  switch (category) +  { +  case LC_COLLATE: +    retval = "LC_COLLATE"; +    break; +  case LC_CTYPE: +    retval = "LC_CTYPE"; +    break; +  case LC_MONETARY: +    retval = "LC_MONETARY"; +    break; +  case LC_NUMERIC: +    retval = "LC_NUMERIC"; +    break; +  case LC_TIME: +    retval = "LC_TIME"; +    break; +  case LC_MESSAGES: +    retval = "LC_MESSAGES"; +    break; +  default: +    /* If you have a better idea for a default value let me know.  */ +    retval = "LC_XXX"; +  } + +  return retval; +} + +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + +/* The native Win32 setlocale() function expects locale names of the form +   "German" or "German_Germany" or "DEU", but not "de" or "de_DE".  We need +   to convert the names from the form with ISO 639 language code and ISO 3166 +   country code to the form with English names or with three-letter identifier. +   The three-letter identifiers known by a Windows XP SP2 or SP3 are: +     AFK  Afrikaans_South Africa.1252 +     ARA  Arabic_Saudi Arabia.1256 +     ARB  Arabic_Lebanon.1256 +     ARE  Arabic_Egypt.1256 +     ARG  Arabic_Algeria.1256 +     ARH  Arabic_Bahrain.1256 +     ARI  Arabic_Iraq.1256 +     ARJ  Arabic_Jordan.1256 +     ARK  Arabic_Kuwait.1256 +     ARL  Arabic_Libya.1256 +     ARM  Arabic_Morocco.1256 +     ARO  Arabic_Oman.1256 +     ARQ  Arabic_Qatar.1256 +     ARS  Arabic_Syria.1256 +     ART  Arabic_Tunisia.1256 +     ARU  Arabic_U.A.E..1256 +     ARY  Arabic_Yemen.1256 +     AZE  Azeri (Latin)_Azerbaijan.1254 +     BEL  Belarusian_Belarus.1251 +     BGR  Bulgarian_Bulgaria.1251 +     BSB  Bosnian_Bosnia and Herzegovina.1250 +     BSC  Bosnian (Cyrillic)_Bosnia and Herzegovina.1250  (wrong encoding!) +     CAT  Catalan_Spain.1252 +     CHH  Chinese_Hong Kong S.A.R..950 +     CHI  Chinese_Singapore.936 +     CHS  Chinese_People's Republic of China.936 +     CHT  Chinese_Taiwan.950 +     CSY  Czech_Czech Republic.1250 +     CYM  Welsh_United Kingdom.1252 +     DAN  Danish_Denmark.1252 +     DEA  German_Austria.1252 +     DEC  German_Liechtenstein.1252 +     DEL  German_Luxembourg.1252 +     DES  German_Switzerland.1252 +     DEU  German_Germany.1252 +     ELL  Greek_Greece.1253 +     ENA  English_Australia.1252 +     ENB  English_Caribbean.1252 +     ENC  English_Canada.1252 +     ENG  English_United Kingdom.1252 +     ENI  English_Ireland.1252 +     ENJ  English_Jamaica.1252 +     ENL  English_Belize.1252 +     ENP  English_Republic of the Philippines.1252 +     ENS  English_South Africa.1252 +     ENT  English_Trinidad and Tobago.1252 +     ENU  English_United States.1252 +     ENW  English_Zimbabwe.1252 +     ENZ  English_New Zealand.1252 +     ESA  Spanish_Panama.1252 +     ESB  Spanish_Bolivia.1252 +     ESC  Spanish_Costa Rica.1252 +     ESD  Spanish_Dominican Republic.1252 +     ESE  Spanish_El Salvador.1252 +     ESF  Spanish_Ecuador.1252 +     ESG  Spanish_Guatemala.1252 +     ESH  Spanish_Honduras.1252 +     ESI  Spanish_Nicaragua.1252 +     ESL  Spanish_Chile.1252 +     ESM  Spanish_Mexico.1252 +     ESN  Spanish_Spain.1252 +     ESO  Spanish_Colombia.1252 +     ESP  Spanish_Spain.1252 +     ESR  Spanish_Peru.1252 +     ESS  Spanish_Argentina.1252 +     ESU  Spanish_Puerto Rico.1252 +     ESV  Spanish_Venezuela.1252 +     ESY  Spanish_Uruguay.1252 +     ESZ  Spanish_Paraguay.1252 +     ETI  Estonian_Estonia.1257 +     EUQ  Basque_Spain.1252 +     FAR  Farsi_Iran.1256 +     FIN  Finnish_Finland.1252 +     FOS  Faroese_Faroe Islands.1252 +     FPO  Filipino_Philippines.1252 +     FRA  French_France.1252 +     FRB  French_Belgium.1252 +     FRC  French_Canada.1252 +     FRL  French_Luxembourg.1252 +     FRM  French_Principality of Monaco.1252 +     FRS  French_Switzerland.1252 +     FYN  Frisian_Netherlands.1252 +     GLC  Galician_Spain.1252 +     HEB  Hebrew_Israel.1255 +     HRB  Croatian_Bosnia and Herzegovina.1250 +     HRV  Croatian_Croatia.1250 +     HUN  Hungarian_Hungary.1250 +     IND  Indonesian_Indonesia.1252 +     IRE  Irish_Ireland.1252 +     ISL  Icelandic_Iceland.1252 +     ITA  Italian_Italy.1252 +     ITS  Italian_Switzerland.1252 +     IUK  Inuktitut (Latin)_Canada.1252 +     JPN  Japanese_Japan.932 +     KKZ  Kazakh_Kazakhstan.1251 +     KOR  Korean_Korea.949 +     KYR  Kyrgyz_Kyrgyzstan.1251 +     LBX  Luxembourgish_Luxembourg.1252 +     LTH  Lithuanian_Lithuania.1257 +     LVI  Latvian_Latvia.1257 +     MKI  FYRO Macedonian_Former Yugoslav Republic of Macedonia.1251 +     MON  Mongolian_Mongolia.1251 +     MPD  Mapudungun_Chile.1252 +     MSB  Malay_Brunei Darussalam.1252 +     MSL  Malay_Malaysia.1252 +     MWK  Mohawk_Canada.1252 +     NLB  Dutch_Belgium.1252 +     NLD  Dutch_Netherlands.1252 +     NON  Norwegian-Nynorsk_Norway.1252 +     NOR  Norwegian (Bokmål)_Norway.1252 +     NSO  Northern Sotho_South Africa.1252 +     PLK  Polish_Poland.1250 +     PTB  Portuguese_Brazil.1252 +     PTG  Portuguese_Portugal.1252 +     QUB  Quechua_Bolivia.1252 +     QUE  Quechua_Ecuador.1252 +     QUP  Quechua_Peru.1252 +     RMC  Romansh_Switzerland.1252 +     ROM  Romanian_Romania.1250 +     RUS  Russian_Russia.1251 +     SKY  Slovak_Slovakia.1250 +     SLV  Slovenian_Slovenia.1250 +     SMA  Sami (Southern)_Norway.1252 +     SMB  Sami (Southern)_Sweden.1252 +     SME  Sami (Northern)_Norway.1252 +     SMF  Sami (Northern)_Sweden.1252 +     SMG  Sami (Northern)_Finland.1252 +     SMJ  Sami (Lule)_Norway.1252 +     SMK  Sami (Lule)_Sweden.1252 +     SMN  Sami (Inari)_Finland.1252 +     SMS  Sami (Skolt)_Finland.1252 +     SQI  Albanian_Albania.1250 +     SRB  Serbian (Cyrillic)_Serbia and Montenegro.1251 +     SRL  Serbian (Latin)_Serbia and Montenegro.1250 +     SRN  Serbian (Cyrillic)_Bosnia and Herzegovina.1251 +     SRS  Serbian (Latin)_Bosnia and Herzegovina.1250 +     SVE  Swedish_Sweden.1252 +     SVF  Swedish_Finland.1252 +     SWK  Swahili_Kenya.1252 +     THA  Thai_Thailand.874 +     TRK  Turkish_Turkey.1254 +     TSN  Tswana_South Africa.1252 +     TTT  Tatar_Russia.1251 +     UKR  Ukrainian_Ukraine.1251 +     URD  Urdu_Islamic Republic of Pakistan.1256 +     USA  English_United States.1252 +     UZB  Uzbek (Latin)_Uzbekistan.1254 +     VIT  Vietnamese_Viet Nam.1258 +     XHO  Xhosa_South Africa.1252 +     ZHH  Chinese_Hong Kong S.A.R..950 +     ZHI  Chinese_Singapore.936 +     ZHM  Chinese_Macau S.A.R..950 +     ZUL  Zulu_South Africa.1252 + */ + +/* Table from ISO 639 language code, optionally with country or script suffix, +   to English name. +   Keep in sync with the gl_locale_name_from_win32_LANGID function in +   localename.c!  */ +struct table_entry +{ +  const char *code; +  const char *english; +}; +static const struct table_entry language_table[] = +  { +    { "af", "Afrikaans" }, +    { "am", "Amharic" }, +    { "ar", "Arabic" }, +    { "arn", "Mapudungun" }, +    { "as", "Assamese" }, +    { "az@cyrillic", "Azeri (Cyrillic)" }, +    { "az@latin", "Azeri (Latin)" }, +    { "ba", "Bashkir" }, +    { "be", "Belarusian" }, +    { "ber", "Tamazight" }, +    { "ber@arabic", "Tamazight (Arabic)" }, +    { "ber@latin", "Tamazight (Latin)" }, +    { "bg", "Bulgarian" }, +    { "bin", "Edo" }, +    { "bn", "Bengali" }, +    { "bn_BD", "Bengali (Bangladesh)" }, +    { "bn_IN", "Bengali (India)" }, +    { "bnt", "Sutu" }, +    { "bo", "Tibetan" }, +    { "br", "Breton" }, +    { "bs", "BSB" }, /* "Bosnian (Latin)" */ +    { "bs@cyrillic", "BSC" }, /* Bosnian (Cyrillic) */ +    { "ca", "Catalan" }, +    { "chr", "Cherokee" }, +    { "co", "Corsican" }, +    { "cpe", "Hawaiian" }, +    { "cs", "Czech" }, +    { "cy", "Welsh" }, +    { "da", "Danish" }, +    { "de", "German" }, +    { "dsb", "Lower Sorbian" }, +    { "dv", "Divehi" }, +    { "el", "Greek" }, +    { "en", "English" }, +    { "es", "Spanish" }, +    { "et", "Estonian" }, +    { "eu", "Basque" }, +    { "fa", "Farsi" }, +    { "ff", "Fulfulde" }, +    { "fi", "Finnish" }, +    { "fo", "Faroese" }, /* "Faeroese" does not work */ +    { "fr", "French" }, +    { "fy", "Frisian" }, +    { "ga", "IRE" }, /* Gaelic (Ireland) */ +    { "gd", "Gaelic (Scotland)" }, +    { "gd", "Scottish Gaelic" }, +    { "gl", "Galician" }, +    { "gn", "Guarani" }, +    { "gsw", "Alsatian" }, +    { "gu", "Gujarati" }, +    { "ha", "Hausa" }, +    { "he", "Hebrew" }, +    { "hi", "Hindi" }, +    { "hr", "Croatian" }, +    { "hsb", "Upper Sorbian" }, +    { "hu", "Hungarian" }, +    { "hy", "Armenian" }, +    { "id", "Indonesian" }, +    { "ig", "Igbo" }, +    { "ii", "Yi" }, +    { "is", "Icelandic" }, +    { "it", "Italian" }, +    { "iu", "IUK" }, /* Inuktitut */ +    { "ja", "Japanese" }, +    { "ka", "Georgian" }, +    { "kk", "Kazakh" }, +    { "kl", "Greenlandic" }, +    { "km", "Cambodian" }, +    { "km", "Khmer" }, +    { "kn", "Kannada" }, +    { "ko", "Korean" }, +    { "kok", "Konkani" }, +    { "kr", "Kanuri" }, +    { "ks", "Kashmiri" }, +    { "ks_IN", "Kashmiri_India" }, +    { "ks_PK", "Kashmiri (Arabic)_Pakistan" }, +    { "ky", "Kyrgyz" }, +    { "la", "Latin" }, +    { "lb", "Luxembourgish" }, +    { "lo", "Lao" }, +    { "lt", "Lithuanian" }, +    { "lv", "Latvian" }, +    { "mi", "Maori" }, +    { "mk", "FYRO Macedonian" }, +    { "mk", "Macedonian" }, +    { "ml", "Malayalam" }, +    { "mn", "Mongolian" }, +    { "mni", "Manipuri" }, +    { "moh", "Mohawk" }, +    { "mr", "Marathi" }, +    { "ms", "Malay" }, +    { "mt", "Maltese" }, +    { "my", "Burmese" }, +    { "nb", "NOR" }, /* Norwegian Bokmål */ +    { "ne", "Nepali" }, +    { "nic", "Ibibio" }, +    { "nl", "Dutch" }, +    { "nn", "NON" }, /* Norwegian Nynorsk */ +    { "no", "Norwegian" }, +    { "nso", "Northern Sotho" }, +    { "nso", "Sepedi" }, +    { "oc", "Occitan" }, +    { "om", "Oromo" }, +    { "or", "Oriya" }, +    { "pa", "Punjabi" }, +    { "pap", "Papiamentu" }, +    { "pl", "Polish" }, +    { "prs", "Dari" }, +    { "ps", "Pashto" }, +    { "pt", "Portuguese" }, +    { "qu", "Quechua" }, +    { "qut", "K'iche'" }, +    { "rm", "Romansh" }, +    { "ro", "Romanian" }, +    { "ru", "Russian" }, +    { "rw", "Kinyarwanda" }, +    { "sa", "Sanskrit" }, +    { "sah", "Yakut" }, +    { "sd", "Sindhi" }, +    { "se", "Sami (Northern)" }, +    { "se", "Northern Sami" }, +    { "si", "Sinhalese" }, +    { "sk", "Slovak" }, +    { "sl", "Slovenian" }, +    { "sma", "Sami (Southern)" }, +    { "sma", "Southern Sami" }, +    { "smj", "Sami (Lule)" }, +    { "smj", "Lule Sami" }, +    { "smn", "Sami (Inari)" }, +    { "smn", "Inari Sami" }, +    { "sms", "Sami (Skolt)" }, +    { "sms", "Skolt Sami" }, +    { "so", "Somali" }, +    { "sq", "Albanian" }, +    { "sr", "Serbian (Latin)" }, +    { "sr@cyrillic", "SRB" }, /* Serbian (Cyrillic) */ +    { "sw", "Swahili" }, +    { "syr", "Syriac" }, +    { "ta", "Tamil" }, +    { "te", "Telugu" }, +    { "tg", "Tajik" }, +    { "th", "Thai" }, +    { "ti", "Tigrinya" }, +    { "tk", "Turkmen" }, +    { "tl", "Filipino" }, +    { "tn", "Tswana" }, +    { "tr", "Turkish" }, +    { "ts", "Tsonga" }, +    { "tt", "Tatar" }, +    { "ug", "Uighur" }, +    { "uk", "Ukrainian" }, +    { "ur", "Urdu" }, +    { "uz", "Uzbek" }, +    { "uz", "Uzbek (Latin)" }, +    { "uz@cyrillic", "Uzbek (Cyrillic)" }, +    { "ve", "Venda" }, +    { "vi", "Vietnamese" }, +    { "wen", "Sorbian" }, +    { "wo", "Wolof" }, +    { "xh", "Xhosa" }, +    { "yi", "Yiddish" }, +    { "yo", "Yoruba" }, +    { "zh", "Chinese" }, +    { "zu", "Zulu" } +  }; + +/* Table from ISO 3166 country code to English name. +   Keep in sync with the gl_locale_name_from_win32_LANGID function in +   localename.c!  */ +static const struct table_entry country_table[] = +  { +    { "AE", "U.A.E." }, +    { "AF", "Afghanistan" }, +    { "AL", "Albania" }, +    { "AM", "Armenia" }, +    { "AN", "Netherlands Antilles" }, +    { "AR", "Argentina" }, +    { "AT", "Austria" }, +    { "AU", "Australia" }, +    { "AZ", "Azerbaijan" }, +    { "BA", "Bosnia and Herzegovina" }, +    { "BD", "Bangladesh" }, +    { "BE", "Belgium" }, +    { "BG", "Bulgaria" }, +    { "BH", "Bahrain" }, +    { "BN", "Brunei Darussalam" }, +    { "BO", "Bolivia" }, +    { "BR", "Brazil" }, +    { "BT", "Bhutan" }, +    { "BY", "Belarus" }, +    { "BZ", "Belize" }, +    { "CA", "Canada" }, +    { "CG", "Congo" }, +    { "CH", "Switzerland" }, +    { "CI", "Cote d'Ivoire" }, +    { "CL", "Chile" }, +    { "CM", "Cameroon" }, +    { "CN", "People's Republic of China" }, +    { "CO", "Colombia" }, +    { "CR", "Costa Rica" }, +    { "CS", "Serbia and Montenegro" }, +    { "CZ", "Czech Republic" }, +    { "DE", "Germany" }, +    { "DK", "Denmark" }, +    { "DO", "Dominican Republic" }, +    { "DZ", "Algeria" }, +    { "EC", "Ecuador" }, +    { "EE", "Estonia" }, +    { "EG", "Egypt" }, +    { "ER", "Eritrea" }, +    { "ES", "Spain" }, +    { "ET", "Ethiopia" }, +    { "FI", "Finland" }, +    { "FO", "Faroe Islands" }, +    { "FR", "France" }, +    { "GB", "United Kingdom" }, +    { "GD", "Caribbean" }, +    { "GE", "Georgia" }, +    { "GL", "Greenland" }, +    { "GR", "Greece" }, +    { "GT", "Guatemala" }, +    { "HK", "Hong Kong" }, +    { "HK", "Hong Kong S.A.R." }, +    { "HN", "Honduras" }, +    { "HR", "Croatia" }, +    { "HT", "Haiti" }, +    { "HU", "Hungary" }, +    { "ID", "Indonesia" }, +    { "IE", "Ireland" }, +    { "IL", "Israel" }, +    { "IN", "India" }, +    { "IQ", "Iraq" }, +    { "IR", "Iran" }, +    { "IS", "Iceland" }, +    { "IT", "Italy" }, +    { "JM", "Jamaica" }, +    { "JO", "Jordan" }, +    { "JP", "Japan" }, +    { "KE", "Kenya" }, +    { "KG", "Kyrgyzstan" }, +    { "KH", "Cambodia" }, +    { "KR", "South Korea" }, +    { "KW", "Kuwait" }, +    { "KZ", "Kazakhstan" }, +    { "LA", "Laos" }, +    { "LB", "Lebanon" }, +    { "LI", "Liechtenstein" }, +    { "LK", "Sri Lanka" }, +    { "LT", "Lithuania" }, +    { "LU", "Luxembourg" }, +    { "LV", "Latvia" }, +    { "LY", "Libya" }, +    { "MA", "Morocco" }, +    { "MC", "Principality of Monaco" }, +    { "MD", "Moldava" }, +    { "MD", "Moldova" }, +    { "ME", "Montenegro" }, +    { "MK", "Former Yugoslav Republic of Macedonia" }, +    { "ML", "Mali" }, +    { "MM", "Myanmar" }, +    { "MN", "Mongolia" }, +    { "MO", "Macau S.A.R." }, +    { "MT", "Malta" }, +    { "MV", "Maldives" }, +    { "MX", "Mexico" }, +    { "MY", "Malaysia" }, +    { "NG", "Nigeria" }, +    { "NI", "Nicaragua" }, +    { "NL", "Netherlands" }, +    { "NO", "Norway" }, +    { "NP", "Nepal" }, +    { "NZ", "New Zealand" }, +    { "OM", "Oman" }, +    { "PA", "Panama" }, +    { "PE", "Peru" }, +    { "PH", "Philippines" }, +    { "PK", "Islamic Republic of Pakistan" }, +    { "PL", "Poland" }, +    { "PR", "Puerto Rico" }, +    { "PT", "Portugal" }, +    { "PY", "Paraguay" }, +    { "QA", "Qatar" }, +    { "RE", "Reunion" }, +    { "RO", "Romania" }, +    { "RS", "Serbia" }, +    { "RU", "Russia" }, +    { "RW", "Rwanda" }, +    { "SA", "Saudi Arabia" }, +    { "SE", "Sweden" }, +    { "SG", "Singapore" }, +    { "SI", "Slovenia" }, +    { "SK", "Slovak" }, +    { "SN", "Senegal" }, +    { "SO", "Somalia" }, +    { "SR", "Suriname" }, +    { "SV", "El Salvador" }, +    { "SY", "Syria" }, +    { "TH", "Thailand" }, +    { "TJ", "Tajikistan" }, +    { "TM", "Turkmenistan" }, +    { "TN", "Tunisia" }, +    { "TR", "Turkey" }, +    { "TT", "Trinidad and Tobago" }, +    { "TW", "Taiwan" }, +    { "TZ", "Tanzania" }, +    { "UA", "Ukraine" }, +    { "US", "United States" }, +    { "UY", "Uruguay" }, +    { "VA", "Vatican" }, +    { "VE", "Venezuela" }, +    { "VN", "Viet Nam" }, +    { "YE", "Yemen" }, +    { "ZA", "South Africa" }, +    { "ZW", "Zimbabwe" } +  }; + +/* Given a string STRING, find the set of indices i such that TABLE[i].code is +   the given STRING.  It is a range [lo,hi-1].  */ +typedef struct { size_t lo; size_t hi; } range_t; +static void +search (const struct table_entry *table, size_t table_size, const char *string, +        range_t *result) +{ +  /* The table is sorted.  Perform a binary search.  */ +  size_t hi = table_size; +  size_t lo = 0; +  while (lo < hi) +    { +      /* Invariant: +         for i < lo, strcmp (table[i].code, string) < 0, +         for i >= hi, strcmp (table[i].code, string) > 0.  */ +      size_t mid = (hi + lo) >> 1; /* >= lo, < hi */ +      int cmp = strcmp (table[mid].code, string); +      if (cmp < 0) +        lo = mid + 1; +      else if (cmp > 0) +        hi = mid; +      else +        { +          /* Found an i with +               strcmp (language_table[i].code, string) == 0. +             Find the entire interval of such i.  */ +          { +            size_t i; + +            for (i = mid; i > lo; ) +              { +                i--; +                if (strcmp (table[i].code, string) < 0) +                  { +                    lo = i + 1; +                    break; +                  } +              } +          } +          { +            size_t i; + +            for (i = mid; i < hi; i++) +              { +                if (strcmp (table[i].code, string) > 0) +                  { +                    hi = i; +                    break; +                  } +              } +          } +          /* The set of i with +               strcmp (language_table[i].code, string) == 0 +             is the interval [lo, hi-1].  */ +          break; +        } +    } +  result->lo = lo; +  result->hi = hi; +} + +/* Like setlocale, but accept also locale names in the form ll or ll_CC, +   where ll is an ISO 639 language code and CC is an ISO 3166 country code.  */ +static char * +setlocale_unixlike (int category, const char *locale) +{ +  char *result; +  char llCC_buf[64]; +  char ll_buf[64]; +  char CC_buf[64]; + +  /* First, try setlocale with the original argument unchanged.  */ +  result = setlocale (category, locale); +  if (result != NULL) +    return result; + +  /* Otherwise, assume the argument is in the form +       language[_territory][.codeset][@modifier] +     and try to map it using the tables.  */ +  if (strlen (locale) < sizeof (llCC_buf)) +    { +      /* Second try: Remove the codeset part.  */ +      { +        const char *p = locale; +        char *q = llCC_buf; + +        /* Copy the part before the dot.  */ +        for (; *p != '\0' && *p != '.'; p++, q++) +          *q = *p; +        if (*p == '.') +          /* Skip the part up to the '@', if any.  */ +          for (; *p != '\0' && *p != '@'; p++) +            ; +        /* Copy the part starting with '@', if any.  */ +        for (; *p != '\0'; p++, q++) +          *q = *p; +        *q = '\0'; +      } +      /* llCC_buf now contains +           language[_territory][@modifier] +       */ +      if (strcmp (llCC_buf, locale) != 0) +        { +          result = setlocale (category, llCC_buf); +          if (result != NULL) +            return result; +        } +      /* Look it up in language_table.  */ +      { +        range_t range; +        size_t i; + +        search (language_table, +                sizeof (language_table) / sizeof (language_table[0]), +                llCC_buf, +                &range); + +        for (i = range.lo; i < range.hi; i++) +          { +            /* Try the replacement in language_table[i].  */ +            result = setlocale (category, language_table[i].english); +            if (result != NULL) +              return result; +          } +      } +      /* Split language[_territory][@modifier] +         into  ll_buf = language[@modifier] +         and   CC_buf = territory +       */ +      { +        const char *underscore = strchr (llCC_buf, '_'); +        if (underscore != NULL) +          { +            const char *territory_start = underscore + 1; +            const char *territory_end = strchr (territory_start, '@'); +            if (territory_end == NULL) +              territory_end = territory_start + strlen (territory_start); + +            memcpy (ll_buf, llCC_buf, underscore - llCC_buf); +            strcpy (ll_buf + (underscore - llCC_buf), territory_end); + +            memcpy (CC_buf, territory_start, territory_end - territory_start); +            CC_buf[territory_end - territory_start] = '\0'; + +            { +              /* Look up ll_buf in language_table +                 and CC_buf in country_table.  */ +              range_t language_range; + +              search (language_table, +                      sizeof (language_table) / sizeof (language_table[0]), +                      ll_buf, +                      &language_range); +              if (language_range.lo < language_range.hi) +                { +                  range_t country_range; + +                  search (country_table, +                          sizeof (country_table) / sizeof (country_table[0]), +                          CC_buf, +                          &country_range); +                  if (country_range.lo < country_range.hi) +                    { +                      size_t i; +                      size_t j; + +                      for (i = language_range.lo; i < language_range.hi; i++) +                        for (j = country_range.lo; j < country_range.hi; j++) +                          { +                            /* Concatenate the replacements.  */ +                            const char *part1 = language_table[i].english; +                            size_t part1_len = strlen (part1); +                            const char *part2 = country_table[j].english; +                            size_t part2_len = strlen (part2) + 1; +                            char buf[64+64]; + +                            if (!(part1_len + 1 + part2_len <= sizeof (buf))) +                              abort (); +                            memcpy (buf, part1, part1_len); +                            buf[part1_len] = '_'; +                            memcpy (buf + part1_len + 1, part2, part2_len); + +                            /* Try the concatenated replacements.  */ +                            result = setlocale (category, buf); +                            if (result != NULL) +                              return result; +                          } +                    } + +                  /* Try omitting the country entirely.  This may set a locale +                     corresponding to the wrong country, but is better than +                     failing entirely.  */ +                  { +                    size_t i; + +                    for (i = language_range.lo; i < language_range.hi; i++) +                      { +                        /* Try only the language replacement.  */ +                        result = +                          setlocale (category, language_table[i].english); +                        if (result != NULL) +                          return result; +                      } +                  } +                } +            } +          } +      } +    } + +  /* Failed.  */ +  return NULL; +} + +# else +#  define setlocale_unixlike setlocale +# endif + +# if LC_MESSAGES == 1729 + +/* The system does not store an LC_MESSAGES locale category.  Do it here.  */ +static char lc_messages_name[64] = "C"; + +/* Like setlocale, but support also LC_MESSAGES.  */ +static char * +setlocale_single (int category, const char *locale) +{ +  if (category == LC_MESSAGES) +    { +      if (locale != NULL) +        { +          lc_messages_name[sizeof (lc_messages_name) - 1] = '\0'; +          strncpy (lc_messages_name, locale, sizeof (lc_messages_name) - 1); +        } +      return lc_messages_name; +    } +  else +    return setlocale_unixlike (category, locale); +} + +# else +#  define setlocale_single setlocale_unixlike +# endif + +DLL_EXPORTED +char * +libintl_setlocale (int category, const char *locale) +{ +  if (locale != NULL && locale[0] == '\0') +    { +      /* A request to the set the current locale to the default locale.  */ +      if (category == LC_ALL) +        { +          /* Set LC_CTYPE first.  Then the other categories.  */ +          static int const categories[] = +            { +              LC_NUMERIC, +              LC_TIME, +              LC_COLLATE, +              LC_MONETARY, +              LC_MESSAGES +            }; +          char *saved_locale; +          const char *base_name; +          unsigned int i; + +          /* Back up the old locale, in case one of the steps fails.  */ +          saved_locale = setlocale (LC_ALL, NULL); +          if (saved_locale == NULL) +            return NULL; +          saved_locale = strdup (saved_locale); +          if (saved_locale == NULL) +            return NULL; + +          /* Set LC_CTYPE category.  Set all other categories (except possibly +             LC_MESSAGES) to the same value in the same call; this is likely to +             save calls.  */ +          base_name = +            gl_locale_name_environ (LC_CTYPE, category_to_name (LC_CTYPE)); +          if (base_name == NULL) +            base_name = gl_locale_name_default (); + +          if (setlocale_unixlike (LC_ALL, base_name) == NULL) +            goto fail; +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +          /* On native Windows, setlocale(LC_ALL,...) may succeed but set the +             LC_CTYPE category to an invalid value ("C") when it does not +             support the specified encoding.  Report a failure instead.  */ +          if (strchr (base_name, '.') != NULL +              && strcmp (setlocale (LC_CTYPE, NULL), "C") == 0) +            goto fail; +# endif + +          for (i = 0; i < sizeof (categories) / sizeof (categories[0]); i++) +            { +              int cat = categories[i]; +              const char *name; + +              name = gl_locale_name_environ (cat, category_to_name (cat)); +              if (name == NULL) +                name = gl_locale_name_default (); + +              /* If name is the same as base_name, it has already been set +                 through the setlocale call before the loop.  */ +              if (strcmp (name, base_name) != 0 +# if LC_MESSAGES == 1729 +                  || cat == LC_MESSAGES +# endif +                 ) +                if (setlocale_single (cat, name) == NULL) +                  goto fail; +            } + +          /* All steps were successful.  */ +          free (saved_locale); +          return setlocale (LC_ALL, NULL); + +        fail: +          if (saved_locale[0] != '\0') /* don't risk an endless recursion */ +            setlocale (LC_ALL, saved_locale); +          free (saved_locale); +          return NULL; +        } +      else +        { +          const char *name = +            gl_locale_name_environ (category, category_to_name (category)); +          if (name == NULL) +            name = gl_locale_name_default (); + +          return setlocale_single (category, name); +        } +    } +  else +    { +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +      if (category == LC_ALL && locale != NULL && strchr (locale, '.') != NULL) +        { +          char *saved_locale; + +          /* Back up the old locale.  */ +          saved_locale = setlocale (LC_ALL, NULL); +          if (saved_locale == NULL) +            return NULL; +          saved_locale = strdup (saved_locale); +          if (saved_locale == NULL) +            return NULL; + +          if (setlocale_unixlike (LC_ALL, locale) == NULL) +            { +              free (saved_locale); +              return NULL; +            } + +          /* On native Windows, setlocale(LC_ALL,...) may succeed but set the +             LC_CTYPE category to an invalid value ("C") when it does not +             support the specified encoding.  Report a failure instead.  */ +          if (strcmp (setlocale (LC_CTYPE, NULL), "C") == 0) +            { +              if (saved_locale[0] != '\0') /* don't risk an endless recursion */ +                setlocale (LC_ALL, saved_locale); +              free (saved_locale); +              return NULL; +            } + +          /* It was really successful.  */ +          free (saved_locale); +          return setlocale (LC_ALL, NULL); +        } +      else +# endif +        return setlocale_single (category, locale); +    } +} + +# if HAVE_NEWLOCALE + +DLL_EXPORTED +locale_t +libintl_newlocale (int category_mask, const char *locale, locale_t base) +{ +  if (category_mask != 0 && locale != NULL && locale[0] == '\0') +    { +      /* A request to construct a locale_t object that refers to the default +         locale.  */ + +      /* Set LC_CTYPE first.  Then the other categories.  */ +      static struct { int cat; int mask; } const categories[] = +        { +          { LC_CTYPE,    LC_CTYPE_MASK }, +          { LC_NUMERIC,  LC_NUMERIC_MASK }, +          { LC_TIME,     LC_TIME_MASK }, +          { LC_COLLATE,  LC_COLLATE_MASK }, +          { LC_MONETARY, LC_MONETARY_MASK }, +          { LC_MESSAGES, LC_MESSAGES_MASK } +        }; + +      locale_t orig_base = base; + +      if ((LC_ALL_MASK & ~category_mask) == 0) +        { +          const char *base_name; +          unsigned int i; + +          /* Set LC_CTYPE category.  Set all other categories (except possibly +             LC_MESSAGES) to the same value in the same call; this is likely to +             save calls.  */ +          base_name = +            gl_locale_name_environ (LC_CTYPE, category_to_name (LC_CTYPE)); +          if (base_name == NULL) +            base_name = gl_locale_name_default (); + +          base = newlocale (LC_ALL_MASK, base_name, base); +          if (base == NULL) +            return NULL; + +          for (i = 1; i < sizeof (categories) / sizeof (categories[0]); i++) +            { +              int category = categories[i].cat; +              int category_mask = categories[i].mask; +              const char *name; + +              name = +                gl_locale_name_environ (category, category_to_name (category)); +              if (name == NULL) +                name = gl_locale_name_default (); + +              /* If name is the same as base_name, it has already been set +                 through the setlocale call before the loop.  */ +              if (strcmp (name, base_name) != 0) +                { +                  locale_t copy = newlocale (category_mask, name, base); +                  if (copy == NULL) +                    goto fail; +                  /* No need to call freelocale (base) if copy != base; the +                     newlocale function already takes care of doing it.  */ +                  base = copy; +                } +            } +        } +      else +        { +          unsigned int i; + +          for (i = 0; i < sizeof (categories) / sizeof (categories[0]); i++) +            { +              int cat_mask = categories[i].mask; + +              if ((category_mask & cat_mask) != 0) +                { +                  int cat = categories[i].cat; +                  const char *name; +                  locale_t copy; + +                  name = gl_locale_name_environ (cat, category_to_name (cat)); +                  if (name == NULL) +                    name = gl_locale_name_default (); + +                  copy = newlocale (cat_mask, name, base); +                  if (copy == NULL) +                    goto fail; +                  /* No need to call freelocale (base) if copy != base; the +                     newlocale function already takes care of doing it.  */ +                  base = copy; +                } +            } +        } + +      /* All steps were successful.  */ +      return base; + +    fail: +      if (base != NULL && orig_base == NULL) +        { +          int saved_errno = errno; +          freelocale (base); +          errno = saved_errno; +        } +      return NULL; +    } +  else +    return newlocale (category_mask, locale, base); +} + +# endif + +#endif | 
