michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nscore.h" michael@0: #include "nsString.h" michael@0: #include "nsPosixLocale.h" michael@0: #include "prprf.h" michael@0: #include "plstr.h" michael@0: #include "nsReadableUtils.h" michael@0: michael@0: static bool michael@0: ParseLocaleString(const char* locale_string, char* language, char* country, char* extra, char separator); michael@0: michael@0: nsresult michael@0: nsPosixLocale::GetPlatformLocale(const nsAString& locale, nsACString& posixLocale) michael@0: { michael@0: char country_code[MAX_COUNTRY_CODE_LEN+1]; michael@0: char lang_code[MAX_LANGUAGE_CODE_LEN+1]; michael@0: char extra[MAX_EXTRA_LEN+1]; michael@0: char posix_locale[MAX_LOCALE_LEN+1]; michael@0: NS_LossyConvertUTF16toASCII xp_locale(locale); michael@0: michael@0: if (!xp_locale.IsEmpty()) { michael@0: if (!ParseLocaleString(xp_locale.get(),lang_code,country_code,extra,'-')) { michael@0: // strncpy(posixLocale,"C",length); michael@0: posixLocale = xp_locale; // use xp locale if parse failed michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (*country_code) { michael@0: if (*extra) { michael@0: PR_snprintf(posix_locale,sizeof(posix_locale),"%s_%s.%s",lang_code,country_code,extra); michael@0: } michael@0: else { michael@0: PR_snprintf(posix_locale,sizeof(posix_locale),"%s_%s",lang_code,country_code); michael@0: } michael@0: } michael@0: else { michael@0: if (*extra) { michael@0: PR_snprintf(posix_locale,sizeof(posix_locale),"%s.%s",lang_code,extra); michael@0: } michael@0: else { michael@0: PR_snprintf(posix_locale,sizeof(posix_locale),"%s",lang_code); michael@0: } michael@0: } michael@0: michael@0: posixLocale = posix_locale; michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsresult michael@0: nsPosixLocale::GetXPLocale(const char* posixLocale, nsAString& locale) michael@0: { michael@0: char country_code[MAX_COUNTRY_CODE_LEN+1]; michael@0: char lang_code[MAX_LANGUAGE_CODE_LEN+1]; michael@0: char extra[MAX_EXTRA_LEN+1]; michael@0: char posix_locale[MAX_LOCALE_LEN+1]; michael@0: michael@0: if (posixLocale!=nullptr) { michael@0: if (strcmp(posixLocale,"C")==0 || strcmp(posixLocale,"POSIX")==0) { michael@0: locale.AssignLiteral("en-US"); michael@0: return NS_OK; michael@0: } michael@0: if (!ParseLocaleString(posixLocale,lang_code,country_code,extra,'_')) { michael@0: // * locale = "x-user-defined"; michael@0: // use posix if parse failed michael@0: CopyASCIItoUTF16(nsDependentCString(posixLocale), locale); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Special case: substitute "nb" (Norwegian Bokmal) for macrolanguage michael@0: // code "no" (Norwegian) michael@0: if (nsDependentCString(lang_code).LowerCaseEqualsLiteral("no")) { michael@0: lang_code[1] = 'b'; michael@0: } michael@0: michael@0: if (*country_code) { michael@0: PR_snprintf(posix_locale,sizeof(posix_locale),"%s-%s",lang_code,country_code); michael@0: } michael@0: else { michael@0: PR_snprintf(posix_locale,sizeof(posix_locale),"%s",lang_code); michael@0: } michael@0: michael@0: CopyASCIItoUTF16(nsDependentCString(posix_locale), locale); michael@0: return NS_OK; michael@0: michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: } michael@0: michael@0: // michael@0: // returns false/true depending on if it was of the form LL-CC.Extra michael@0: static bool michael@0: ParseLocaleString(const char* locale_string, char* language, char* country, char* extra, char separator) michael@0: { michael@0: const char *src = locale_string; michael@0: char modifier[MAX_EXTRA_LEN+1]; michael@0: char *dest; michael@0: int dest_space, len; michael@0: michael@0: *language = '\0'; michael@0: *country = '\0'; michael@0: *extra = '\0'; michael@0: if (strlen(locale_string) < 2) { michael@0: return(false); michael@0: } michael@0: michael@0: // michael@0: // parse the language part michael@0: // michael@0: dest = language; michael@0: dest_space = MAX_LANGUAGE_CODE_LEN; michael@0: while ((*src) && (isalpha(*src)) && (dest_space--)) { michael@0: *dest++ = tolower(*src++); michael@0: } michael@0: *dest = '\0'; michael@0: len = dest - language; michael@0: if ((len != 2) && (len != 3)) { michael@0: NS_ASSERTION((len == 2) || (len == 3), "language code too short"); michael@0: NS_ASSERTION(len < 3, "reminder: verify we can handle 3+ character language code in all parts of the system; eg: language packs"); michael@0: *language = '\0'; michael@0: return(false); michael@0: } michael@0: michael@0: // check if all done michael@0: if (*src == '\0') { michael@0: return(true); michael@0: } michael@0: michael@0: if ((*src != '_') && (*src != '-') && (*src != '.') && (*src != '@')) { michael@0: NS_ASSERTION(isalpha(*src), "language code too long"); michael@0: NS_ASSERTION(!isalpha(*src), "unexpected language/country separator"); michael@0: *language = '\0'; michael@0: return(false); michael@0: } michael@0: michael@0: // michael@0: // parse the country part michael@0: // michael@0: if ((*src == '_') || (*src == '-')) { michael@0: src++; michael@0: dest = country; michael@0: dest_space = MAX_COUNTRY_CODE_LEN; michael@0: while ((*src) && (isalpha(*src)) && (dest_space--)) { michael@0: *dest++ = toupper(*src++); michael@0: } michael@0: *dest = '\0'; michael@0: len = dest - country; michael@0: if (len != 2) { michael@0: NS_ASSERTION(len == 2, "unexpected country code length"); michael@0: *language = '\0'; michael@0: *country = '\0'; michael@0: return(false); michael@0: } michael@0: } michael@0: michael@0: // check if all done michael@0: if (*src == '\0') { michael@0: return(true); michael@0: } michael@0: michael@0: if ((*src != '.') && (*src != '@')) { michael@0: NS_ASSERTION(isalpha(*src), "country code too long"); michael@0: NS_ASSERTION(!isalpha(*src), "unexpected country/extra separator"); michael@0: *language = '\0'; michael@0: *country = '\0'; michael@0: return(false); michael@0: } michael@0: michael@0: // michael@0: // handle the extra part michael@0: // michael@0: if (*src == '.') { michael@0: src++; // move past the extra part separator michael@0: dest = extra; michael@0: dest_space = MAX_EXTRA_LEN; michael@0: while ((*src) && (*src != '@') && (dest_space--)) { michael@0: *dest++ = *src++; michael@0: } michael@0: *dest = '\0'; michael@0: len = dest - extra; michael@0: if (len < 1) { michael@0: NS_ASSERTION(len > 0, "found country/extra separator but no extra code"); michael@0: *language = '\0'; michael@0: *country = '\0'; michael@0: *extra = '\0'; michael@0: return(false); michael@0: } michael@0: } michael@0: michael@0: // check if all done michael@0: if (*src == '\0') { michael@0: return(true); michael@0: } michael@0: michael@0: // michael@0: // handle the modifier part michael@0: // michael@0: michael@0: if (*src == '@') { michael@0: src++; // move past the modifier separator michael@0: NS_ASSERTION(strcmp("euro",src) == 0, "found non euro modifier"); michael@0: dest = modifier; michael@0: dest_space = MAX_EXTRA_LEN; michael@0: while ((*src) && (dest_space--)) { michael@0: *dest++ = *src++; michael@0: } michael@0: *dest = '\0'; michael@0: len = dest - modifier; michael@0: if (len < 1) { michael@0: NS_ASSERTION(len > 0, "found modifier separator but no modifier code"); michael@0: *language = '\0'; michael@0: *country = '\0'; michael@0: *extra = '\0'; michael@0: *modifier = '\0'; michael@0: return(false); michael@0: } michael@0: } michael@0: michael@0: // check if all done michael@0: if (*src == '\0') { michael@0: return(true); michael@0: } michael@0: michael@0: NS_ASSERTION(*src == '\0', "extra/modifier code too long"); michael@0: *language = '\0'; michael@0: *country = '\0'; michael@0: *extra = '\0'; michael@0: michael@0: return(false); michael@0: } michael@0: