PageRenderTime 78ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/indra/llcommon/llfindlocale.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 518 lines | 421 code | 28 blank | 69 comment | 56 complexity | 1d1c0174b27169988cfb0a685c1fb1c0 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llfindlocale.cpp
  3. * @brief Detect system language setting
  4. *
  5. * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. /* Yes, this was originally C code. */
  27. #include "linden_common.h"
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <ctype.h>
  31. #ifdef WIN32
  32. #include <windows.h>
  33. #include <winnt.h>
  34. #endif
  35. #include "llfindlocale.h"
  36. static int
  37. is_lcchar(const int c) {
  38. return isalnum(c);
  39. }
  40. static void
  41. lang_country_variant_from_envstring(const char *str,
  42. char **lang,
  43. char **country,
  44. char **variant) {
  45. int end = 0;
  46. int start;
  47. /* get lang, if any */
  48. start = end;
  49. while (is_lcchar(str[end])) {
  50. ++end;
  51. }
  52. if (start != end) {
  53. int i;
  54. int len = end - start;
  55. char *s = (char*)malloc(len + 1);
  56. for (i=0; i<len; ++i) {
  57. s[i] = tolower(str[start + i]);
  58. }
  59. s[i] = '\0';
  60. *lang = s;
  61. } else {
  62. *lang = NULL;
  63. }
  64. if (str[end] && str[end]!=':') { /* not at end of str */
  65. ++end;
  66. }
  67. /* get country, if any */
  68. start = end;
  69. while (is_lcchar(str[end])) {
  70. ++end;
  71. }
  72. if (start != end) {
  73. int i;
  74. int len = end - start;
  75. char *s = (char*)malloc(len + 1);
  76. for (i=0; i<len; ++i) {
  77. s[i] = toupper(str[start + i]);
  78. }
  79. s[i] = '\0';
  80. *country = s;
  81. } else {
  82. *country = NULL;
  83. }
  84. if (str[end] && str[end]!=':') { /* not at end of str */
  85. ++end;
  86. }
  87. /* get variant, if any */
  88. start = end;
  89. while (str[end] && str[end]!=':') {
  90. ++end;
  91. }
  92. if (start != end) {
  93. int i;
  94. int len = end - start;
  95. char *s = (char*)malloc(len + 1);
  96. for (i=0; i<len; ++i) {
  97. s[i] = str[start + i];
  98. }
  99. s[i] = '\0';
  100. *variant = s;
  101. } else {
  102. *variant = NULL;
  103. }
  104. }
  105. static int
  106. accumulate_locstring(const char *str, FL_Locale *l) {
  107. char *lang = NULL;
  108. char *country = NULL;
  109. char *variant = NULL;
  110. if (str) {
  111. lang_country_variant_from_envstring(str, &lang, &country, &variant);
  112. if (lang) {
  113. l->lang = lang;
  114. l->country = country;
  115. l->variant = variant;
  116. return 1;
  117. }
  118. }
  119. free(lang); free(country); free(variant);
  120. return 0;
  121. }
  122. static int
  123. accumulate_env(const char *name, FL_Locale *l) {
  124. char *env;
  125. char *lang = NULL;
  126. char *country = NULL;
  127. char *variant = NULL;
  128. env = getenv(name);
  129. if (env) {
  130. return accumulate_locstring(env, l);
  131. }
  132. free(lang); free(country); free(variant);
  133. return 0;
  134. }
  135. static void
  136. canonise_fl(FL_Locale *l) {
  137. /* this function fixes some common locale-specifying mistakes */
  138. /* en_UK -> en_GB */
  139. if (l->lang && 0 == strcmp(l->lang, "en")) {
  140. if (l->country && 0 == strcmp(l->country, "UK")) {
  141. free((void*)l->country);
  142. l->country = strdup("GB");
  143. }
  144. }
  145. /* ja_JA -> ja_JP */
  146. if (l->lang && 0 == strcmp(l->lang, "ja")) {
  147. if (l->country && 0 == strcmp(l->country, "JA")) {
  148. free((void*)l->country);
  149. l->country = strdup("JP");
  150. }
  151. }
  152. }
  153. #ifdef WIN32
  154. #include <stdio.h>
  155. #define ML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##pn##_##sn)
  156. #define MLN(pn) MAKELANGID(LANG_##pn, SUBLANG_DEFAULT)
  157. #define RML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##sn)
  158. struct IDToCode {
  159. LANGID id;
  160. char* code;
  161. };
  162. static const IDToCode both_to_code[] = {
  163. {ML(ENGLISH,US), "en_US.ISO_8859-1"},
  164. {ML(ENGLISH,CAN), "en_CA"}, /* english / canadian */
  165. {ML(ENGLISH,UK), "en_GB"},
  166. {ML(ENGLISH,EIRE), "en_IE"},
  167. {ML(ENGLISH,AUS), "en_AU"},
  168. {MLN(GERMAN), "de_DE"},
  169. {MLN(SPANISH), "es_ES"},
  170. {ML(SPANISH,MEXICAN), "es_MX"},
  171. {MLN(FRENCH), "fr_FR"},
  172. {ML(FRENCH,CANADIAN), "fr_CA"},
  173. {ML(FRENCH,BELGIAN), "fr_BE"}, /* ? */
  174. {ML(DUTCH,BELGIAN), "nl_BE"}, /* ? */
  175. {ML(PORTUGUESE,BRAZILIAN), "pt_BR"},
  176. {MLN(PORTUGUESE), "pt_PT"},
  177. {MLN(SWEDISH), "sv_SE"},
  178. {ML(CHINESE,HONGKONG), "zh_HK"},
  179. /* these are machine-generated and not yet verified */
  180. {RML(AFRIKAANS,DEFAULT), "af_ZA"},
  181. {RML(ALBANIAN,DEFAULT), "sq_AL"},
  182. {RML(ARABIC,ARABIC_ALGERIA), "ar_DZ"},
  183. {RML(ARABIC,ARABIC_BAHRAIN), "ar_BH"},
  184. {RML(ARABIC,ARABIC_EGYPT), "ar_EG"},
  185. {RML(ARABIC,ARABIC_IRAQ), "ar_IQ"},
  186. {RML(ARABIC,ARABIC_JORDAN), "ar_JO"},
  187. {RML(ARABIC,ARABIC_KUWAIT), "ar_KW"},
  188. {RML(ARABIC,ARABIC_LEBANON), "ar_LB"},
  189. {RML(ARABIC,ARABIC_LIBYA), "ar_LY"},
  190. {RML(ARABIC,ARABIC_MOROCCO), "ar_MA"},
  191. {RML(ARABIC,ARABIC_OMAN), "ar_OM"},
  192. {RML(ARABIC,ARABIC_QATAR), "ar_QA"},
  193. {RML(ARABIC,ARABIC_SAUDI_ARABIA), "ar_SA"},
  194. {RML(ARABIC,ARABIC_SYRIA), "ar_SY"},
  195. {RML(ARABIC,ARABIC_TUNISIA), "ar_TN"},
  196. {RML(ARABIC,ARABIC_UAE), "ar_AE"},
  197. {RML(ARABIC,ARABIC_YEMEN), "ar_YE"},
  198. {RML(ARMENIAN,DEFAULT), "hy_AM"},
  199. {RML(AZERI,AZERI_CYRILLIC), "az_AZ"},
  200. {RML(AZERI,AZERI_LATIN), "az_AZ"},
  201. {RML(BASQUE,DEFAULT), "eu_ES"},
  202. {RML(BELARUSIAN,DEFAULT), "be_BY"},
  203. /*{RML(BRETON,DEFAULT), "br_FR"},*/
  204. {RML(BULGARIAN,DEFAULT), "bg_BG"},
  205. {RML(CATALAN,DEFAULT), "ca_ES"},
  206. {RML(CHINESE,CHINESE_HONGKONG), "zh_HK"},
  207. {RML(CHINESE,CHINESE_MACAU), "zh_MO"},
  208. {RML(CHINESE,CHINESE_SIMPLIFIED), "zh_CN"},
  209. {RML(CHINESE,CHINESE_SINGAPORE), "zh_SG"},
  210. {RML(CHINESE,CHINESE_TRADITIONAL), "zh_TW"},
  211. /*{RML(CORNISH,DEFAULT), "kw_GB"},*/
  212. {RML(CZECH,DEFAULT), "cs_CZ"},
  213. {RML(DANISH,DEFAULT), "da_DK"},
  214. {RML(DUTCH,DUTCH), "nl_NL"},
  215. {RML(DUTCH,DUTCH_BELGIAN), "nl_BE"},
  216. /*{RML(DUTCH,DUTCH_SURINAM), "nl_SR"},*/
  217. {RML(ENGLISH,ENGLISH_AUS), "en_AU"},
  218. {RML(ENGLISH,ENGLISH_BELIZE), "en_BZ"},
  219. {RML(ENGLISH,ENGLISH_CAN), "en_CA"},
  220. {RML(ENGLISH,ENGLISH_CARIBBEAN), "en_CB"},
  221. {RML(ENGLISH,ENGLISH_EIRE), "en_IE"},
  222. {RML(ENGLISH,ENGLISH_JAMAICA), "en_JM"},
  223. {RML(ENGLISH,ENGLISH_NZ), "en_NZ"},
  224. {RML(ENGLISH,ENGLISH_PHILIPPINES), "en_PH"},
  225. {RML(ENGLISH,ENGLISH_SOUTH_AFRICA), "en_ZA"},
  226. {RML(ENGLISH,ENGLISH_TRINIDAD), "en_TT"},
  227. {RML(ENGLISH,ENGLISH_UK), "en_GB"},
  228. {RML(ENGLISH,ENGLISH_US), "en_US"},
  229. {RML(ENGLISH,ENGLISH_ZIMBABWE), "en_ZW"},
  230. /*{RML(ESPERANTO,DEFAULT), "eo_"},*/
  231. {RML(ESTONIAN,DEFAULT), "et_EE"},
  232. {RML(FAEROESE,DEFAULT), "fo_FO"},
  233. {RML(FARSI,DEFAULT), "fa_IR"},
  234. {RML(FINNISH,DEFAULT), "fi_FI"},
  235. {RML(FRENCH,FRENCH), "fr_FR"},
  236. {RML(FRENCH,FRENCH_BELGIAN), "fr_BE"},
  237. {RML(FRENCH,FRENCH_CANADIAN), "fr_CA"},
  238. {RML(FRENCH,FRENCH_LUXEMBOURG), "fr_LU"},
  239. {RML(FRENCH,FRENCH_MONACO), "fr_MC"},
  240. {RML(FRENCH,FRENCH_SWISS), "fr_CH"},
  241. /*{RML(GAELIC,GAELIC), "ga_IE"},*/
  242. /*{RML(GAELIC,GAELIC_MANX), "gv_GB"},*/
  243. /*{RML(GAELIC,GAELIC_SCOTTISH), "gd_GB"},*/
  244. /*{RML(GALICIAN,DEFAULT), "gl_ES"},*/
  245. {RML(GEORGIAN,DEFAULT), "ka_GE"},
  246. {RML(GERMAN,GERMAN), "de_DE"},
  247. {RML(GERMAN,GERMAN_AUSTRIAN), "de_AT"},
  248. {RML(GERMAN,GERMAN_LIECHTENSTEIN), "de_LI"},
  249. {RML(GERMAN,GERMAN_LUXEMBOURG), "de_LU"},
  250. {RML(GERMAN,GERMAN_SWISS), "de_CH"},
  251. {RML(GREEK,DEFAULT), "el_GR"},
  252. {RML(GUJARATI,DEFAULT), "gu_IN"},
  253. {RML(HEBREW,DEFAULT), "he_IL"},
  254. {RML(HINDI,DEFAULT), "hi_IN"},
  255. {RML(HUNGARIAN,DEFAULT), "hu_HU"},
  256. {RML(ICELANDIC,DEFAULT), "is_IS"},
  257. {RML(INDONESIAN,DEFAULT), "id_ID"},
  258. {RML(ITALIAN,ITALIAN), "it_IT"},
  259. {RML(ITALIAN,ITALIAN_SWISS), "it_CH"},
  260. {RML(JAPANESE,DEFAULT), "ja_JP"},
  261. {RML(KANNADA,DEFAULT), "kn_IN"},
  262. {RML(KAZAK,DEFAULT), "kk_KZ"},
  263. {RML(KONKANI,DEFAULT), "kok_IN"},
  264. {RML(KOREAN,KOREAN), "ko_KR"},
  265. /*{RML(KYRGYZ,DEFAULT), "ky_KG"},*/
  266. {RML(LATVIAN,DEFAULT), "lv_LV"},
  267. {RML(LITHUANIAN,LITHUANIAN), "lt_LT"},
  268. {RML(MACEDONIAN,DEFAULT), "mk_MK"},
  269. {RML(MALAY,MALAY_BRUNEI_DARUSSALAM), "ms_BN"},
  270. {RML(MALAY,MALAY_MALAYSIA), "ms_MY"},
  271. {RML(MARATHI,DEFAULT), "mr_IN"},
  272. /*{RML(MONGOLIAN,DEFAULT), "mn_MN"},*/
  273. {RML(NORWEGIAN,NORWEGIAN_BOKMAL), "nb_NO"},
  274. {RML(NORWEGIAN,NORWEGIAN_NYNORSK), "nn_NO"},
  275. {RML(POLISH,DEFAULT), "pl_PL"},
  276. {RML(PORTUGUESE,PORTUGUESE), "pt_PT"},
  277. {RML(PORTUGUESE,PORTUGUESE_BRAZILIAN), "pt_BR"},
  278. {RML(PUNJABI,DEFAULT), "pa_IN"},
  279. {RML(ROMANIAN,DEFAULT), "ro_RO"},
  280. {RML(RUSSIAN,DEFAULT), "ru_RU"},
  281. {RML(SANSKRIT,DEFAULT), "sa_IN"},
  282. {RML(SERBIAN,DEFAULT), "hr_HR"},
  283. {RML(SERBIAN,SERBIAN_CYRILLIC), "sr_SP"},
  284. {RML(SERBIAN,SERBIAN_LATIN), "sr_SP"},
  285. {RML(SLOVAK,DEFAULT), "sk_SK"},
  286. {RML(SLOVENIAN,DEFAULT), "sl_SI"},
  287. {RML(SPANISH,SPANISH), "es_ES"},
  288. {RML(SPANISH,SPANISH_ARGENTINA), "es_AR"},
  289. {RML(SPANISH,SPANISH_BOLIVIA), "es_BO"},
  290. {RML(SPANISH,SPANISH_CHILE), "es_CL"},
  291. {RML(SPANISH,SPANISH_COLOMBIA), "es_CO"},
  292. {RML(SPANISH,SPANISH_COSTA_RICA), "es_CR"},
  293. {RML(SPANISH,SPANISH_DOMINICAN_REPUBLIC), "es_DO"},
  294. {RML(SPANISH,SPANISH_ECUADOR), "es_EC"},
  295. {RML(SPANISH,SPANISH_EL_SALVADOR), "es_SV"},
  296. {RML(SPANISH,SPANISH_GUATEMALA), "es_GT"},
  297. {RML(SPANISH,SPANISH_HONDURAS), "es_HN"},
  298. {RML(SPANISH,SPANISH_MEXICAN), "es_MX"},
  299. {RML(SPANISH,SPANISH_MODERN), "es_ES"},
  300. {RML(SPANISH,SPANISH_NICARAGUA), "es_NI"},
  301. {RML(SPANISH,SPANISH_PANAMA), "es_PA"},
  302. {RML(SPANISH,SPANISH_PARAGUAY), "es_PY"},
  303. {RML(SPANISH,SPANISH_PERU), "es_PE"},
  304. {RML(SPANISH,SPANISH_PUERTO_RICO), "es_PR"},
  305. {RML(SPANISH,SPANISH_URUGUAY), "es_UY"},
  306. {RML(SPANISH,SPANISH_VENEZUELA), "es_VE"},
  307. {RML(SWAHILI,DEFAULT), "sw_KE"},
  308. {RML(SWEDISH,SWEDISH), "sv_SE"},
  309. {RML(SWEDISH,SWEDISH_FINLAND), "sv_FI"},
  310. /*{RML(SYRIAC,DEFAULT), "syr_SY"},*/
  311. {RML(TAMIL,DEFAULT), "ta_IN"},
  312. {RML(TATAR,DEFAULT), "tt_TA"},
  313. {RML(TELUGU,DEFAULT), "te_IN"},
  314. {RML(THAI,DEFAULT), "th_TH"},
  315. {RML(TURKISH,DEFAULT), "tr_TR"},
  316. {RML(UKRAINIAN,DEFAULT), "uk_UA"},
  317. {RML(URDU,URDU_PAKISTAN), "ur_PK"},
  318. {RML(UZBEK,UZBEK_CYRILLIC), "uz_UZ"},
  319. {RML(UZBEK,UZBEK_LATIN), "uz_UZ"},
  320. {RML(VIETNAMESE,DEFAULT), "vi_VN"},
  321. /*{RML(WALON,DEFAULT), "wa_BE"},*/
  322. /*{RML(WELSH,DEFAULT), "cy_GB"},*/
  323. };
  324. static const IDToCode primary_to_code[] = {
  325. {LANG_AFRIKAANS, "af"},
  326. {LANG_ARABIC, "ar"},
  327. {LANG_AZERI, "az"},
  328. {LANG_BULGARIAN, "bg"},
  329. /*{LANG_BRETON, "br"},*/
  330. {LANG_BELARUSIAN, "by"},
  331. {LANG_CATALAN, "ca"},
  332. {LANG_CZECH, "cs"},
  333. /*{LANG_WELSH, "cy"},*/
  334. {LANG_DANISH, "da"},
  335. {LANG_GERMAN, "de"},
  336. {LANG_GREEK, "el"},
  337. {LANG_ENGLISH, "en"},
  338. /*{LANG_ESPERANTO, "eo"},*/
  339. {LANG_SPANISH, "es"},
  340. {LANG_ESTONIAN, "et"},
  341. {LANG_BASQUE, "eu"},
  342. {LANG_FARSI, "fa"},
  343. {LANG_FINNISH, "fi"},
  344. {LANG_FAEROESE, "fo"},
  345. {LANG_FRENCH, "fr"},
  346. /*{LANG_GAELIC, "ga"},*/
  347. /*{LANG_GALICIAN, "gl"},*/
  348. {LANG_GUJARATI, "gu"},
  349. {LANG_HEBREW, "he"},
  350. {LANG_HINDI, "hi"},
  351. {LANG_SERBIAN, "hr"},
  352. {LANG_HUNGARIAN, "hu"},
  353. {LANG_ARMENIAN, "hy"},
  354. {LANG_INDONESIAN, "id"},
  355. {LANG_ITALIAN, "it"},
  356. {LANG_JAPANESE, "ja"},
  357. {LANG_GEORGIAN, "ka"},
  358. {LANG_KAZAK, "kk"},
  359. {LANG_KANNADA, "kn"},
  360. {LANG_KOREAN, "ko"},
  361. /*{LANG_KYRGYZ, "ky"},*/
  362. {LANG_LITHUANIAN, "lt"},
  363. {LANG_LATVIAN, "lv"},
  364. {LANG_MACEDONIAN, "mk"},
  365. /*{LANG_MONGOLIAN, "mn"},*/
  366. {LANG_MARATHI, "mr"},
  367. {LANG_MALAY, "ms"},
  368. {LANG_NORWEGIAN, "nb"},
  369. {LANG_DUTCH, "nl"},
  370. {LANG_NORWEGIAN, "nn"},
  371. {LANG_NORWEGIAN, "no"},/* unofficial? */
  372. {LANG_PUNJABI, "pa"},
  373. {LANG_POLISH, "pl"},
  374. {LANG_PORTUGUESE, "pt"},
  375. {LANG_ROMANIAN, "ro"},
  376. {LANG_RUSSIAN, "ru"},
  377. {LANG_SLOVAK, "sk"},
  378. {LANG_SLOVENIAN, "sl"},
  379. {LANG_ALBANIAN, "sq"},
  380. {LANG_SERBIAN, "sr"},
  381. {LANG_SWEDISH, "sv"},
  382. {LANG_SWAHILI, "sw"},
  383. {LANG_TAMIL, "ta"},
  384. {LANG_THAI, "th"},
  385. {LANG_TURKISH, "tr"},
  386. {LANG_TATAR, "tt"},
  387. {LANG_UKRAINIAN, "uk"},
  388. {LANG_URDU, "ur"},
  389. {LANG_UZBEK, "uz"},
  390. {LANG_VIETNAMESE, "vi"},
  391. /*{LANG_WALON, "wa"},*/
  392. {LANG_CHINESE, "zh"},
  393. };
  394. static int num_primary_to_code = LL_ARRAY_SIZE(primary_to_code);
  395. static int num_both_to_code = LL_ARRAY_SIZE(both_to_code);
  396. static const int
  397. lcid_to_fl(LCID lcid,
  398. FL_Locale *rtn) {
  399. LANGID langid = LANGIDFROMLCID(lcid);
  400. LANGID primary_lang = PRIMARYLANGID(langid);
  401. /*LANGID sub_lang = SUBLANGID(langid);*/
  402. int i;
  403. /* try to find an exact primary/sublanguage combo that we know about */
  404. for (i=0; i<num_both_to_code; ++i) {
  405. if (both_to_code[i].id == langid) {
  406. accumulate_locstring(both_to_code[i].code, rtn);
  407. return 1;
  408. }
  409. }
  410. /* fallback to just checking the primary language id */
  411. for (i=0; i<num_primary_to_code; ++i) {
  412. if (primary_to_code[i].id == primary_lang) {
  413. accumulate_locstring(primary_to_code[i].code, rtn);
  414. return 1;
  415. }
  416. }
  417. return 0;
  418. }
  419. #endif
  420. FL_Success
  421. FL_FindLocale(FL_Locale **locale, FL_Domain domain) {
  422. FL_Success success = FL_FAILED;
  423. FL_Locale *rtn = (FL_Locale*)malloc(sizeof(FL_Locale));
  424. rtn->lang = NULL;
  425. rtn->country = NULL;
  426. rtn->variant = NULL;
  427. #ifdef WIN32
  428. /* win32 >= mswindows95 */
  429. {
  430. LCID lcid = GetThreadLocale();
  431. if (lcid_to_fl(lcid, rtn)) {
  432. success = FL_CONFIDENT;
  433. }
  434. if (success == FL_FAILED) {
  435. /* assume US English on mswindows systems unless we know otherwise */
  436. if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
  437. success = FL_DEFAULT_GUESS;
  438. }
  439. }
  440. }
  441. #else
  442. /* assume unixoid */
  443. {
  444. /* examples: */
  445. /* sv_SE.ISO_8859-1 */
  446. /* fr_FR.ISO8859-1 */
  447. /* no_NO_NB */
  448. /* no_NO_NY */
  449. /* no_NO */
  450. /* de_DE */
  451. /* try the various vars in decreasing order of authority */
  452. if (accumulate_env("LC_ALL", rtn) ||
  453. accumulate_env("LC_MESSAGES", rtn) ||
  454. accumulate_env("LANG", rtn) ||
  455. accumulate_env("LANGUAGE", rtn)) {
  456. success = FL_CONFIDENT;
  457. }
  458. if (success == FL_FAILED) {
  459. /* assume US English on unixoid systems unless we know otherwise */
  460. if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
  461. success = FL_DEFAULT_GUESS;
  462. }
  463. }
  464. }
  465. #endif
  466. if (success != FL_FAILED) {
  467. canonise_fl(rtn);
  468. }
  469. *locale = rtn;
  470. return success;
  471. }
  472. void
  473. FL_FreeLocale(FL_Locale **locale) {
  474. if (locale) {
  475. FL_Locale *l = *locale;
  476. if (l) {
  477. if (l->lang) {
  478. free((void*)l->lang);
  479. }
  480. if (l->country) {
  481. free((void*)l->country);
  482. }
  483. if (l->variant) {
  484. free((void*)l->variant);
  485. }
  486. free(l);
  487. *locale = NULL;
  488. }
  489. }
  490. }