llfindlocale.cpp

Go to the documentation of this file.
00001 
00032 /* Yes, this was originally C code. */
00033 
00034 #include "linden_common.h"
00035 
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <ctype.h>
00039 
00040 #ifdef WIN32
00041 #include <windows.h>
00042 #include <winnt.h>
00043 #endif
00044 
00045 #include "llfindlocale.h"
00046 
00047 static int
00048 is_lcchar(const int c) {
00049   return isalnum(c);
00050 }
00051 
00052 static void
00053 lang_country_variant_from_envstring(const char *str,
00054                                     char **lang,
00055                                     char **country,
00056                                     char **variant) {
00057   int end = 0;
00058   int start;
00059 
00060   /* get lang, if any */
00061   start = end;
00062   while (is_lcchar(str[end])) {
00063     ++end;
00064   }
00065   if (start != end) {
00066     int i;
00067     int len = end - start;
00068     char *s = (char*)malloc(len + 1);
00069     for (i=0; i<len; ++i) {
00070       s[i] = tolower(str[start + i]);
00071     }
00072     s[i] = '\0';
00073     *lang = s;
00074   } else {
00075     *lang = NULL;
00076   }
00077 
00078   if (str[end] && str[end]!=':') { /* not at end of str */
00079     ++end;
00080   }
00081 
00082   /* get country, if any */
00083   start = end;
00084   while (is_lcchar(str[end])) {
00085     ++end;
00086   }
00087   if (start != end) {
00088     int i;
00089     int len = end - start;
00090     char *s = (char*)malloc(len + 1);
00091     for (i=0; i<len; ++i) {
00092       s[i] = toupper(str[start + i]);
00093     }
00094     s[i] = '\0';
00095     *country = s;
00096   } else {
00097     *country = NULL;
00098   }
00099 
00100   if (str[end] && str[end]!=':') { /* not at end of str */
00101     ++end;
00102   }
00103 
00104   /* get variant, if any */
00105   start = end;
00106   while (str[end] && str[end]!=':') {
00107     ++end;
00108   }
00109   if (start != end) {
00110     int i;
00111     int len = end - start;
00112     char *s = (char*)malloc(len + 1);
00113     for (i=0; i<len; ++i) {
00114       s[i] = str[start + i];
00115     }
00116     s[i] = '\0';
00117     *variant = s;
00118   } else {
00119     *variant = NULL;
00120   }
00121 }
00122 
00123 
00124 static int
00125 accumulate_locstring(const char *str, FL_Locale *l) {
00126   char *lang = NULL;
00127   char *country = NULL;
00128   char *variant = NULL;
00129   if (str) {
00130     lang_country_variant_from_envstring(str, &lang, &country, &variant);
00131     if (lang) {
00132       l->lang = lang;
00133       l->country = country;
00134       l->variant = variant;
00135       return 1;
00136     }
00137   }
00138   free(lang); free(country); free(variant);
00139   return 0;
00140 }
00141 
00142 
00143 static int
00144 accumulate_env(const char *name, FL_Locale *l) {
00145   char *env;
00146   char *lang = NULL;
00147   char *country = NULL;
00148   char *variant = NULL;
00149   env = getenv(name);
00150   if (env) {
00151     return accumulate_locstring(env, l);
00152   }
00153   free(lang); free(country); free(variant);
00154   return 0;
00155 }
00156 
00157 
00158 static void
00159 canonise_fl(FL_Locale *l) {
00160   /* this function fixes some common locale-specifying mistakes */
00161   /* en_UK -> en_GB */
00162   if (l->lang && 0 == strcmp(l->lang, "en")) {
00163     if (l->country && 0 == strcmp(l->country, "UK")) {
00164       free((void*)l->country);
00165       l->country = strdup("GB");
00166     }
00167   }
00168   /* ja_JA -> ja_JP */
00169   if (l->lang && 0 == strcmp(l->lang, "ja")) {
00170     if (l->country && 0 == strcmp(l->country, "JA")) {
00171       free((void*)l->country);
00172       l->country = strdup("JP");
00173     }
00174   }
00175 }
00176 
00177 
00178 #ifdef WIN32
00179 #include <stdio.h>
00180 #define ML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##pn##_##sn)
00181 #define MLN(pn) MAKELANGID(LANG_##pn, SUBLANG_DEFAULT)
00182 #define RML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##sn)
00183 typedef struct {
00184   LANGID id;
00185   char*  code;
00186 } IDToCode;
00187 static const IDToCode both_to_code[] = {
00188   {ML(ENGLISH,US),           "en_US.ISO_8859-1"},
00189   {ML(ENGLISH,CAN),          "en_CA"}, /* english / canadian */
00190   {ML(ENGLISH,UK),           "en_GB"},
00191   {ML(ENGLISH,EIRE),         "en_IE"},
00192   {ML(ENGLISH,AUS),          "en_AU"},
00193   {MLN(GERMAN),              "de_DE"},
00194   {MLN(SPANISH),             "es_ES"},
00195   {ML(SPANISH,MEXICAN),      "es_MX"},
00196   {MLN(FRENCH),              "fr_FR"},
00197   {ML(FRENCH,CANADIAN),      "fr_CA"},
00198   {ML(FRENCH,BELGIAN),       "fr_BE"}, /* ? */
00199   {ML(DUTCH,BELGIAN),        "nl_BE"}, /* ? */
00200   {ML(PORTUGUESE,BRAZILIAN), "pt_BR"},
00201   {MLN(PORTUGUESE),          "pt_PT"},
00202   {MLN(SWEDISH),             "sv_SE"},
00203   {ML(CHINESE,HONGKONG),     "zh_HK"},
00204   /* these are machine-generated and not yet verified */
00205   {RML(AFRIKAANS,DEFAULT), "af_ZA"},
00206   {RML(ALBANIAN,DEFAULT), "sq_AL"},
00207   {RML(ARABIC,ARABIC_ALGERIA), "ar_DZ"},
00208   {RML(ARABIC,ARABIC_BAHRAIN), "ar_BH"},
00209   {RML(ARABIC,ARABIC_EGYPT), "ar_EG"},
00210   {RML(ARABIC,ARABIC_IRAQ), "ar_IQ"},
00211   {RML(ARABIC,ARABIC_JORDAN), "ar_JO"},
00212   {RML(ARABIC,ARABIC_KUWAIT), "ar_KW"},
00213   {RML(ARABIC,ARABIC_LEBANON), "ar_LB"},
00214   {RML(ARABIC,ARABIC_LIBYA), "ar_LY"},
00215   {RML(ARABIC,ARABIC_MOROCCO), "ar_MA"},
00216   {RML(ARABIC,ARABIC_OMAN), "ar_OM"},
00217   {RML(ARABIC,ARABIC_QATAR), "ar_QA"},
00218   {RML(ARABIC,ARABIC_SAUDI_ARABIA), "ar_SA"},
00219   {RML(ARABIC,ARABIC_SYRIA), "ar_SY"},
00220   {RML(ARABIC,ARABIC_TUNISIA), "ar_TN"},
00221   {RML(ARABIC,ARABIC_UAE), "ar_AE"},
00222   {RML(ARABIC,ARABIC_YEMEN), "ar_YE"},
00223   {RML(ARMENIAN,DEFAULT), "hy_AM"},
00224   {RML(AZERI,AZERI_CYRILLIC), "az_AZ"},
00225   {RML(AZERI,AZERI_LATIN), "az_AZ"},
00226   {RML(BASQUE,DEFAULT), "eu_ES"},
00227   {RML(BELARUSIAN,DEFAULT), "be_BY"},
00228 /*{RML(BRETON,DEFAULT), "br_FR"},*/
00229   {RML(BULGARIAN,DEFAULT), "bg_BG"},
00230   {RML(CATALAN,DEFAULT), "ca_ES"},
00231   {RML(CHINESE,CHINESE_HONGKONG), "zh_HK"},
00232   {RML(CHINESE,CHINESE_MACAU), "zh_MO"},
00233   {RML(CHINESE,CHINESE_SIMPLIFIED), "zh_CN"},
00234   {RML(CHINESE,CHINESE_SINGAPORE), "zh_SG"},
00235   {RML(CHINESE,CHINESE_TRADITIONAL), "zh_TW"},
00236 /*{RML(CORNISH,DEFAULT), "kw_GB"},*/
00237   {RML(CZECH,DEFAULT), "cs_CZ"},
00238   {RML(DANISH,DEFAULT), "da_DK"},
00239   {RML(DUTCH,DUTCH), "nl_NL"},
00240   {RML(DUTCH,DUTCH_BELGIAN), "nl_BE"},
00241 /*{RML(DUTCH,DUTCH_SURINAM), "nl_SR"},*/
00242   {RML(ENGLISH,ENGLISH_AUS), "en_AU"},
00243   {RML(ENGLISH,ENGLISH_BELIZE), "en_BZ"},
00244   {RML(ENGLISH,ENGLISH_CAN), "en_CA"},
00245   {RML(ENGLISH,ENGLISH_CARIBBEAN), "en_CB"},
00246   {RML(ENGLISH,ENGLISH_EIRE), "en_IE"},
00247   {RML(ENGLISH,ENGLISH_JAMAICA), "en_JM"},
00248   {RML(ENGLISH,ENGLISH_NZ), "en_NZ"},
00249   {RML(ENGLISH,ENGLISH_PHILIPPINES), "en_PH"},
00250   {RML(ENGLISH,ENGLISH_SOUTH_AFRICA), "en_ZA"},
00251   {RML(ENGLISH,ENGLISH_TRINIDAD), "en_TT"},
00252   {RML(ENGLISH,ENGLISH_UK), "en_GB"},
00253   {RML(ENGLISH,ENGLISH_US), "en_US"},
00254   {RML(ENGLISH,ENGLISH_ZIMBABWE), "en_ZW"},
00255 /*{RML(ESPERANTO,DEFAULT), "eo_"},*/
00256   {RML(ESTONIAN,DEFAULT), "et_EE"},
00257   {RML(FAEROESE,DEFAULT), "fo_FO"},
00258   {RML(FARSI,DEFAULT), "fa_IR"},
00259   {RML(FINNISH,DEFAULT), "fi_FI"},
00260   {RML(FRENCH,FRENCH), "fr_FR"},
00261   {RML(FRENCH,FRENCH_BELGIAN), "fr_BE"},
00262   {RML(FRENCH,FRENCH_CANADIAN), "fr_CA"},
00263   {RML(FRENCH,FRENCH_LUXEMBOURG), "fr_LU"},
00264   {RML(FRENCH,FRENCH_MONACO), "fr_MC"},
00265   {RML(FRENCH,FRENCH_SWISS), "fr_CH"},
00266 /*{RML(GAELIC,GAELIC), "ga_IE"},*/
00267 /*{RML(GAELIC,GAELIC_MANX), "gv_GB"},*/
00268 /*{RML(GAELIC,GAELIC_SCOTTISH), "gd_GB"},*/
00269 /*{RML(GALICIAN,DEFAULT), "gl_ES"},*/
00270   {RML(GEORGIAN,DEFAULT), "ka_GE"},
00271   {RML(GERMAN,GERMAN), "de_DE"},
00272   {RML(GERMAN,GERMAN_AUSTRIAN), "de_AT"},
00273   {RML(GERMAN,GERMAN_LIECHTENSTEIN), "de_LI"},
00274   {RML(GERMAN,GERMAN_LUXEMBOURG), "de_LU"},
00275   {RML(GERMAN,GERMAN_SWISS), "de_CH"},
00276   {RML(GREEK,DEFAULT), "el_GR"},
00277   {RML(GUJARATI,DEFAULT), "gu_IN"},
00278   {RML(HEBREW,DEFAULT), "he_IL"},
00279   {RML(HINDI,DEFAULT), "hi_IN"},
00280   {RML(HUNGARIAN,DEFAULT), "hu_HU"},
00281   {RML(ICELANDIC,DEFAULT), "is_IS"},
00282   {RML(INDONESIAN,DEFAULT), "id_ID"},
00283   {RML(ITALIAN,ITALIAN), "it_IT"},
00284   {RML(ITALIAN,ITALIAN_SWISS), "it_CH"},
00285   {RML(JAPANESE,DEFAULT), "ja_JP"},
00286   {RML(KANNADA,DEFAULT), "kn_IN"},
00287   {RML(KAZAK,DEFAULT), "kk_KZ"},
00288   {RML(KONKANI,DEFAULT), "kok_IN"},
00289   {RML(KOREAN,KOREAN), "ko_KR"},
00290 /*{RML(KYRGYZ,DEFAULT), "ky_KG"},*/
00291   {RML(LATVIAN,DEFAULT), "lv_LV"},
00292   {RML(LITHUANIAN,LITHUANIAN), "lt_LT"},
00293   {RML(MACEDONIAN,DEFAULT), "mk_MK"},
00294   {RML(MALAY,MALAY_BRUNEI_DARUSSALAM), "ms_BN"},
00295   {RML(MALAY,MALAY_MALAYSIA), "ms_MY"},
00296   {RML(MARATHI,DEFAULT), "mr_IN"},
00297 /*{RML(MONGOLIAN,DEFAULT), "mn_MN"},*/
00298   {RML(NORWEGIAN,NORWEGIAN_BOKMAL), "nb_NO"},
00299   {RML(NORWEGIAN,NORWEGIAN_NYNORSK), "nn_NO"},
00300   {RML(POLISH,DEFAULT), "pl_PL"},
00301   {RML(PORTUGUESE,PORTUGUESE), "pt_PT"},
00302   {RML(PORTUGUESE,PORTUGUESE_BRAZILIAN), "pt_BR"},
00303   {RML(PUNJABI,DEFAULT), "pa_IN"},
00304   {RML(ROMANIAN,DEFAULT), "ro_RO"},
00305   {RML(RUSSIAN,DEFAULT), "ru_RU"},
00306   {RML(SANSKRIT,DEFAULT), "sa_IN"},
00307   {RML(SERBIAN,DEFAULT), "hr_HR"},
00308   {RML(SERBIAN,SERBIAN_CYRILLIC), "sr_SP"},
00309   {RML(SERBIAN,SERBIAN_LATIN), "sr_SP"},
00310   {RML(SLOVAK,DEFAULT), "sk_SK"},
00311   {RML(SLOVENIAN,DEFAULT), "sl_SI"},
00312   {RML(SPANISH,SPANISH), "es_ES"},
00313   {RML(SPANISH,SPANISH_ARGENTINA), "es_AR"},
00314   {RML(SPANISH,SPANISH_BOLIVIA), "es_BO"},
00315   {RML(SPANISH,SPANISH_CHILE), "es_CL"},
00316   {RML(SPANISH,SPANISH_COLOMBIA), "es_CO"},
00317   {RML(SPANISH,SPANISH_COSTA_RICA), "es_CR"},
00318   {RML(SPANISH,SPANISH_DOMINICAN_REPUBLIC), "es_DO"},
00319   {RML(SPANISH,SPANISH_ECUADOR), "es_EC"},
00320   {RML(SPANISH,SPANISH_EL_SALVADOR), "es_SV"},
00321   {RML(SPANISH,SPANISH_GUATEMALA), "es_GT"},
00322   {RML(SPANISH,SPANISH_HONDURAS), "es_HN"},
00323   {RML(SPANISH,SPANISH_MEXICAN), "es_MX"},
00324   {RML(SPANISH,SPANISH_MODERN), "es_ES"},
00325   {RML(SPANISH,SPANISH_NICARAGUA), "es_NI"},
00326   {RML(SPANISH,SPANISH_PANAMA), "es_PA"},
00327   {RML(SPANISH,SPANISH_PARAGUAY), "es_PY"},
00328   {RML(SPANISH,SPANISH_PERU), "es_PE"},
00329   {RML(SPANISH,SPANISH_PUERTO_RICO), "es_PR"},
00330   {RML(SPANISH,SPANISH_URUGUAY), "es_UY"},
00331   {RML(SPANISH,SPANISH_VENEZUELA), "es_VE"},
00332   {RML(SWAHILI,DEFAULT), "sw_KE"},
00333   {RML(SWEDISH,SWEDISH), "sv_SE"},
00334   {RML(SWEDISH,SWEDISH_FINLAND), "sv_FI"},
00335 /*{RML(SYRIAC,DEFAULT), "syr_SY"},*/
00336   {RML(TAMIL,DEFAULT), "ta_IN"},
00337   {RML(TATAR,DEFAULT), "tt_TA"},
00338   {RML(TELUGU,DEFAULT), "te_IN"},
00339   {RML(THAI,DEFAULT), "th_TH"},
00340   {RML(TURKISH,DEFAULT), "tr_TR"},
00341   {RML(UKRAINIAN,DEFAULT), "uk_UA"},
00342   {RML(URDU,URDU_PAKISTAN), "ur_PK"},
00343   {RML(UZBEK,UZBEK_CYRILLIC), "uz_UZ"},
00344   {RML(UZBEK,UZBEK_LATIN), "uz_UZ"},
00345   {RML(VIETNAMESE,DEFAULT), "vi_VN"},
00346 /*{RML(WALON,DEFAULT), "wa_BE"},*/
00347 /*{RML(WELSH,DEFAULT), "cy_GB"},*/
00348 };
00349 static const IDToCode primary_to_code[] = {
00350   {LANG_AFRIKAANS,  "af"},
00351   {LANG_ARABIC,     "ar"},
00352   {LANG_AZERI,      "az"},
00353   {LANG_BULGARIAN,  "bg"},
00354 /*{LANG_BRETON,     "br"},*/
00355   {LANG_BELARUSIAN, "by"},
00356   {LANG_CATALAN,    "ca"},
00357   {LANG_CZECH,      "cs"},
00358 /*{LANG_WELSH,      "cy"},*/
00359   {LANG_DANISH,     "da"},
00360   {LANG_GERMAN,     "de"},
00361   {LANG_GREEK,      "el"},
00362   {LANG_ENGLISH,    "en"},
00363 /*{LANG_ESPERANTO,  "eo"},*/
00364   {LANG_SPANISH,    "es"},
00365   {LANG_ESTONIAN,   "et"},
00366   {LANG_BASQUE,     "eu"},
00367   {LANG_FARSI,      "fa"},
00368   {LANG_FINNISH,    "fi"},
00369   {LANG_FAEROESE,   "fo"},
00370   {LANG_FRENCH,     "fr"},
00371 /*{LANG_GAELIC,     "ga"},*/
00372 /*{LANG_GALICIAN,   "gl"},*/
00373   {LANG_GUJARATI,   "gu"},
00374   {LANG_HEBREW,     "he"},
00375   {LANG_HINDI,      "hi"},
00376   {LANG_SERBIAN,    "hr"},
00377   {LANG_HUNGARIAN,  "hu"},
00378   {LANG_ARMENIAN,   "hy"},
00379   {LANG_INDONESIAN, "id"},
00380   {LANG_ITALIAN,    "it"},
00381   {LANG_JAPANESE,   "ja"},
00382   {LANG_GEORGIAN,   "ka"},
00383   {LANG_KAZAK,      "kk"},
00384   {LANG_KANNADA,    "kn"},
00385   {LANG_KOREAN,     "ko"},
00386 /*{LANG_KYRGYZ,     "ky"},*/
00387   {LANG_LITHUANIAN, "lt"},
00388   {LANG_LATVIAN,    "lv"},
00389   {LANG_MACEDONIAN, "mk"},
00390 /*{LANG_MONGOLIAN,  "mn"},*/
00391   {LANG_MARATHI,    "mr"},
00392   {LANG_MALAY,      "ms"},
00393   {LANG_NORWEGIAN,  "nb"},
00394   {LANG_DUTCH,      "nl"},
00395   {LANG_NORWEGIAN,  "nn"},
00396   {LANG_NORWEGIAN,  "no"},/* unofficial? */
00397   {LANG_PUNJABI,    "pa"},
00398   {LANG_POLISH,     "pl"},
00399   {LANG_PORTUGUESE, "pt"},
00400   {LANG_ROMANIAN,   "ro"},
00401   {LANG_RUSSIAN,    "ru"},
00402   {LANG_SLOVAK,     "sk"},
00403   {LANG_SLOVENIAN,  "sl"},
00404   {LANG_ALBANIAN,   "sq"},
00405   {LANG_SERBIAN,    "sr"},
00406   {LANG_SWEDISH,    "sv"},
00407   {LANG_SWAHILI,    "sw"},
00408   {LANG_TAMIL,      "ta"},
00409   {LANG_THAI,       "th"},
00410   {LANG_TURKISH,    "tr"},
00411   {LANG_TATAR,      "tt"},
00412   {LANG_UKRAINIAN,  "uk"},
00413   {LANG_URDU,       "ur"},
00414   {LANG_UZBEK,      "uz"},
00415   {LANG_VIETNAMESE, "vi"},
00416 /*{LANG_WALON,      "wa"},*/
00417   {LANG_CHINESE,    "zh"},
00418 };
00419 static int num_primary_to_code =
00420   sizeof(primary_to_code) / sizeof(*primary_to_code);
00421 static int num_both_to_code =
00422   sizeof(both_to_code) / sizeof(*both_to_code);
00423 
00424 static const int
00425 lcid_to_fl(LCID lcid,
00426            FL_Locale *rtn) {
00427   LANGID langid       = LANGIDFROMLCID(lcid);
00428   LANGID primary_lang = PRIMARYLANGID(langid);
00429   /*LANGID sub_lang     = SUBLANGID(langid);*/
00430   int i;
00431   /* try to find an exact primary/sublanguage combo that we know about */
00432   for (i=0; i<num_both_to_code; ++i) {
00433     if (both_to_code[i].id == langid) {
00434       accumulate_locstring(both_to_code[i].code, rtn);
00435       return 1;
00436     }
00437   }
00438   /* fallback to just checking the primary language id */
00439   for (i=0; i<num_primary_to_code; ++i) {
00440     if (primary_to_code[i].id == primary_lang) {
00441       accumulate_locstring(primary_to_code[i].code, rtn);
00442       return 1;
00443     }
00444   }
00445   return 0;
00446 }
00447 #endif
00448 
00449 
00450 FL_Success
00451 FL_FindLocale(FL_Locale **locale, FL_Domain domain) {
00452   FL_Success success = FL_FAILED;
00453   FL_Locale *rtn = (FL_Locale*)malloc(sizeof(FL_Locale));
00454   rtn->lang = NULL;
00455   rtn->country = NULL;
00456   rtn->variant = NULL;
00457 
00458 #ifdef WIN32
00459   /* win32 >= mswindows95 */
00460   {
00461     LCID lcid = GetThreadLocale();
00462     if (lcid_to_fl(lcid, rtn)) {
00463       success = FL_CONFIDENT;
00464     }
00465     if (success == FL_FAILED) {
00466       /* assume US English on mswindows systems unless we know otherwise */
00467       if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
00468         success = FL_DEFAULT_GUESS;
00469       }
00470     }
00471   }
00472 #else
00473   /* assume unixoid */
00474   {
00475     /* examples: */
00476     /* sv_SE.ISO_8859-1 */
00477     /* fr_FR.ISO8859-1 */
00478     /* no_NO_NB */
00479     /* no_NO_NY */
00480     /* no_NO */
00481     /* de_DE */
00482     /* try the various vars in decreasing order of authority */
00483     if (accumulate_env("LC_ALL", rtn) ||
00484         accumulate_env("LC_MESSAGES", rtn) ||
00485         accumulate_env("LANG", rtn) ||
00486         accumulate_env("LANGUAGE", rtn)) {
00487       success = FL_CONFIDENT;
00488     }
00489     if (success == FL_FAILED) {
00490       /* assume US English on unixoid systems unless we know otherwise */
00491       if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
00492         success = FL_DEFAULT_GUESS;
00493       }
00494     }
00495   }
00496 #endif
00497 
00498   if (success != FL_FAILED) {
00499     canonise_fl(rtn);
00500   }
00501 
00502   *locale = rtn;
00503   return success;
00504 }
00505 
00506 
00507 void
00508 FL_FreeLocale(FL_Locale **locale) {
00509   if (locale) {
00510     FL_Locale *l = *locale;
00511     if (l) {
00512       if (l->lang) {
00513         free((void*)l->lang);
00514       }
00515       if (l->country) {
00516         free((void*)l->country);
00517       }
00518       if (l->variant) {
00519         free((void*)l->variant);
00520       }
00521       free(l);
00522       *locale = NULL;
00523     }
00524   }
00525 }

Generated on Fri May 16 08:32:03 2008 for SecondLife by  doxygen 1.5.5