root/maint/gnulib/lib/setlocale.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. setlocale_mtsafe
  2. category_to_name
  3. search
  4. setlocale_unixlike
  5. setlocale_unixlike
  6. setlocale_single
  7. langcmp
  8. get_main_locale_with_same_language
  9. terrcmp
  10. get_main_locale_with_same_territory
  11. setlocale_improved

   1 /* Set the current locale.  -*- coding: utf-8 -*-
   2    Copyright (C) 2009, 2011-2021 Free Software Foundation, Inc.
   3 
   4    This file is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU Lesser General Public License as
   6    published by the Free Software Foundation; either version 3 of the
   7    License, or (at your option) any later version.
   8 
   9    This file is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU Lesser General Public License for more details.
  13 
  14    You should have received a copy of the GNU Lesser General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Written by Bruno Haible <bruno@clisp.org>, 2009.  */
  18 
  19 #include <config.h>
  20 
  21 /* Override setlocale() so that when the default locale is requested
  22    (locale = ""), the environment variables LC_ALL, LC_*, and LANG are
  23    considered.
  24    Also include all the functionality from libintl's setlocale() override.  */
  25 
  26 /* Please keep this file in sync with
  27    gettext/gettext-runtime/intl/setlocale.c !  */
  28 
  29 /* Specification.  */
  30 #include <locale.h>
  31 
  32 #include <stdio.h>
  33 #include <stdlib.h>
  34 #include <string.h>
  35 
  36 #include "localename.h"
  37 
  38 #if HAVE_CFLOCALECOPYPREFERREDLANGUAGES || HAVE_CFPREFERENCESCOPYAPPVALUE
  39 # if HAVE_CFLOCALECOPYPREFERREDLANGUAGES
  40 #  include <CoreFoundation/CFLocale.h>
  41 # elif HAVE_CFPREFERENCESCOPYAPPVALUE
  42 #  include <CoreFoundation/CFPreferences.h>
  43 # endif
  44 # include <CoreFoundation/CFPropertyList.h>
  45 # include <CoreFoundation/CFArray.h>
  46 # include <CoreFoundation/CFString.h>
  47 extern void gl_locale_name_canonicalize (char *name);
  48 #endif
  49 
  50 #if 1
  51 
  52 # undef setlocale
  53 
  54 /* Which of the replacements to activate?  */
  55 # if NEED_SETLOCALE_IMPROVED
  56 #  define setlocale_improved rpl_setlocale
  57 # elif NEED_SETLOCALE_MTSAFE
  58 #  define setlocale_mtsafe rpl_setlocale
  59 # else
  60 #  error "This file should only be compiled if NEED_SETLOCALE_IMPROVED || NEED_SETLOCALE_MTSAFE."
  61 # endif
  62 
  63 /* Like setlocale, but guaranteed to be multithread-safe if LOCALE == NULL.  */
  64 # if !SETLOCALE_NULL_ALL_MTSAFE || !SETLOCALE_NULL_ONE_MTSAFE /* i.e. if NEED_SETLOCALE_MTSAFE */
  65 
  66 #  if NEED_SETLOCALE_IMPROVED
  67 static
  68 #  endif
  69 char *
  70 setlocale_mtsafe (int category, const char *locale)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72   if (locale == NULL)
  73     return (char *) setlocale_null (category);
  74   else
  75     return setlocale (category, locale);
  76 }
  77 # else /* !NEED_SETLOCALE_MTSAFE */
  78 
  79 #  define setlocale_mtsafe setlocale
  80 
  81 # endif /* NEED_SETLOCALE_MTSAFE */
  82 
  83 # if NEED_SETLOCALE_IMPROVED
  84 
  85 /* Return string representation of locale category CATEGORY.  */
  86 static const char *
  87 category_to_name (int category)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89   const char *retval;
  90 
  91   switch (category)
  92   {
  93   case LC_COLLATE:
  94     retval = "LC_COLLATE";
  95     break;
  96   case LC_CTYPE:
  97     retval = "LC_CTYPE";
  98     break;
  99   case LC_MONETARY:
 100     retval = "LC_MONETARY";
 101     break;
 102   case LC_NUMERIC:
 103     retval = "LC_NUMERIC";
 104     break;
 105   case LC_TIME:
 106     retval = "LC_TIME";
 107     break;
 108   case LC_MESSAGES:
 109     retval = "LC_MESSAGES";
 110     break;
 111   default:
 112     /* If you have a better idea for a default value let me know.  */
 113     retval = "LC_XXX";
 114   }
 115 
 116   return retval;
 117 }
 118 
 119 #  if defined _WIN32 && ! defined __CYGWIN__
 120 
 121 /* The native Windows setlocale() function expects locale names of the form
 122    "German" or "German_Germany" or "DEU", but not "de" or "de_DE".  We need
 123    to convert the names from the form with ISO 639 language code and ISO 3166
 124    country code to the form with English names or with three-letter identifier.
 125    The three-letter identifiers known by a Windows XP SP2 or SP3 are:
 126      AFK  Afrikaans_South Africa.1252
 127      ARA  Arabic_Saudi Arabia.1256
 128      ARB  Arabic_Lebanon.1256
 129      ARE  Arabic_Egypt.1256
 130      ARG  Arabic_Algeria.1256
 131      ARH  Arabic_Bahrain.1256
 132      ARI  Arabic_Iraq.1256
 133      ARJ  Arabic_Jordan.1256
 134      ARK  Arabic_Kuwait.1256
 135      ARL  Arabic_Libya.1256
 136      ARM  Arabic_Morocco.1256
 137      ARO  Arabic_Oman.1256
 138      ARQ  Arabic_Qatar.1256
 139      ARS  Arabic_Syria.1256
 140      ART  Arabic_Tunisia.1256
 141      ARU  Arabic_U.A.E..1256
 142      ARY  Arabic_Yemen.1256
 143      AZE  Azeri (Latin)_Azerbaijan.1254
 144      BEL  Belarusian_Belarus.1251
 145      BGR  Bulgarian_Bulgaria.1251
 146      BSB  Bosnian_Bosnia and Herzegovina.1250
 147      BSC  Bosnian (Cyrillic)_Bosnia and Herzegovina.1250  (wrong encoding!)
 148      CAT  Catalan_Spain.1252
 149      CHH  Chinese_Hong Kong S.A.R..950
 150      CHI  Chinese_Singapore.936
 151      CHS  Chinese_People's Republic of China.936
 152      CHT  Chinese_Taiwan.950
 153      CSY  Czech_Czech Republic.1250
 154      CYM  Welsh_United Kingdom.1252
 155      DAN  Danish_Denmark.1252
 156      DEA  German_Austria.1252
 157      DEC  German_Liechtenstein.1252
 158      DEL  German_Luxembourg.1252
 159      DES  German_Switzerland.1252
 160      DEU  German_Germany.1252
 161      ELL  Greek_Greece.1253
 162      ENA  English_Australia.1252
 163      ENB  English_Caribbean.1252
 164      ENC  English_Canada.1252
 165      ENG  English_United Kingdom.1252
 166      ENI  English_Ireland.1252
 167      ENJ  English_Jamaica.1252
 168      ENL  English_Belize.1252
 169      ENP  English_Republic of the Philippines.1252
 170      ENS  English_South Africa.1252
 171      ENT  English_Trinidad and Tobago.1252
 172      ENU  English_United States.1252
 173      ENW  English_Zimbabwe.1252
 174      ENZ  English_New Zealand.1252
 175      ESA  Spanish_Panama.1252
 176      ESB  Spanish_Bolivia.1252
 177      ESC  Spanish_Costa Rica.1252
 178      ESD  Spanish_Dominican Republic.1252
 179      ESE  Spanish_El Salvador.1252
 180      ESF  Spanish_Ecuador.1252
 181      ESG  Spanish_Guatemala.1252
 182      ESH  Spanish_Honduras.1252
 183      ESI  Spanish_Nicaragua.1252
 184      ESL  Spanish_Chile.1252
 185      ESM  Spanish_Mexico.1252
 186      ESN  Spanish_Spain.1252
 187      ESO  Spanish_Colombia.1252
 188      ESP  Spanish_Spain.1252
 189      ESR  Spanish_Peru.1252
 190      ESS  Spanish_Argentina.1252
 191      ESU  Spanish_Puerto Rico.1252
 192      ESV  Spanish_Venezuela.1252
 193      ESY  Spanish_Uruguay.1252
 194      ESZ  Spanish_Paraguay.1252
 195      ETI  Estonian_Estonia.1257
 196      EUQ  Basque_Spain.1252
 197      FAR  Farsi_Iran.1256
 198      FIN  Finnish_Finland.1252
 199      FOS  Faroese_Faroe Islands.1252
 200      FPO  Filipino_Philippines.1252
 201      FRA  French_France.1252
 202      FRB  French_Belgium.1252
 203      FRC  French_Canada.1252
 204      FRL  French_Luxembourg.1252
 205      FRM  French_Principality of Monaco.1252
 206      FRS  French_Switzerland.1252
 207      FYN  Frisian_Netherlands.1252
 208      GLC  Galician_Spain.1252
 209      HEB  Hebrew_Israel.1255
 210      HRB  Croatian_Bosnia and Herzegovina.1250
 211      HRV  Croatian_Croatia.1250
 212      HUN  Hungarian_Hungary.1250
 213      IND  Indonesian_Indonesia.1252
 214      IRE  Irish_Ireland.1252
 215      ISL  Icelandic_Iceland.1252
 216      ITA  Italian_Italy.1252
 217      ITS  Italian_Switzerland.1252
 218      IUK  Inuktitut (Latin)_Canada.1252
 219      JPN  Japanese_Japan.932
 220      KKZ  Kazakh_Kazakhstan.1251
 221      KOR  Korean_Korea.949
 222      KYR  Kyrgyz_Kyrgyzstan.1251
 223      LBX  Luxembourgish_Luxembourg.1252
 224      LTH  Lithuanian_Lithuania.1257
 225      LVI  Latvian_Latvia.1257
 226      MKI  FYRO Macedonian_Former Yugoslav Republic of Macedonia.1251
 227      MON  Mongolian_Mongolia.1251
 228      MPD  Mapudungun_Chile.1252
 229      MSB  Malay_Brunei Darussalam.1252
 230      MSL  Malay_Malaysia.1252
 231      MWK  Mohawk_Canada.1252
 232      NLB  Dutch_Belgium.1252
 233      NLD  Dutch_Netherlands.1252
 234      NON  Norwegian-Nynorsk_Norway.1252
 235      NOR  Norwegian (Bokmål)_Norway.1252
 236      NSO  Northern Sotho_South Africa.1252
 237      PLK  Polish_Poland.1250
 238      PTB  Portuguese_Brazil.1252
 239      PTG  Portuguese_Portugal.1252
 240      QUB  Quechua_Bolivia.1252
 241      QUE  Quechua_Ecuador.1252
 242      QUP  Quechua_Peru.1252
 243      RMC  Romansh_Switzerland.1252
 244      ROM  Romanian_Romania.1250
 245      RUS  Russian_Russia.1251
 246      SKY  Slovak_Slovakia.1250
 247      SLV  Slovenian_Slovenia.1250
 248      SMA  Sami (Southern)_Norway.1252
 249      SMB  Sami (Southern)_Sweden.1252
 250      SME  Sami (Northern)_Norway.1252
 251      SMF  Sami (Northern)_Sweden.1252
 252      SMG  Sami (Northern)_Finland.1252
 253      SMJ  Sami (Lule)_Norway.1252
 254      SMK  Sami (Lule)_Sweden.1252
 255      SMN  Sami (Inari)_Finland.1252
 256      SMS  Sami (Skolt)_Finland.1252
 257      SQI  Albanian_Albania.1250
 258      SRB  Serbian (Cyrillic)_Serbia and Montenegro.1251
 259      SRL  Serbian (Latin)_Serbia and Montenegro.1250
 260      SRN  Serbian (Cyrillic)_Bosnia and Herzegovina.1251
 261      SRS  Serbian (Latin)_Bosnia and Herzegovina.1250
 262      SVE  Swedish_Sweden.1252
 263      SVF  Swedish_Finland.1252
 264      SWK  Swahili_Kenya.1252
 265      THA  Thai_Thailand.874
 266      TRK  Turkish_Turkey.1254
 267      TSN  Tswana_South Africa.1252
 268      TTT  Tatar_Russia.1251
 269      UKR  Ukrainian_Ukraine.1251
 270      URD  Urdu_Islamic Republic of Pakistan.1256
 271      USA  English_United States.1252
 272      UZB  Uzbek (Latin)_Uzbekistan.1254
 273      VIT  Vietnamese_Viet Nam.1258
 274      XHO  Xhosa_South Africa.1252
 275      ZHH  Chinese_Hong Kong S.A.R..950
 276      ZHI  Chinese_Singapore.936
 277      ZHM  Chinese_Macau S.A.R..950
 278      ZUL  Zulu_South Africa.1252
 279  */
 280 
 281 /* Table from ISO 639 language code, optionally with country or script suffix,
 282    to English name.
 283    Keep in sync with the gl_locale_name_from_win32_LANGID function in
 284    localename.c!  */
 285 struct table_entry
 286 {
 287   const char *code;
 288   const char *english;
 289 };
 290 static const struct table_entry language_table[] =
 291   {
 292     { "af", "Afrikaans" },
 293     { "am", "Amharic" },
 294     { "ar", "Arabic" },
 295     { "arn", "Mapudungun" },
 296     { "as", "Assamese" },
 297     { "az@cyrillic", "Azeri (Cyrillic)" },
 298     { "az@latin", "Azeri (Latin)" },
 299     { "ba", "Bashkir" },
 300     { "be", "Belarusian" },
 301     { "ber", "Tamazight" },
 302     { "ber@arabic", "Tamazight (Arabic)" },
 303     { "ber@latin", "Tamazight (Latin)" },
 304     { "bg", "Bulgarian" },
 305     { "bin", "Edo" },
 306     { "bn", "Bengali" },
 307     { "bn_BD", "Bengali (Bangladesh)" },
 308     { "bn_IN", "Bengali (India)" },
 309     { "bnt", "Sutu" },
 310     { "bo", "Tibetan" },
 311     { "br", "Breton" },
 312     { "bs", "BSB" }, /* "Bosnian (Latin)" */
 313     { "bs@cyrillic", "BSC" }, /* Bosnian (Cyrillic) */
 314     { "ca", "Catalan" },
 315     { "chr", "Cherokee" },
 316     { "co", "Corsican" },
 317     { "cpe", "Hawaiian" },
 318     { "cs", "Czech" },
 319     { "cy", "Welsh" },
 320     { "da", "Danish" },
 321     { "de", "German" },
 322     { "dsb", "Lower Sorbian" },
 323     { "dv", "Divehi" },
 324     { "el", "Greek" },
 325     { "en", "English" },
 326     { "es", "Spanish" },
 327     { "et", "Estonian" },
 328     { "eu", "Basque" },
 329     { "fa", "Farsi" },
 330     { "ff", "Fulfulde" },
 331     { "fi", "Finnish" },
 332     { "fo", "Faroese" }, /* "Faeroese" does not work */
 333     { "fr", "French" },
 334     { "fy", "Frisian" },
 335     { "ga", "IRE" }, /* Gaelic (Ireland) */
 336     { "gd", "Gaelic (Scotland)" },
 337     { "gd", "Scottish Gaelic" },
 338     { "gl", "Galician" },
 339     { "gn", "Guarani" },
 340     { "gsw", "Alsatian" },
 341     { "gu", "Gujarati" },
 342     { "ha", "Hausa" },
 343     { "he", "Hebrew" },
 344     { "hi", "Hindi" },
 345     { "hr", "Croatian" },
 346     { "hsb", "Upper Sorbian" },
 347     { "hu", "Hungarian" },
 348     { "hy", "Armenian" },
 349     { "id", "Indonesian" },
 350     { "ig", "Igbo" },
 351     { "ii", "Yi" },
 352     { "is", "Icelandic" },
 353     { "it", "Italian" },
 354     { "iu", "IUK" }, /* Inuktitut */
 355     { "ja", "Japanese" },
 356     { "ka", "Georgian" },
 357     { "kk", "Kazakh" },
 358     { "kl", "Greenlandic" },
 359     { "km", "Cambodian" },
 360     { "km", "Khmer" },
 361     { "kn", "Kannada" },
 362     { "ko", "Korean" },
 363     { "kok", "Konkani" },
 364     { "kr", "Kanuri" },
 365     { "ks", "Kashmiri" },
 366     { "ks_IN", "Kashmiri_India" },
 367     { "ks_PK", "Kashmiri (Arabic)_Pakistan" },
 368     { "ky", "Kyrgyz" },
 369     { "la", "Latin" },
 370     { "lb", "Luxembourgish" },
 371     { "lo", "Lao" },
 372     { "lt", "Lithuanian" },
 373     { "lv", "Latvian" },
 374     { "mi", "Maori" },
 375     { "mk", "FYRO Macedonian" },
 376     { "mk", "Macedonian" },
 377     { "ml", "Malayalam" },
 378     { "mn", "Mongolian" },
 379     { "mni", "Manipuri" },
 380     { "moh", "Mohawk" },
 381     { "mr", "Marathi" },
 382     { "ms", "Malay" },
 383     { "mt", "Maltese" },
 384     { "my", "Burmese" },
 385     { "nb", "NOR" }, /* Norwegian Bokmål */
 386     { "ne", "Nepali" },
 387     { "nic", "Ibibio" },
 388     { "nl", "Dutch" },
 389     { "nn", "NON" }, /* Norwegian Nynorsk */
 390     { "no", "Norwegian" },
 391     { "nso", "Northern Sotho" },
 392     { "nso", "Sepedi" },
 393     { "oc", "Occitan" },
 394     { "om", "Oromo" },
 395     { "or", "Oriya" },
 396     { "pa", "Punjabi" },
 397     { "pap", "Papiamentu" },
 398     { "pl", "Polish" },
 399     { "prs", "Dari" },
 400     { "ps", "Pashto" },
 401     { "pt", "Portuguese" },
 402     { "qu", "Quechua" },
 403     { "qut", "K'iche'" },
 404     { "rm", "Romansh" },
 405     { "ro", "Romanian" },
 406     { "ru", "Russian" },
 407     { "rw", "Kinyarwanda" },
 408     { "sa", "Sanskrit" },
 409     { "sah", "Yakut" },
 410     { "sd", "Sindhi" },
 411     { "se", "Sami (Northern)" },
 412     { "se", "Northern Sami" },
 413     { "si", "Sinhalese" },
 414     { "sk", "Slovak" },
 415     { "sl", "Slovenian" },
 416     { "sma", "Sami (Southern)" },
 417     { "sma", "Southern Sami" },
 418     { "smj", "Sami (Lule)" },
 419     { "smj", "Lule Sami" },
 420     { "smn", "Sami (Inari)" },
 421     { "smn", "Inari Sami" },
 422     { "sms", "Sami (Skolt)" },
 423     { "sms", "Skolt Sami" },
 424     { "so", "Somali" },
 425     { "sq", "Albanian" },
 426     { "sr", "Serbian (Latin)" },
 427     { "sr@cyrillic", "SRB" }, /* Serbian (Cyrillic) */
 428     { "sv", "Swedish" },
 429     { "sw", "Swahili" },
 430     { "syr", "Syriac" },
 431     { "ta", "Tamil" },
 432     { "te", "Telugu" },
 433     { "tg", "Tajik" },
 434     { "th", "Thai" },
 435     { "ti", "Tigrinya" },
 436     { "tk", "Turkmen" },
 437     { "tl", "Filipino" },
 438     { "tn", "Tswana" },
 439     { "tr", "Turkish" },
 440     { "ts", "Tsonga" },
 441     { "tt", "Tatar" },
 442     { "ug", "Uighur" },
 443     { "uk", "Ukrainian" },
 444     { "ur", "Urdu" },
 445     { "uz", "Uzbek" },
 446     { "uz", "Uzbek (Latin)" },
 447     { "uz@cyrillic", "Uzbek (Cyrillic)" },
 448     { "ve", "Venda" },
 449     { "vi", "Vietnamese" },
 450     { "wen", "Sorbian" },
 451     { "wo", "Wolof" },
 452     { "xh", "Xhosa" },
 453     { "yi", "Yiddish" },
 454     { "yo", "Yoruba" },
 455     { "zh", "Chinese" },
 456     { "zu", "Zulu" }
 457   };
 458 
 459 /* Table from ISO 3166 country code to English name.
 460    Keep in sync with the gl_locale_name_from_win32_LANGID function in
 461    localename.c!  */
 462 static const struct table_entry country_table[] =
 463   {
 464     { "AE", "U.A.E." },
 465     { "AF", "Afghanistan" },
 466     { "AL", "Albania" },
 467     { "AM", "Armenia" },
 468     { "AN", "Netherlands Antilles" },
 469     { "AR", "Argentina" },
 470     { "AT", "Austria" },
 471     { "AU", "Australia" },
 472     { "AZ", "Azerbaijan" },
 473     { "BA", "Bosnia and Herzegovina" },
 474     { "BD", "Bangladesh" },
 475     { "BE", "Belgium" },
 476     { "BG", "Bulgaria" },
 477     { "BH", "Bahrain" },
 478     { "BN", "Brunei Darussalam" },
 479     { "BO", "Bolivia" },
 480     { "BR", "Brazil" },
 481     { "BT", "Bhutan" },
 482     { "BY", "Belarus" },
 483     { "BZ", "Belize" },
 484     { "CA", "Canada" },
 485     { "CG", "Congo" },
 486     { "CH", "Switzerland" },
 487     { "CI", "Cote d'Ivoire" },
 488     { "CL", "Chile" },
 489     { "CM", "Cameroon" },
 490     { "CN", "People's Republic of China" },
 491     { "CO", "Colombia" },
 492     { "CR", "Costa Rica" },
 493     { "CS", "Serbia and Montenegro" },
 494     { "CZ", "Czech Republic" },
 495     { "DE", "Germany" },
 496     { "DK", "Denmark" },
 497     { "DO", "Dominican Republic" },
 498     { "DZ", "Algeria" },
 499     { "EC", "Ecuador" },
 500     { "EE", "Estonia" },
 501     { "EG", "Egypt" },
 502     { "ER", "Eritrea" },
 503     { "ES", "Spain" },
 504     { "ET", "Ethiopia" },
 505     { "FI", "Finland" },
 506     { "FO", "Faroe Islands" },
 507     { "FR", "France" },
 508     { "GB", "United Kingdom" },
 509     { "GD", "Caribbean" },
 510     { "GE", "Georgia" },
 511     { "GL", "Greenland" },
 512     { "GR", "Greece" },
 513     { "GT", "Guatemala" },
 514     { "HK", "Hong Kong" },
 515     { "HK", "Hong Kong S.A.R." },
 516     { "HN", "Honduras" },
 517     { "HR", "Croatia" },
 518     { "HT", "Haiti" },
 519     { "HU", "Hungary" },
 520     { "ID", "Indonesia" },
 521     { "IE", "Ireland" },
 522     { "IL", "Israel" },
 523     { "IN", "India" },
 524     { "IQ", "Iraq" },
 525     { "IR", "Iran" },
 526     { "IS", "Iceland" },
 527     { "IT", "Italy" },
 528     { "JM", "Jamaica" },
 529     { "JO", "Jordan" },
 530     { "JP", "Japan" },
 531     { "KE", "Kenya" },
 532     { "KG", "Kyrgyzstan" },
 533     { "KH", "Cambodia" },
 534     { "KR", "South Korea" },
 535     { "KW", "Kuwait" },
 536     { "KZ", "Kazakhstan" },
 537     { "LA", "Laos" },
 538     { "LB", "Lebanon" },
 539     { "LI", "Liechtenstein" },
 540     { "LK", "Sri Lanka" },
 541     { "LT", "Lithuania" },
 542     { "LU", "Luxembourg" },
 543     { "LV", "Latvia" },
 544     { "LY", "Libya" },
 545     { "MA", "Morocco" },
 546     { "MC", "Principality of Monaco" },
 547     { "MD", "Moldava" },
 548     { "MD", "Moldova" },
 549     { "ME", "Montenegro" },
 550     { "MK", "Former Yugoslav Republic of Macedonia" },
 551     { "ML", "Mali" },
 552     { "MM", "Myanmar" },
 553     { "MN", "Mongolia" },
 554     { "MO", "Macau S.A.R." },
 555     { "MT", "Malta" },
 556     { "MV", "Maldives" },
 557     { "MX", "Mexico" },
 558     { "MY", "Malaysia" },
 559     { "NG", "Nigeria" },
 560     { "NI", "Nicaragua" },
 561     { "NL", "Netherlands" },
 562     { "NO", "Norway" },
 563     { "NP", "Nepal" },
 564     { "NZ", "New Zealand" },
 565     { "OM", "Oman" },
 566     { "PA", "Panama" },
 567     { "PE", "Peru" },
 568     { "PH", "Philippines" },
 569     { "PK", "Islamic Republic of Pakistan" },
 570     { "PL", "Poland" },
 571     { "PR", "Puerto Rico" },
 572     { "PT", "Portugal" },
 573     { "PY", "Paraguay" },
 574     { "QA", "Qatar" },
 575     { "RE", "Reunion" },
 576     { "RO", "Romania" },
 577     { "RS", "Serbia" },
 578     { "RU", "Russia" },
 579     { "RW", "Rwanda" },
 580     { "SA", "Saudi Arabia" },
 581     { "SE", "Sweden" },
 582     { "SG", "Singapore" },
 583     { "SI", "Slovenia" },
 584     { "SK", "Slovak" },
 585     { "SN", "Senegal" },
 586     { "SO", "Somalia" },
 587     { "SR", "Suriname" },
 588     { "SV", "El Salvador" },
 589     { "SY", "Syria" },
 590     { "TH", "Thailand" },
 591     { "TJ", "Tajikistan" },
 592     { "TM", "Turkmenistan" },
 593     { "TN", "Tunisia" },
 594     { "TR", "Turkey" },
 595     { "TT", "Trinidad and Tobago" },
 596     { "TW", "Taiwan" },
 597     { "TZ", "Tanzania" },
 598     { "UA", "Ukraine" },
 599     { "US", "United States" },
 600     { "UY", "Uruguay" },
 601     { "VA", "Vatican" },
 602     { "VE", "Venezuela" },
 603     { "VN", "Viet Nam" },
 604     { "YE", "Yemen" },
 605     { "ZA", "South Africa" },
 606     { "ZW", "Zimbabwe" }
 607   };
 608 
 609 /* Given a string STRING, find the set of indices i such that TABLE[i].code is
 610    the given STRING.  It is a range [lo,hi-1].  */
 611 typedef struct { size_t lo; size_t hi; } range_t;
 612 static void
 613 search (const struct table_entry *table, size_t table_size, const char *string,
     /* [previous][next][first][last][top][bottom][index][help] */
 614         range_t *result)
 615 {
 616   /* The table is sorted.  Perform a binary search.  */
 617   size_t hi = table_size;
 618   size_t lo = 0;
 619   while (lo < hi)
 620     {
 621       /* Invariant:
 622          for i < lo, strcmp (table[i].code, string) < 0,
 623          for i >= hi, strcmp (table[i].code, string) > 0.  */
 624       size_t mid = (hi + lo) >> 1; /* >= lo, < hi */
 625       int cmp = strcmp (table[mid].code, string);
 626       if (cmp < 0)
 627         lo = mid + 1;
 628       else if (cmp > 0)
 629         hi = mid;
 630       else
 631         {
 632           /* Found an i with
 633                strcmp (language_table[i].code, string) == 0.
 634              Find the entire interval of such i.  */
 635           {
 636             size_t i;
 637 
 638             for (i = mid; i > lo; )
 639               {
 640                 i--;
 641                 if (strcmp (table[i].code, string) < 0)
 642                   {
 643                     lo = i + 1;
 644                     break;
 645                   }
 646               }
 647           }
 648           {
 649             size_t i;
 650 
 651             for (i = mid + 1; i < hi; i++)
 652               {
 653                 if (strcmp (table[i].code, string) > 0)
 654                   {
 655                     hi = i;
 656                     break;
 657                   }
 658               }
 659           }
 660           /* The set of i with
 661                strcmp (language_table[i].code, string) == 0
 662              is the interval [lo, hi-1].  */
 663           break;
 664         }
 665     }
 666   result->lo = lo;
 667   result->hi = hi;
 668 }
 669 
 670 /* Like setlocale, but accept also locale names in the form ll or ll_CC,
 671    where ll is an ISO 639 language code and CC is an ISO 3166 country code.  */
 672 static char *
 673 setlocale_unixlike (int category, const char *locale)
     /* [previous][next][first][last][top][bottom][index][help] */
 674 {
 675   char *result;
 676   char llCC_buf[64];
 677   char ll_buf[64];
 678   char CC_buf[64];
 679 
 680   /* The native Windows implementation of setlocale understands the special
 681      locale name "C", but not "POSIX".  Therefore map "POSIX" to "C".  */
 682   if (locale != NULL && strcmp (locale, "POSIX") == 0)
 683     locale = "C";
 684 
 685   /* First, try setlocale with the original argument unchanged.  */
 686   result = setlocale_mtsafe (category, locale);
 687   if (result != NULL)
 688     return result;
 689 
 690   /* Otherwise, assume the argument is in the form
 691        language[_territory][.codeset][@modifier]
 692      and try to map it using the tables.  */
 693   if (strlen (locale) < sizeof (llCC_buf))
 694     {
 695       /* Second try: Remove the codeset part.  */
 696       {
 697         const char *p = locale;
 698         char *q = llCC_buf;
 699 
 700         /* Copy the part before the dot.  */
 701         for (; *p != '\0' && *p != '.'; p++, q++)
 702           *q = *p;
 703         if (*p == '.')
 704           /* Skip the part up to the '@', if any.  */
 705           for (; *p != '\0' && *p != '@'; p++)
 706             ;
 707         /* Copy the part starting with '@', if any.  */
 708         for (; *p != '\0'; p++, q++)
 709           *q = *p;
 710         *q = '\0';
 711       }
 712       /* llCC_buf now contains
 713            language[_territory][@modifier]
 714        */
 715       if (strcmp (llCC_buf, locale) != 0)
 716         {
 717           result = setlocale (category, llCC_buf);
 718           if (result != NULL)
 719             return result;
 720         }
 721       /* Look it up in language_table.  */
 722       {
 723         range_t range;
 724         size_t i;
 725 
 726         search (language_table,
 727                 sizeof (language_table) / sizeof (language_table[0]),
 728                 llCC_buf,
 729                 &range);
 730 
 731         for (i = range.lo; i < range.hi; i++)
 732           {
 733             /* Try the replacement in language_table[i].  */
 734             result = setlocale (category, language_table[i].english);
 735             if (result != NULL)
 736               return result;
 737           }
 738       }
 739       /* Split language[_territory][@modifier]
 740          into  ll_buf = language[@modifier]
 741          and   CC_buf = territory
 742        */
 743       {
 744         const char *underscore = strchr (llCC_buf, '_');
 745         if (underscore != NULL)
 746           {
 747             const char *territory_start = underscore + 1;
 748             const char *territory_end = strchr (territory_start, '@');
 749             if (territory_end == NULL)
 750               territory_end = territory_start + strlen (territory_start);
 751 
 752             memcpy (ll_buf, llCC_buf, underscore - llCC_buf);
 753             strcpy (ll_buf + (underscore - llCC_buf), territory_end);
 754 
 755             memcpy (CC_buf, territory_start, territory_end - territory_start);
 756             CC_buf[territory_end - territory_start] = '\0';
 757 
 758             {
 759               /* Look up ll_buf in language_table
 760                  and CC_buf in country_table.  */
 761               range_t language_range;
 762 
 763               search (language_table,
 764                       sizeof (language_table) / sizeof (language_table[0]),
 765                       ll_buf,
 766                       &language_range);
 767               if (language_range.lo < language_range.hi)
 768                 {
 769                   range_t country_range;
 770 
 771                   search (country_table,
 772                           sizeof (country_table) / sizeof (country_table[0]),
 773                           CC_buf,
 774                           &country_range);
 775                   if (country_range.lo < country_range.hi)
 776                     {
 777                       size_t i;
 778                       size_t j;
 779 
 780                       for (i = language_range.lo; i < language_range.hi; i++)
 781                         for (j = country_range.lo; j < country_range.hi; j++)
 782                           {
 783                             /* Concatenate the replacements.  */
 784                             const char *part1 = language_table[i].english;
 785                             size_t part1_len = strlen (part1);
 786                             const char *part2 = country_table[j].english;
 787                             size_t part2_len = strlen (part2) + 1;
 788                             char buf[64+64];
 789 
 790                             if (!(part1_len + 1 + part2_len <= sizeof (buf)))
 791                               abort ();
 792                             memcpy (buf, part1, part1_len);
 793                             buf[part1_len] = '_';
 794                             memcpy (buf + part1_len + 1, part2, part2_len);
 795 
 796                             /* Try the concatenated replacements.  */
 797                             result = setlocale (category, buf);
 798                             if (result != NULL)
 799                               return result;
 800                           }
 801                     }
 802 
 803                   /* Try omitting the country entirely.  This may set a locale
 804                      corresponding to the wrong country, but is better than
 805                      failing entirely.  */
 806                   {
 807                     size_t i;
 808 
 809                     for (i = language_range.lo; i < language_range.hi; i++)
 810                       {
 811                         /* Try only the language replacement.  */
 812                         result =
 813                           setlocale (category, language_table[i].english);
 814                         if (result != NULL)
 815                           return result;
 816                       }
 817                   }
 818                 }
 819             }
 820           }
 821       }
 822     }
 823 
 824   /* Failed.  */
 825   return NULL;
 826 }
 827 
 828 #  elif defined __ANDROID__
 829 
 830 /* Like setlocale, but accept also the locale names "C" and "POSIX".  */
 831 static char *
 832 setlocale_unixlike (int category, const char *locale)
     /* [previous][next][first][last][top][bottom][index][help] */
 833 {
 834   char *result = setlocale_mtsafe (category, locale);
 835   if (result == NULL)
 836     switch (category)
 837       {
 838       case LC_CTYPE:
 839       case LC_NUMERIC:
 840       case LC_TIME:
 841       case LC_COLLATE:
 842       case LC_MONETARY:
 843       case LC_MESSAGES:
 844       case LC_ALL:
 845       case LC_PAPER:
 846       case LC_NAME:
 847       case LC_ADDRESS:
 848       case LC_TELEPHONE:
 849       case LC_MEASUREMENT:
 850         if (locale == NULL
 851             || strcmp (locale, "C") == 0 || strcmp (locale, "POSIX") == 0)
 852           result = (char *) "C";
 853         break;
 854       default:
 855         break;
 856       }
 857   return result;
 858 }
 859 #   define setlocale setlocale_unixlike
 860 
 861 #  else
 862 #   define setlocale_unixlike setlocale_mtsafe
 863 #  endif
 864 
 865 #  if LC_MESSAGES == 1729
 866 
 867 /* The system does not store an LC_MESSAGES locale category.  Do it here.  */
 868 static char lc_messages_name[64] = "C";
 869 
 870 /* Like setlocale, but support also LC_MESSAGES.  */
 871 static char *
 872 setlocale_single (int category, const char *locale)
     /* [previous][next][first][last][top][bottom][index][help] */
 873 {
 874   if (category == LC_MESSAGES)
 875     {
 876       if (locale != NULL)
 877         {
 878           lc_messages_name[sizeof (lc_messages_name) - 1] = '\0';
 879           strncpy (lc_messages_name, locale, sizeof (lc_messages_name) - 1);
 880         }
 881       return lc_messages_name;
 882     }
 883   else
 884     return setlocale_unixlike (category, locale);
 885 }
 886 
 887 #  else
 888 #   define setlocale_single setlocale_unixlike
 889 #  endif
 890 
 891 #  if defined __APPLE__ && defined __MACH__
 892 
 893 /* Mapping from language to main territory where that language is spoken.  */
 894 static char const locales_with_principal_territory[][6 + 1] =
 895   {
 896                 /* Language     Main territory */
 897     "ace_ID",   /* Achinese     Indonesia */
 898     "af_ZA",    /* Afrikaans    South Africa */
 899     "ak_GH",    /* Akan         Ghana */
 900     "am_ET",    /* Amharic      Ethiopia */
 901     "an_ES",    /* Aragonese    Spain */
 902     "ang_GB",   /* Old English  Britain */
 903     "arn_CL",   /* Mapudungun   Chile */
 904     "as_IN",    /* Assamese     India */
 905     "ast_ES",   /* Asturian     Spain */
 906     "av_RU",    /* Avaric       Russia */
 907     "awa_IN",   /* Awadhi       India */
 908     "az_AZ",    /* Azerbaijani  Azerbaijan */
 909     "ban_ID",   /* Balinese     Indonesia */
 910     "be_BY",    /* Belarusian   Belarus */
 911     "bej_SD",   /* Beja         Sudan */
 912     "bem_ZM",   /* Bemba        Zambia */
 913     "bg_BG",    /* Bulgarian    Bulgaria */
 914     "bho_IN",   /* Bhojpuri     India */
 915     "bi_VU",    /* Bislama      Vanuatu */
 916     "bik_PH",   /* Bikol        Philippines */
 917     "bin_NG",   /* Bini         Nigeria */
 918     "bm_ML",    /* Bambara      Mali */
 919     "bn_IN",    /* Bengali      India */
 920     "bo_CN",    /* Tibetan      China */
 921     "br_FR",    /* Breton       France */
 922     "bs_BA",    /* Bosnian      Bosnia */
 923     "bug_ID",   /* Buginese     Indonesia */
 924     "ca_ES",    /* Catalan      Spain */
 925     "ce_RU",    /* Chechen      Russia */
 926     "ceb_PH",   /* Cebuano      Philippines */
 927     "co_FR",    /* Corsican     France */
 928     "cr_CA",    /* Cree         Canada */
 929     /* Don't put "crh_UZ" or "crh_UA" here.  That would be asking for fruitless
 930        political discussion.  */
 931     "cs_CZ",    /* Czech        Czech Republic */
 932     "csb_PL",   /* Kashubian    Poland */
 933     "cy_GB",    /* Welsh        Britain */
 934     "da_DK",    /* Danish       Denmark */
 935     "de_DE",    /* German       Germany */
 936     "din_SD",   /* Dinka        Sudan */
 937     "doi_IN",   /* Dogri        India */
 938     "dsb_DE",   /* Lower Sorbian        Germany */
 939     "dv_MV",    /* Divehi       Maldives */
 940     "dz_BT",    /* Dzongkha     Bhutan */
 941     "ee_GH",    /* Éwé          Ghana */
 942     "el_GR",    /* Greek        Greece */
 943     /* Don't put "en_GB" or "en_US" here.  That would be asking for fruitless
 944        political discussion.  */
 945     "es_ES",    /* Spanish      Spain */
 946     "et_EE",    /* Estonian     Estonia */
 947     "fa_IR",    /* Persian      Iran */
 948     "fi_FI",    /* Finnish      Finland */
 949     "fil_PH",   /* Filipino     Philippines */
 950     "fj_FJ",    /* Fijian       Fiji */
 951     "fo_FO",    /* Faroese      Faeroe Islands */
 952     "fon_BJ",   /* Fon          Benin */
 953     "fr_FR",    /* French       France */
 954     "fur_IT",   /* Friulian     Italy */
 955     "fy_NL",    /* Western Frisian      Netherlands */
 956     "ga_IE",    /* Irish        Ireland */
 957     "gd_GB",    /* Scottish Gaelic      Britain */
 958     "gon_IN",   /* Gondi        India */
 959     "gsw_CH",   /* Swiss German Switzerland */
 960     "gu_IN",    /* Gujarati     India */
 961     "he_IL",    /* Hebrew       Israel */
 962     "hi_IN",    /* Hindi        India */
 963     "hil_PH",   /* Hiligaynon   Philippines */
 964     "hr_HR",    /* Croatian     Croatia */
 965     "hsb_DE",   /* Upper Sorbian        Germany */
 966     "ht_HT",    /* Haitian      Haiti */
 967     "hu_HU",    /* Hungarian    Hungary */
 968     "hy_AM",    /* Armenian     Armenia */
 969     "id_ID",    /* Indonesian   Indonesia */
 970     "ig_NG",    /* Igbo         Nigeria */
 971     "ii_CN",    /* Sichuan Yi   China */
 972     "ilo_PH",   /* Iloko        Philippines */
 973     "is_IS",    /* Icelandic    Iceland */
 974     "it_IT",    /* Italian      Italy */
 975     "ja_JP",    /* Japanese     Japan */
 976     "jab_NG",   /* Hyam         Nigeria */
 977     "jv_ID",    /* Javanese     Indonesia */
 978     "ka_GE",    /* Georgian     Georgia */
 979     "kab_DZ",   /* Kabyle       Algeria */
 980     "kaj_NG",   /* Jju          Nigeria */
 981     "kam_KE",   /* Kamba        Kenya */
 982     "kmb_AO",   /* Kimbundu     Angola */
 983     "kcg_NG",   /* Tyap         Nigeria */
 984     "kdm_NG",   /* Kagoma       Nigeria */
 985     "kg_CD",    /* Kongo        Democratic Republic of Congo */
 986     "kk_KZ",    /* Kazakh       Kazakhstan */
 987     "kl_GL",    /* Kalaallisut  Greenland */
 988     "km_KH",    /* Central Khmer        Cambodia */
 989     "kn_IN",    /* Kannada      India */
 990     "ko_KR",    /* Korean       Korea (South) */
 991     "kok_IN",   /* Konkani      India */
 992     "kr_NG",    /* Kanuri       Nigeria */
 993     "kru_IN",   /* Kurukh       India */
 994     "ky_KG",    /* Kyrgyz       Kyrgyzstan */
 995     "lg_UG",    /* Ganda        Uganda */
 996     "li_BE",    /* Limburgish   Belgium */
 997     "lo_LA",    /* Laotian      Laos */
 998     "lt_LT",    /* Lithuanian   Lithuania */
 999     "lu_CD",    /* Luba-Katanga Democratic Republic of Congo */
1000     "lua_CD",   /* Luba-Lulua   Democratic Republic of Congo */
1001     "luo_KE",   /* Luo          Kenya */
1002     "lv_LV",    /* Latvian      Latvia */
1003     "mad_ID",   /* Madurese     Indonesia */
1004     "mag_IN",   /* Magahi       India */
1005     "mai_IN",   /* Maithili     India */
1006     "mak_ID",   /* Makasar      Indonesia */
1007     "man_ML",   /* Mandingo     Mali */
1008     "men_SL",   /* Mende        Sierra Leone */
1009     "mfe_MU",   /* Mauritian Creole     Mauritius */
1010     "mg_MG",    /* Malagasy     Madagascar */
1011     "mi_NZ",    /* Maori        New Zealand */
1012     "min_ID",   /* Minangkabau  Indonesia */
1013     "mk_MK",    /* Macedonian   North Macedonia */
1014     "ml_IN",    /* Malayalam    India */
1015     "mn_MN",    /* Mongolian    Mongolia */
1016     "mni_IN",   /* Manipuri     India */
1017     "mos_BF",   /* Mossi        Burkina Faso */
1018     "mr_IN",    /* Marathi      India */
1019     "ms_MY",    /* Malay        Malaysia */
1020     "mt_MT",    /* Maltese      Malta */
1021     "mwr_IN",   /* Marwari      India */
1022     "my_MM",    /* Burmese      Myanmar */
1023     "na_NR",    /* Nauru        Nauru */
1024     "nah_MX",   /* Nahuatl      Mexico */
1025     "nap_IT",   /* Neapolitan   Italy */
1026     "nb_NO",    /* Norwegian Bokmål    Norway */
1027     "nds_DE",   /* Low Saxon    Germany */
1028     "ne_NP",    /* Nepali       Nepal */
1029     "nl_NL",    /* Dutch        Netherlands */
1030     "nn_NO",    /* Norwegian Nynorsk    Norway */
1031     "no_NO",    /* Norwegian    Norway */
1032     "nr_ZA",    /* South Ndebele        South Africa */
1033     "nso_ZA",   /* Northern Sotho       South Africa */
1034     "ny_MW",    /* Chichewa     Malawi */
1035     "nym_TZ",   /* Nyamwezi     Tanzania */
1036     "nyn_UG",   /* Nyankole     Uganda */
1037     "oc_FR",    /* Occitan      France */
1038     "oj_CA",    /* Ojibwa       Canada */
1039     "or_IN",    /* Oriya        India */
1040     "pa_IN",    /* Punjabi      India */
1041     "pag_PH",   /* Pangasinan   Philippines */
1042     "pam_PH",   /* Pampanga     Philippines */
1043     "pap_AN",   /* Papiamento   Netherlands Antilles - this line can be removed in 2018 */
1044     "pbb_CO",   /* Páez         Colombia */
1045     "pl_PL",    /* Polish       Poland */
1046     "ps_AF",    /* Pashto       Afghanistan */
1047     "pt_PT",    /* Portuguese   Portugal */
1048     "raj_IN",   /* Rajasthani   India */
1049     "rm_CH",    /* Romansh      Switzerland */
1050     "rn_BI",    /* Kirundi      Burundi */
1051     "ro_RO",    /* Romanian     Romania */
1052     "ru_RU",    /* Russian      Russia */
1053     "rw_RW",    /* Kinyarwanda  Rwanda */
1054     "sa_IN",    /* Sanskrit     India */
1055     "sah_RU",   /* Yakut        Russia */
1056     "sas_ID",   /* Sasak        Indonesia */
1057     "sat_IN",   /* Santali      India */
1058     "sc_IT",    /* Sardinian    Italy */
1059     "scn_IT",   /* Sicilian     Italy */
1060     "sg_CF",    /* Sango        Central African Republic */
1061     "shn_MM",   /* Shan         Myanmar */
1062     "si_LK",    /* Sinhala      Sri Lanka */
1063     "sid_ET",   /* Sidamo       Ethiopia */
1064     "sk_SK",    /* Slovak       Slovakia */
1065     "sl_SI",    /* Slovenian    Slovenia */
1066     "sm_WS",    /* Samoan       Samoa */
1067     "smn_FI",   /* Inari Sami   Finland */
1068     "sms_FI",   /* Skolt Sami   Finland */
1069     "so_SO",    /* Somali       Somalia */
1070     "sq_AL",    /* Albanian     Albania */
1071     "sr_RS",    /* Serbian      Serbia */
1072     "srr_SN",   /* Serer        Senegal */
1073     "suk_TZ",   /* Sukuma       Tanzania */
1074     "sus_GN",   /* Susu         Guinea */
1075     "sv_SE",    /* Swedish      Sweden */
1076     "te_IN",    /* Telugu       India */
1077     "tem_SL",   /* Timne        Sierra Leone */
1078     "tet_ID",   /* Tetum        Indonesia */
1079     "tg_TJ",    /* Tajik        Tajikistan */
1080     "th_TH",    /* Thai         Thailand */
1081     "ti_ER",    /* Tigrinya     Eritrea */
1082     "tiv_NG",   /* Tiv          Nigeria */
1083     "tk_TM",    /* Turkmen      Turkmenistan */
1084     "tl_PH",    /* Tagalog      Philippines */
1085     "to_TO",    /* Tonga        Tonga */
1086     "tpi_PG",   /* Tok Pisin    Papua New Guinea */
1087     "tr_TR",    /* Turkish      Turkey */
1088     "tum_MW",   /* Tumbuka      Malawi */
1089     "ug_CN",    /* Uighur       China */
1090     "uk_UA",    /* Ukrainian    Ukraine */
1091     "umb_AO",   /* Umbundu      Angola */
1092     "ur_PK",    /* Urdu         Pakistan */
1093     "uz_UZ",    /* Uzbek        Uzbekistan */
1094     "ve_ZA",    /* Venda        South Africa */
1095     "vi_VN",    /* Vietnamese   Vietnam */
1096     "wa_BE",    /* Walloon      Belgium */
1097     "wal_ET",   /* Walamo       Ethiopia */
1098     "war_PH",   /* Waray        Philippines */
1099     "wen_DE",   /* Sorbian      Germany */
1100     "yao_MW",   /* Yao          Malawi */
1101     "zap_MX"    /* Zapotec      Mexico */
1102   };
1103 
1104 /* Compare just the language part of two locale names.  */
1105 static int
1106 langcmp (const char *locale1, const char *locale2)
     /* [previous][next][first][last][top][bottom][index][help] */
1107 {
1108   size_t locale1_len;
1109   size_t locale2_len;
1110   int cmp;
1111 
1112   {
1113     const char *locale1_end = strchr (locale1, '_');
1114     if (locale1_end != NULL)
1115       locale1_len = locale1_end - locale1;
1116     else
1117       locale1_len = strlen (locale1);
1118   }
1119   {
1120     const char *locale2_end = strchr (locale2, '_');
1121     if (locale2_end != NULL)
1122       locale2_len = locale2_end - locale2;
1123     else
1124       locale2_len = strlen (locale2);
1125   }
1126 
1127   if (locale1_len < locale2_len)
1128     {
1129       cmp = memcmp (locale1, locale2, locale1_len);
1130       if (cmp == 0)
1131         cmp = -1;
1132     }
1133   else
1134     {
1135       cmp = memcmp (locale1, locale2, locale2_len);
1136       if (locale1_len > locale2_len && cmp == 0)
1137         cmp = 1;
1138     }
1139 
1140   return cmp;
1141 }
1142 
1143 /* Given a locale name, return the main locale with the same language,
1144    or NULL if not found.
1145    For example: "fr_DE" -> "fr_FR".  */
1146 static const char *
1147 get_main_locale_with_same_language (const char *locale)
     /* [previous][next][first][last][top][bottom][index][help] */
1148 {
1149 #   define table locales_with_principal_territory
1150   /* The table is sorted.  Perform a binary search.  */
1151   size_t hi = sizeof (table) / sizeof (table[0]);
1152   size_t lo = 0;
1153   while (lo < hi)
1154     {
1155       /* Invariant:
1156          for i < lo, langcmp (table[i], locale) < 0,
1157          for i >= hi, langcmp (table[i], locale) > 0.  */
1158       size_t mid = (hi + lo) >> 1; /* >= lo, < hi */
1159       int cmp = langcmp (table[mid], locale);
1160       if (cmp < 0)
1161         lo = mid + 1;
1162       else if (cmp > 0)
1163         hi = mid;
1164       else
1165         {
1166           /* Found an i with
1167                langcmp (language_table[i], locale) == 0.
1168              Verify that it is the only such i.  */
1169           if (mid > lo && langcmp (table[mid - 1], locale) >= 0)
1170             abort ();
1171           if (mid + 1 < hi && langcmp (table[mid + 1], locale) <= 0)
1172             abort ();
1173           return table[mid];
1174         }
1175     }
1176 #   undef table
1177   return NULL;
1178 }
1179 
1180 /* Mapping from territory to main language that is spoken in that territory.  */
1181 static char const locales_with_principal_language[][6 + 1] =
1182   {
1183     /* This is based on the set of existing locales in glibc, with duplicates
1184        removed, and on the Wikipedia pages named "Languages of <territory>".
1185        If in doubt, use the locale that exists in macOS.  For example, the only
1186        "*_IN" locale in macOS 10.13 is "hi_IN", so use that.  */
1187     /* A useful shell function for producing a line of this table is:
1188          func_line ()
1189          {
1190            # Usage: func_line ll_CC
1191            ll=`echo "$1" | sed -e 's|_.*||'`
1192            cc=`echo "$1" | sed -e 's|^.*_||'`
1193            llx=`sed -n -e "s|^${ll} ||p" < gettext-tools/doc/ISO_639`
1194            ccx=`expand gettext-tools/doc/ISO_3166 | sed -n -e "s|^${cc}  *||p"`
1195            echo "    \"$1\",    /$X* ${llx} ${ccx} *$X/"
1196          }
1197      */
1198               /* Main language  Territory */
1199     "ca_AD",    /* Catalan      Andorra */
1200     "ar_AE",    /* Arabic       United Arab Emirates */
1201     "ps_AF",    /* Pashto       Afghanistan */
1202     "en_AG",    /* English      Antigua and Barbuda */
1203     "sq_AL",    /* Albanian     Albania */
1204     "hy_AM",    /* Armenian     Armenia */
1205     "pap_AN",   /* Papiamento   Netherlands Antilles - this line can be removed in 2018 */
1206     "pt_AO",    /* Portuguese   Angola */
1207     "es_AR",    /* Spanish      Argentina */
1208     "de_AT",    /* German       Austria */
1209     "en_AU",    /* English      Australia */
1210     /* Aruba has two official languages: "nl_AW", "pap_AW".  */
1211     "az_AZ",    /* Azerbaijani  Azerbaijan */
1212     "bs_BA",    /* Bosnian      Bosnia */
1213     "bn_BD",    /* Bengali      Bangladesh */
1214     "nl_BE",    /* Dutch        Belgium */
1215     "fr_BF",    /* French       Burkina Faso */
1216     "bg_BG",    /* Bulgarian    Bulgaria */
1217     "ar_BH",    /* Arabic       Bahrain */
1218     "rn_BI",    /* Kirundi      Burundi */
1219     "fr_BJ",    /* French       Benin */
1220     "es_BO",    /* Spanish      Bolivia */
1221     "pt_BR",    /* Portuguese   Brazil */
1222     "dz_BT",    /* Dzongkha     Bhutan */
1223     "en_BW",    /* English      Botswana */
1224     "be_BY",    /* Belarusian   Belarus */
1225     "en_CA",    /* English      Canada */
1226     "fr_CD",    /* French       Democratic Republic of Congo */
1227     "sg_CF",    /* Sango        Central African Republic */
1228     "de_CH",    /* German       Switzerland */
1229     "es_CL",    /* Spanish      Chile */
1230     "zh_CN",    /* Chinese      China */
1231     "es_CO",    /* Spanish      Colombia */
1232     "es_CR",    /* Spanish      Costa Rica */
1233     "es_CU",    /* Spanish      Cuba */
1234     /* Curaçao has three official languages: "nl_CW", "pap_CW", "en_CW".  */
1235     "el_CY",    /* Greek        Cyprus */
1236     "cs_CZ",    /* Czech        Czech Republic */
1237     "de_DE",    /* German       Germany */
1238     /* Djibouti has two official languages: "ar_DJ" and "fr_DJ".  */
1239     "da_DK",    /* Danish       Denmark */
1240     "es_DO",    /* Spanish      Dominican Republic */
1241     "ar_DZ",    /* Arabic       Algeria */
1242     "es_EC",    /* Spanish      Ecuador */
1243     "et_EE",    /* Estonian     Estonia */
1244     "ar_EG",    /* Arabic       Egypt */
1245     "ti_ER",    /* Tigrinya     Eritrea */
1246     "es_ES",    /* Spanish      Spain */
1247     "am_ET",    /* Amharic      Ethiopia */
1248     "fi_FI",    /* Finnish      Finland */
1249     /* Fiji has three official languages: "en_FJ", "fj_FJ", "hif_FJ".  */
1250     "fo_FO",    /* Faroese      Faeroe Islands */
1251     "fr_FR",    /* French       France */
1252     "en_GB",    /* English      Britain */
1253     "ka_GE",    /* Georgian     Georgia */
1254     "en_GH",    /* English      Ghana */
1255     "kl_GL",    /* Kalaallisut  Greenland */
1256     "fr_GN",    /* French       Guinea */
1257     "el_GR",    /* Greek        Greece */
1258     "es_GT",    /* Spanish      Guatemala */
1259     "zh_HK",    /* Chinese      Hong Kong */
1260     "es_HN",    /* Spanish      Honduras */
1261     "hr_HR",    /* Croatian     Croatia */
1262     "ht_HT",    /* Haitian      Haiti */
1263     "hu_HU",    /* Hungarian    Hungary */
1264     "id_ID",    /* Indonesian   Indonesia */
1265     "en_IE",    /* English      Ireland */
1266     "he_IL",    /* Hebrew       Israel */
1267     "hi_IN",    /* Hindi        India */
1268     "ar_IQ",    /* Arabic       Iraq */
1269     "fa_IR",    /* Persian      Iran */
1270     "is_IS",    /* Icelandic    Iceland */
1271     "it_IT",    /* Italian      Italy */
1272     "ar_JO",    /* Arabic       Jordan */
1273     "ja_JP",    /* Japanese     Japan */
1274     "sw_KE",    /* Swahili      Kenya */
1275     "ky_KG",    /* Kyrgyz       Kyrgyzstan */
1276     "km_KH",    /* Central Khmer        Cambodia */
1277     "ko_KR",    /* Korean       Korea (South) */
1278     "ar_KW",    /* Arabic       Kuwait */
1279     "kk_KZ",    /* Kazakh       Kazakhstan */
1280     "lo_LA",    /* Laotian      Laos */
1281     "ar_LB",    /* Arabic       Lebanon */
1282     "de_LI",    /* German       Liechtenstein */
1283     "si_LK",    /* Sinhala      Sri Lanka */
1284     "lt_LT",    /* Lithuanian   Lithuania */
1285     /* Luxembourg has three official languages: "lb_LU", "fr_LU", "de_LU".  */
1286     "lv_LV",    /* Latvian      Latvia */
1287     "ar_LY",    /* Arabic       Libya */
1288     "ar_MA",    /* Arabic       Morocco */
1289     "sr_ME",    /* Serbian      Montenegro */
1290     "mg_MG",    /* Malagasy     Madagascar */
1291     "mk_MK",    /* Macedonian   North Macedonia */
1292     "fr_ML",    /* French       Mali */
1293     "my_MM",    /* Burmese      Myanmar */
1294     "mn_MN",    /* Mongolian    Mongolia */
1295     "mt_MT",    /* Maltese      Malta */
1296     "mfe_MU",   /* Mauritian Creole     Mauritius */
1297     "dv_MV",    /* Divehi       Maldives */
1298     "ny_MW",    /* Chichewa     Malawi */
1299     "es_MX",    /* Spanish      Mexico */
1300     "ms_MY",    /* Malay        Malaysia */
1301     "en_NG",    /* English      Nigeria */
1302     "es_NI",    /* Spanish      Nicaragua */
1303     "nl_NL",    /* Dutch        Netherlands */
1304     "no_NO",    /* Norwegian    Norway */
1305     "ne_NP",    /* Nepali       Nepal */
1306     "na_NR",    /* Nauru        Nauru */
1307     "niu_NU",   /* Niuean       Niue */
1308     "en_NZ",    /* English      New Zealand */
1309     "ar_OM",    /* Arabic       Oman */
1310     "es_PA",    /* Spanish      Panama */
1311     "es_PE",    /* Spanish      Peru */
1312     "tpi_PG",   /* Tok Pisin    Papua New Guinea */
1313     "fil_PH",   /* Filipino     Philippines */
1314     "pa_PK",    /* Punjabi      Pakistan */
1315     "pl_PL",    /* Polish       Poland */
1316     "es_PR",    /* Spanish      Puerto Rico */
1317     "pt_PT",    /* Portuguese   Portugal */
1318     "es_PY",    /* Spanish      Paraguay */
1319     "ar_QA",    /* Arabic       Qatar */
1320     "ro_RO",    /* Romanian     Romania */
1321     "sr_RS",    /* Serbian      Serbia */
1322     "ru_RU",    /* Russian      Russia */
1323     "rw_RW",    /* Kinyarwanda  Rwanda */
1324     "ar_SA",    /* Arabic       Saudi Arabia */
1325     "en_SC",    /* English      Seychelles */
1326     "ar_SD",    /* Arabic       Sudan */
1327     "sv_SE",    /* Swedish      Sweden */
1328     "en_SG",    /* English      Singapore */
1329     "sl_SI",    /* Slovenian    Slovenia */
1330     "sk_SK",    /* Slovak       Slovakia */
1331     "en_SL",    /* English      Sierra Leone */
1332     "fr_SN",    /* French       Senegal */
1333     "so_SO",    /* Somali       Somalia */
1334     "ar_SS",    /* Arabic       South Sudan */
1335     "es_SV",    /* Spanish      El Salvador */
1336     "ar_SY",    /* Arabic       Syria */
1337     "th_TH",    /* Thai         Thailand */
1338     "tg_TJ",    /* Tajik        Tajikistan */
1339     "tk_TM",    /* Turkmen      Turkmenistan */
1340     "ar_TN",    /* Arabic       Tunisia */
1341     "to_TO",    /* Tonga        Tonga */
1342     "tr_TR",    /* Turkish      Turkey */
1343     "zh_TW",    /* Chinese      Taiwan */
1344     "sw_TZ",    /* Swahili      Tanzania */
1345     "uk_UA",    /* Ukrainian    Ukraine */
1346     "lg_UG",    /* Ganda        Uganda */
1347     "en_US",    /* English      United States of America */
1348     "es_UY",    /* Spanish      Uruguay */
1349     "uz_UZ",    /* Uzbek        Uzbekistan */
1350     "es_VE",    /* Spanish      Venezuela */
1351     "vi_VN",    /* Vietnamese   Vietnam */
1352     "bi_VU",    /* Bislama      Vanuatu */
1353     "sm_WS",    /* Samoan       Samoa */
1354     "ar_YE",    /* Arabic       Yemen */
1355     "en_ZA",    /* English      South Africa */
1356     "en_ZM",    /* English      Zambia */
1357     "en_ZW"     /* English      Zimbabwe */
1358   };
1359 
1360 /* Compare just the territory part of two locale names.  */
1361 static int
1362 terrcmp (const char *locale1, const char *locale2)
     /* [previous][next][first][last][top][bottom][index][help] */
1363 {
1364   const char *territory1 = strrchr (locale1, '_') + 1;
1365   const char *territory2 = strrchr (locale2, '_') + 1;
1366 
1367   return strcmp (territory1, territory2);
1368 }
1369 
1370 /* Given a locale name, return the locale corresponding to the main language
1371    with the same territory, or NULL if not found.
1372    For example: "fr_DE" -> "de_DE".  */
1373 static const char *
1374 get_main_locale_with_same_territory (const char *locale)
     /* [previous][next][first][last][top][bottom][index][help] */
1375 {
1376   if (strrchr (locale, '_') != NULL)
1377     {
1378 #   define table locales_with_principal_language
1379       /* The table is sorted.  Perform a binary search.  */
1380       size_t hi = sizeof (table) / sizeof (table[0]);
1381       size_t lo = 0;
1382       while (lo < hi)
1383         {
1384           /* Invariant:
1385              for i < lo, terrcmp (table[i], locale) < 0,
1386              for i >= hi, terrcmp (table[i], locale) > 0.  */
1387           size_t mid = (hi + lo) >> 1; /* >= lo, < hi */
1388           int cmp = terrcmp (table[mid], locale);
1389           if (cmp < 0)
1390             lo = mid + 1;
1391           else if (cmp > 0)
1392             hi = mid;
1393           else
1394             {
1395               /* Found an i with
1396                    terrcmp (language_table[i], locale) == 0.
1397                  Verify that it is the only such i.  */
1398               if (mid > lo && terrcmp (table[mid - 1], locale) >= 0)
1399                 abort ();
1400               if (mid + 1 < hi && terrcmp (table[mid + 1], locale) <= 0)
1401                 abort ();
1402               return table[mid];
1403             }
1404         }
1405 #   undef table
1406     }
1407   return NULL;
1408 }
1409 
1410 #  endif
1411 
1412 char *
1413 setlocale_improved (int category, const char *locale)
     /* [previous][next][first][last][top][bottom][index][help] */
1414 {
1415   if (locale != NULL && locale[0] == '\0')
1416     {
1417       /* A request to the set the current locale to the default locale.  */
1418       if (category == LC_ALL)
1419         {
1420           /* Set LC_CTYPE first.  Then the other categories.  */
1421           static int const categories[] =
1422             {
1423               LC_CTYPE,
1424               LC_NUMERIC,
1425               LC_TIME,
1426               LC_COLLATE,
1427               LC_MONETARY,
1428               LC_MESSAGES
1429             };
1430           char *saved_locale;
1431           const char *base_name;
1432           unsigned int i;
1433 
1434           /* Back up the old locale, in case one of the steps fails.  */
1435           saved_locale = setlocale (LC_ALL, NULL);
1436           if (saved_locale == NULL)
1437             return NULL;
1438           saved_locale = strdup (saved_locale);
1439           if (saved_locale == NULL)
1440             return NULL;
1441 
1442           /* Set LC_CTYPE category.  Set all other categories (except possibly
1443              LC_MESSAGES) to the same value in the same call; this is likely to
1444              save calls.  */
1445           base_name =
1446             gl_locale_name_environ (LC_CTYPE, category_to_name (LC_CTYPE));
1447           if (base_name == NULL)
1448             base_name = gl_locale_name_default ();
1449 
1450           if (setlocale_unixlike (LC_ALL, base_name) != NULL)
1451             {
1452               /* LC_CTYPE category already set.  */
1453               i = 1;
1454             }
1455           else
1456             {
1457               /* On Mac OS X, "UTF-8" is a valid locale name for LC_CTYPE but
1458                  not for LC_ALL.  Therefore this call may fail.  So, try
1459                  another base_name.  */
1460               base_name = "C";
1461               if (setlocale_unixlike (LC_ALL, base_name) == NULL)
1462                 goto fail;
1463               i = 0;
1464             }
1465 #  if defined _WIN32 && ! defined __CYGWIN__
1466           /* On native Windows, setlocale(LC_ALL,...) may succeed but set the
1467              LC_CTYPE category to an invalid value ("C") when it does not
1468              support the specified encoding.  Report a failure instead.  */
1469           if (strchr (base_name, '.') != NULL
1470               && strcmp (setlocale (LC_CTYPE, NULL), "C") == 0)
1471             goto fail;
1472 #  endif
1473 
1474           for (; i < sizeof (categories) / sizeof (categories[0]); i++)
1475             {
1476               int cat = categories[i];
1477               const char *name;
1478 
1479               name = gl_locale_name_environ (cat, category_to_name (cat));
1480               if (name == NULL)
1481                 name = gl_locale_name_default ();
1482 
1483               /* If name is the same as base_name, it has already been set
1484                  through the setlocale call before the loop.  */
1485               if (strcmp (name, base_name) != 0
1486 #  if LC_MESSAGES == 1729
1487                   || cat == LC_MESSAGES
1488 #  endif
1489                  )
1490                 if (setlocale_single (cat, name) == NULL)
1491 #  if defined __APPLE__ && defined __MACH__
1492                   {
1493                     /* On Mac OS X 10.13, some locales can be set through
1494                        System Preferences > Language & Region, that are not
1495                        supported by libc.  The system's setlocale() falls
1496                        back to "C" for these locale categories.  We can do
1497                        better, by trying an existing locale with the same
1498                        language or an existing locale with the same territory.
1499                        If we can't, print a warning, to limit user
1500                        expectations.  */
1501                     int warn = 0;
1502 
1503                     if (cat == LC_CTYPE)
1504                       warn = (setlocale_single (cat, "UTF-8") == NULL);
1505                     else if (cat == LC_MESSAGES)
1506                       {
1507 #   if HAVE_CFLOCALECOPYPREFERREDLANGUAGES || HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.4 or newer */
1508                         /* Take the primary language preference.  */
1509 #    if HAVE_CFLOCALECOPYPREFERREDLANGUAGES /* MacOS X 10.5 or newer */
1510                         CFArrayRef prefArray = CFLocaleCopyPreferredLanguages ();
1511 #    elif HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.4 or newer */
1512                         CFTypeRef preferences =
1513                           CFPreferencesCopyAppValue (CFSTR ("AppleLanguages"),
1514                                                      kCFPreferencesCurrentApplication);
1515                         if (preferences != NULL
1516                             && CFGetTypeID (preferences) == CFArrayGetTypeID ())
1517                           {
1518                             CFArrayRef prefArray = (CFArrayRef)preferences;
1519 #    endif
1520                             int n = CFArrayGetCount (prefArray);
1521                             if (n > 0)
1522                               {
1523                                 char buf[256];
1524                                 CFTypeRef element = CFArrayGetValueAtIndex (prefArray, 0);
1525                                 if (element != NULL
1526                                     && CFGetTypeID (element) == CFStringGetTypeID ()
1527                                     && CFStringGetCString ((CFStringRef)element,
1528                                                            buf, sizeof (buf),
1529                                                            kCFStringEncodingASCII))
1530                                   {
1531                                     /* Remove the country.
1532                                        E.g. "zh-Hans-DE" -> "zh-Hans".  */
1533                                     char *last_minus = strrchr (buf, '-');
1534                                     if (last_minus != NULL)
1535                                       *last_minus = '\0';
1536 
1537                                     /* Convert to Unix locale name.
1538                                        E.g. "zh-Hans" -> "zh_CN".  */
1539                                     gl_locale_name_canonicalize (buf);
1540 
1541                                     /* Try setlocale with this value.  */
1542                                     if (setlocale_single (cat, buf) == NULL)
1543                                       {
1544                                         const char *last_try =
1545                                           get_main_locale_with_same_language (buf);
1546 
1547                                         if (last_try == NULL
1548                                             || setlocale_single (cat, last_try) == NULL)
1549                                           warn = 1;
1550                                       }
1551                                   }
1552                               }
1553 #    if HAVE_CFLOCALECOPYPREFERREDLANGUAGES /* MacOS X 10.5 or newer */
1554                         CFRelease (prefArray);
1555 #    elif HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.4 or newer */
1556                           }
1557 #    endif
1558 #   else
1559                         const char *last_try =
1560                           get_main_locale_with_same_language (name);
1561 
1562                         if (last_try == NULL
1563                             || setlocale_single (cat, last_try) == NULL)
1564                           warn = 1;
1565 #   endif
1566                       }
1567                     else
1568                       {
1569                         /* For LC_NUMERIC, the application should use the locale
1570                            properties kCFLocaleDecimalSeparator,
1571                            kCFLocaleGroupingSeparator.
1572                            For LC_TIME, the application should use the locale
1573                            property kCFLocaleCalendarIdentifier.
1574                            For LC_COLLATE, the application should use the locale
1575                            properties kCFLocaleCollationIdentifier,
1576                            kCFLocaleCollatorIdentifier.
1577                            For LC_MONETARY, the applicationshould use the locale
1578                            properties kCFLocaleCurrencySymbol,
1579                            kCFLocaleCurrencyCode.
1580                            But since most applications don't have macOS specific
1581                            code like this, try an existing locale with the same
1582                            territory.  */
1583                         const char *last_try =
1584                           get_main_locale_with_same_territory (name);
1585 
1586                         if (last_try == NULL
1587                             || setlocale_single (cat, last_try) == NULL)
1588                           warn = 1;
1589                       }
1590 
1591                     if (warn)
1592                       {
1593                         /* Warn only if the environment variable
1594                            SETLOCALE_VERBOSE is set.  Otherwise these warnings
1595                            are just annoyances, since normal users won't invoke
1596                            'localedef'.  */
1597                         const char *verbose = getenv ("SETLOCALE_VERBOSE");
1598                         if (verbose != NULL && verbose[0] != '\0')
1599                           fprintf (stderr,
1600                                    "Warning: Failed to set locale category %s to %s.\n",
1601                                    category_to_name (cat), name);
1602                       }
1603                   }
1604 #  else
1605                   goto fail;
1606 #  endif
1607             }
1608 
1609           /* All steps were successful.  */
1610           free (saved_locale);
1611           return setlocale (LC_ALL, NULL);
1612 
1613         fail:
1614           if (saved_locale[0] != '\0') /* don't risk an endless recursion */
1615             setlocale (LC_ALL, saved_locale);
1616           free (saved_locale);
1617           return NULL;
1618         }
1619       else
1620         {
1621           const char *name =
1622             gl_locale_name_environ (category, category_to_name (category));
1623           if (name == NULL)
1624             name = gl_locale_name_default ();
1625 
1626           return setlocale_single (category, name);
1627         }
1628     }
1629   else
1630     {
1631 #  if defined _WIN32 && ! defined __CYGWIN__
1632       if (category == LC_ALL && locale != NULL && strchr (locale, '.') != NULL)
1633         {
1634           char *saved_locale;
1635 
1636           /* Back up the old locale.  */
1637           saved_locale = setlocale (LC_ALL, NULL);
1638           if (saved_locale == NULL)
1639             return NULL;
1640           saved_locale = strdup (saved_locale);
1641           if (saved_locale == NULL)
1642             return NULL;
1643 
1644           if (setlocale_unixlike (LC_ALL, locale) == NULL)
1645             {
1646               free (saved_locale);
1647               return NULL;
1648             }
1649 
1650           /* On native Windows, setlocale(LC_ALL,...) may succeed but set the
1651              LC_CTYPE category to an invalid value ("C") when it does not
1652              support the specified encoding.  Report a failure instead.  */
1653           if (strcmp (setlocale (LC_CTYPE, NULL), "C") == 0)
1654             {
1655               if (saved_locale[0] != '\0') /* don't risk an endless recursion */
1656                 setlocale (LC_ALL, saved_locale);
1657               free (saved_locale);
1658               return NULL;
1659             }
1660 
1661           /* It was really successful.  */
1662           free (saved_locale);
1663           return setlocale (LC_ALL, NULL);
1664         }
1665       else
1666 #  endif
1667         return setlocale_single (category, locale);
1668     }
1669 }
1670 
1671 # endif /* NEED_SETLOCALE_IMPROVED */
1672 
1673 #endif

/* [previous][next][first][last][top][bottom][index][help] */