Blame gnulib/tests/setlocale.c

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