X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/46f4442e9a5a4f3b98b7c1083586332f6a8a99a4..4388f060552cc537e71e957d32f35e9d75a61233:/icuSources/common/locid.cpp?ds=sidebyside diff --git a/icuSources/common/locid.cpp b/icuSources/common/locid.cpp index fe10efa0..80b8a32b 100644 --- a/icuSources/common/locid.cpp +++ b/icuSources/common/locid.cpp @@ -1,6 +1,6 @@ /* ********************************************************************** - * Copyright (C) 1997-2008, International Business Machines + * Copyright (C) 1997-2011, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** * @@ -32,17 +32,17 @@ #include "unicode/locid.h" #include "unicode/uloc.h" +#include "putilimp.h" #include "umutex.h" #include "uassert.h" #include "cmemory.h" #include "cstring.h" #include "uhash.h" #include "ucln_cmn.h" +#include "ustr_imp.h" #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) -static U_NAMESPACE_QUALIFIER Locale* availableLocaleList = NULL; -static int32_t availableLocaleListCount; typedef enum ELocalePos { eENGLISH, eFRENCH, @@ -63,6 +63,7 @@ typedef enum ELocalePos { eUS, eCANADA, eCANADA_FRENCH, + eROOT, //eDEFAULT, @@ -76,9 +77,9 @@ U_CFUNC int32_t locale_getKeywords(const char *localeID, UBool valuesToo, UErrorCode *status); -static U_NAMESPACE_QUALIFIER Locale *gLocaleCache = NULL; -static U_NAMESPACE_QUALIFIER Locale *gDefaultLocale = NULL; -static UHashtable *gDefaultLocalesHashT = NULL; +static icu::Locale *gLocaleCache = NULL; +static icu::Locale *gDefaultLocale = NULL; +static UHashtable *gDefaultLocalesHashT = NULL; U_CDECL_BEGIN // @@ -86,19 +87,13 @@ U_CDECL_BEGIN // static void U_CALLCONV deleteLocale(void *obj) { - delete (U_NAMESPACE_QUALIFIER Locale *) obj; + delete (icu::Locale *) obj; } static UBool U_CALLCONV locale_cleanup(void) { U_NAMESPACE_USE - if (availableLocaleList) { - delete []availableLocaleList; - availableLocaleList = NULL; - } - availableLocaleListCount = 0; - if (gLocaleCache) { delete [] gLocaleCache; gLocaleCache = NULL; @@ -171,16 +166,30 @@ void locale_set_default_internal(const char *id) gDefaultLocale = newFirstDefault; // Assignment to gDefaultLocale must happen inside mutex newFirstDefault = NULL; ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup); - } - // Else some other thread raced us through here, and set the new Locale. - // Use the hash table next. - umtx_unlock(NULL); - if (newFirstDefault == NULL) { + // We were successful in setting the locale, and we were the first one to set it. + umtx_unlock(NULL); return; } - // else start using the hash table. + // Else some other thread raced us through here, and set the new Locale. + else { + delete newFirstDefault; + } + umtx_unlock(NULL); + } + + // Create the hash table next, unless the racing thread is setting the same locale as default. + // The new locale might have been set while a racing thread was stuck at the lock + // earlier in this function. (For example, see uprv_getDefaultLocaleID above). + umtx_lock(NULL); + // Only create the hash table if we need to. + if (uprv_strcmp(gDefaultLocale->getName(), localeNameBuf) == 0) { + umtx_unlock(NULL); + return; } + umtx_unlock(NULL); + // start using the hash table. + // Lazy creation of the hash table itself, if needed. UBool hashTableNeedsInit; @@ -196,9 +205,10 @@ void locale_set_default_internal(const char *id) if (gDefaultLocalesHashT == NULL) { gDefaultLocalesHashT = tHashTable; ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup); + + uhash_put(gDefaultLocalesHashT, (void *)gDefaultLocale->getName(), gDefaultLocale, &status); } else { uhash_close(tHashTable); - hashTableNeedsInit = FALSE; } umtx_unlock(NULL); } @@ -228,11 +238,6 @@ void locale_set_default_internal(const char *id) umtx_lock(NULL); Locale *hashTableVal = (Locale *)uhash_get(gDefaultLocalesHashT, key); if (hashTableVal == NULL) { - if (hashTableNeedsInit) { - // This is the second request to set the locale. - // Cache the first one. - uhash_put(gDefaultLocalesHashT, (void *)gDefaultLocale->getName(), gDefaultLocale, &status); - } uhash_put(gDefaultLocalesHashT, (void *)key, newDefault, &status); gDefaultLocale = newDefault; // ignore errors from hash table insert. (Couldn't do anything anyway) @@ -320,9 +325,7 @@ Locale::Locale( const char * newLanguage, } else { - char togo_stack[ULOC_FULLNAME_CAPACITY]; - char *togo; - char *togo_heap = NULL; + MaybeStackArray togo; int32_t size = 0; int32_t lsize = 0; int32_t csize = 0; @@ -389,24 +392,18 @@ Locale::Locale( const char * newLanguage, /*if the whole string is longer than our internal limit, we need to go to the heap for temporary buffers*/ - if (size >= ULOC_FULLNAME_CAPACITY) + if (size >= togo.getCapacity()) { - togo_heap = (char *)uprv_malloc(sizeof(char)*(size+1)); // If togo_heap could not be created, initialize with default settings. - if (togo_heap == NULL) { + if (togo.resize(size+1) == NULL) { init(NULL, FALSE); } - togo = togo_heap; - } - else - { - togo = togo_stack; } togo[0] = 0; // Now, copy it back. - p = togo; + p = togo.getAlias(); if ( lsize != 0 ) { uprv_strcpy(p, newLanguage); @@ -450,11 +447,7 @@ Locale::Locale( const char * newLanguage, // Parse it, because for example 'language' might really be a complete // string. - init(togo, FALSE); - - if (togo_heap) { - uprv_free(togo_heap); - } + init(togo.getAlias(), FALSE); } } @@ -510,7 +503,7 @@ Locale &Locale::operator=(const Locale &other) uprv_strcpy(script, other.script); uprv_strcpy(country, other.country); - /* The variantBegin is an offset into fullName, just copy it */ + /* The variantBegin is an offset, just copy it */ variantBegin = other.variantBegin; fIsBogus = other.fIsBogus; return *this; @@ -527,6 +520,8 @@ Locale::operator==( const Locale& other) const return (uprv_strcmp(other.fullName, fullName) == 0); } +#define ISASCIIALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) + /*This function initializes a Locale from a C locale ID*/ Locale& Locale::init(const char* localeID, UBool canonicalize) { @@ -607,36 +602,36 @@ Locale& Locale::init(const char* localeID, UBool canonicalize) fieldLen[fieldIdx-1] = length - (int32_t)(field[fieldIdx-1] - fullName); } - if (fieldLen[0] >= (int32_t)(sizeof(language)) - || (fieldLen[1] == 4 && fieldLen[2] >= (int32_t)(sizeof(country))) - || (fieldLen[1] != 4 && fieldLen[1] >= (int32_t)(sizeof(country)))) + if (fieldLen[0] >= (int32_t)(sizeof(language))) { - break; // error: one of the fields is too long + break; // error: the language field is too long } - variantField = 2; /* Usually the 2nd one, except when a script is used. */ + variantField = 1; /* Usually the 2nd one, except when a script or country is also used. */ if (fieldLen[0] > 0) { /* We have a language */ uprv_memcpy(language, fullName, fieldLen[0]); language[fieldLen[0]] = 0; } - if (fieldLen[1] == 4) { + if (fieldLen[1] == 4 && ISASCIIALPHA(field[1][0]) && + ISASCIIALPHA(field[1][1]) && ISASCIIALPHA(field[1][2]) && + ISASCIIALPHA(field[1][3])) { /* We have at least a script */ uprv_memcpy(script, field[1], fieldLen[1]); script[fieldLen[1]] = 0; - variantField = 3; - if (fieldLen[2] > 0) { - /* We have a country */ - uprv_memcpy(country, field[2], fieldLen[2]); - country[fieldLen[2]] = 0; - } + variantField++; } - else if (fieldLen[1] > 0) { - /* We have a country and no script */ - uprv_memcpy(country, field[1], fieldLen[1]); - country[fieldLen[1]] = 0; + + if (fieldLen[variantField] == 2 || fieldLen[variantField] == 3) { + /* We have a country */ + uprv_memcpy(country, field[variantField], fieldLen[variantField]); + country[fieldLen[variantField]] = 0; + variantField++; + } else if (fieldLen[variantField] == 0) { + variantField++; /* script or country empty but variant in next field (i.e. en__POSIX) */ } - if (variantField > 0 && fieldLen[variantField] > 0) { + + if (fieldLen[variantField] > 0) { /* We have a variant */ variantBegin = (int32_t)(field[variantField] - fullName); } @@ -654,9 +649,7 @@ Locale& Locale::init(const char* localeID, UBool canonicalize) int32_t Locale::hashCode() const { - UHashTok hashKey; - hashKey.pointer = fullName; - return uhash_hashChars(hashKey); + return ustr_hashCharsN(fullName, uprv_strlen(fullName)); } void @@ -666,6 +659,10 @@ Locale::setToBogus() { uprv_free(fullName); fullName = fullNameBuffer; } + if(baseName && baseName != baseNameBuffer) { + uprv_free(baseName); + baseName = NULL; + } *fullNameBuffer = 0; *language = 0; *script = 0; @@ -754,249 +751,6 @@ Locale::getLCID() const return uloc_getLCID(fullName); } -UnicodeString& -Locale::getDisplayLanguage(UnicodeString& dispLang) const -{ - return this->getDisplayLanguage(getDefault(), dispLang); -} - -/*We cannot make any assumptions on the size of the output display strings -* Yet, since we are calling through to a C API, we need to set limits on -* buffer size. For all the following getDisplay functions we first attempt -* to fill up a stack allocated buffer. If it is to small we heap allocated -* the exact buffer we need copy it to the UnicodeString and delete it*/ - -UnicodeString& -Locale::getDisplayLanguage(const Locale &displayLocale, - UnicodeString &result) const { - UChar *buffer; - UErrorCode errorCode=U_ZERO_ERROR; - int32_t length; - - buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); - if(buffer==0) { - result.truncate(0); - return result; - } - - length=uloc_getDisplayLanguage(fullName, displayLocale.fullName, - buffer, result.getCapacity(), - &errorCode); - result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); - - if(errorCode==U_BUFFER_OVERFLOW_ERROR) { - buffer=result.getBuffer(length); - if(buffer==0) { - result.truncate(0); - return result; - } - errorCode=U_ZERO_ERROR; - length=uloc_getDisplayLanguage(fullName, displayLocale.fullName, - buffer, result.getCapacity(), - &errorCode); - result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); - } - - return result; -} - -UnicodeString& -Locale::getDisplayScript(UnicodeString& dispScript) const -{ - return this->getDisplayScript(getDefault(), dispScript); -} - -UnicodeString& -Locale::getDisplayScript(const Locale &displayLocale, - UnicodeString &result) const { - UChar *buffer; - UErrorCode errorCode=U_ZERO_ERROR; - int32_t length; - - buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); - if(buffer==0) { - result.truncate(0); - return result; - } - - length=uloc_getDisplayScript(fullName, displayLocale.fullName, - buffer, result.getCapacity(), - &errorCode); - result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); - - if(errorCode==U_BUFFER_OVERFLOW_ERROR) { - buffer=result.getBuffer(length); - if(buffer==0) { - result.truncate(0); - return result; - } - errorCode=U_ZERO_ERROR; - length=uloc_getDisplayScript(fullName, displayLocale.fullName, - buffer, result.getCapacity(), - &errorCode); - result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); - } - - return result; -} - -UnicodeString& -Locale::getDisplayCountry(UnicodeString& dispCntry) const -{ - return this->getDisplayCountry(getDefault(), dispCntry); -} - -UnicodeString& -Locale::getDisplayCountry(const Locale &displayLocale, - UnicodeString &result) const { - UChar *buffer; - UErrorCode errorCode=U_ZERO_ERROR; - int32_t length; - - buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); - if(buffer==0) { - result.truncate(0); - return result; - } - - length=uloc_getDisplayCountry(fullName, displayLocale.fullName, - buffer, result.getCapacity(), - &errorCode); - result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); - - if(errorCode==U_BUFFER_OVERFLOW_ERROR) { - buffer=result.getBuffer(length); - if(buffer==0) { - result.truncate(0); - return result; - } - errorCode=U_ZERO_ERROR; - length=uloc_getDisplayCountry(fullName, displayLocale.fullName, - buffer, result.getCapacity(), - &errorCode); - result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); - } - - return result; -} - -UnicodeString& -Locale::getDisplayVariant(UnicodeString& dispVar) const -{ - return this->getDisplayVariant(getDefault(), dispVar); -} - -UnicodeString& -Locale::getDisplayVariant(const Locale &displayLocale, - UnicodeString &result) const { - UChar *buffer; - UErrorCode errorCode=U_ZERO_ERROR; - int32_t length; - - buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); - if(buffer==0) { - result.truncate(0); - return result; - } - - length=uloc_getDisplayVariant(fullName, displayLocale.fullName, - buffer, result.getCapacity(), - &errorCode); - result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); - - if(errorCode==U_BUFFER_OVERFLOW_ERROR) { - buffer=result.getBuffer(length); - if(buffer==0) { - result.truncate(0); - return result; - } - errorCode=U_ZERO_ERROR; - length=uloc_getDisplayVariant(fullName, displayLocale.fullName, - buffer, result.getCapacity(), - &errorCode); - result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); - } - - return result; -} - -UnicodeString& -Locale::getDisplayName( UnicodeString& name ) const -{ - return this->getDisplayName(getDefault(), name); -} - -UnicodeString& -Locale::getDisplayName(const Locale &displayLocale, - UnicodeString &result) const { - UChar *buffer; - UErrorCode errorCode=U_ZERO_ERROR; - int32_t length; - - buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); - if(buffer==0) { - result.truncate(0); - return result; - } - - length=uloc_getDisplayName(fullName, displayLocale.fullName, - buffer, result.getCapacity(), - &errorCode); - result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); - - if(errorCode==U_BUFFER_OVERFLOW_ERROR) { - buffer=result.getBuffer(length); - if(buffer==0) { - result.truncate(0); - return result; - } - errorCode=U_ZERO_ERROR; - length=uloc_getDisplayName(fullName, displayLocale.fullName, - buffer, result.getCapacity(), - &errorCode); - result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); - } - - return result; -} -const Locale* U_EXPORT2 -Locale::getAvailableLocales(int32_t& count) -{ - // for now, there is a hardcoded list, so just walk through that list and set it up. - UBool needInit; - UMTX_CHECK(NULL, availableLocaleList == NULL, needInit); - - if (needInit) { - int32_t locCount = uloc_countAvailable(); - Locale *newLocaleList = 0; - if(locCount) { - newLocaleList = new Locale[locCount]; - } - if (newLocaleList == NULL) { - count = 0; - return NULL; - } - - count = locCount; - - while(--locCount >= 0) { - newLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount)); - } - - umtx_lock(NULL); - if(availableLocaleList == 0) { - availableLocaleListCount = count; - availableLocaleList = newLocaleList; - newLocaleList = NULL; - ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup); - } - umtx_unlock(NULL); - delete []newLocaleList; - } - count = availableLocaleListCount; - return availableLocaleList; -} - const char* const* U_EXPORT2 Locale::getISOCountries() { return uloc_getISOCountries(); @@ -1013,6 +767,12 @@ void Locale::setFromPOSIXID(const char *posixID) init(posixID, TRUE); } +const Locale & U_EXPORT2 +Locale::getRoot(void) +{ + return getLocale(eROOT); +} + const Locale & U_EXPORT2 Locale::getEnglish(void) { @@ -1169,6 +929,7 @@ Locale::getLocaleCache(void) if (tLocaleCache == NULL) { return NULL; } + tLocaleCache[eROOT] = Locale(""); tLocaleCache[eENGLISH] = Locale("en"); tLocaleCache[eFRENCH] = Locale("fr"); tLocaleCache[eGERMAN] = Locale("de"); @@ -1234,9 +995,7 @@ public: } } - virtual ~KeywordEnumeration() { - uprv_free(keywords); - } + virtual ~KeywordEnumeration(); virtual StringEnumeration * clone() const { @@ -1286,6 +1045,10 @@ public: const char KeywordEnumeration::fgClassID = '\0'; +KeywordEnumeration::~KeywordEnumeration() { + uprv_free(keywords); +} + StringEnumeration * Locale::createKeywords(UErrorCode &status) const { @@ -1314,6 +1077,12 @@ Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, U return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status); } +void +Locale::setKeywordValue(const char* keywordName, const char* keywordValue, UErrorCode &status) +{ + uloc_setKeywordValue(keywordName, keywordValue, fullName, ULOC_FULLNAME_CAPACITY, &status); +} + const char * Locale::getBaseName() const { @@ -1331,10 +1100,16 @@ Locale::getBaseName() const uloc_getBaseName(fullName, baseName, baseNameSize+1, &status); } baseName[baseNameSize] = 0; + + // the computation of variantBegin leaves it equal to the length + // of fullName if there is no variant. It should instead be + // the length of the baseName. Patch around this for now. + if (variantBegin == (int32_t)uprv_strlen(fullName)) { + ((Locale*)this)->variantBegin = baseNameSize; + } } return baseName; } - //eof U_NAMESPACE_END