X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/73c04bcfe1096173b00431f0cdc742894b15eef0..a0b4f637ba1a6c3c5651b61a69303b029bacf7d3:/icuSources/common/locid.cpp?ds=inline diff --git a/icuSources/common/locid.cpp b/icuSources/common/locid.cpp index cb8d59eb..27e40306 100644 --- a/icuSources/common/locid.cpp +++ b/icuSources/common/locid.cpp @@ -1,6 +1,6 @@ /* ********************************************************************** - * Copyright (C) 1997-2006, International Business Machines + * Copyright (C) 1997-2015, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** * @@ -32,17 +32,33 @@ #include "unicode/locid.h" #include "unicode/uloc.h" +#include "putilimp.h" +#include "mutex.h" #include "umutex.h" #include "uassert.h" #include "cmemory.h" #include "cstring.h" +#include "uassert.h" #include "uhash.h" #include "ucln_cmn.h" +#include "ustr_imp.h" + +U_CDECL_BEGIN +static UBool U_CALLCONV locale_cleanup(void); +U_CDECL_END + +U_NAMESPACE_BEGIN + +static Locale *gLocaleCache = NULL; +static UInitOnce gLocaleCacheInitOnce = U_INITONCE_INITIALIZER; -#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) +// gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale. +static UMutex gDefaultLocaleMutex = U_MUTEX_INITIALIZER; +static UHashtable *gDefaultLocalesHashT = NULL; +static Locale *gDefaultLocale = NULL; + +U_NAMESPACE_END -static Locale* availableLocaleList = NULL; -static int32_t availableLocaleListCount; typedef enum ELocalePos { eENGLISH, eFRENCH, @@ -63,6 +79,7 @@ typedef enum ELocalePos { eUS, eCANADA, eCANADA_FRENCH, + eROOT, //eDEFAULT, @@ -76,54 +93,71 @@ U_CFUNC int32_t locale_getKeywords(const char *localeID, UBool valuesToo, UErrorCode *status); -static Locale *gLocaleCache = NULL; -static const Locale *gDefaultLocale = NULL; -static UHashtable *gDefaultLocalesHashT = NULL; - U_CDECL_BEGIN // // Deleter function for Locales owned by the default Locale hash table/ // static void U_CALLCONV deleteLocale(void *obj) { - delete (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; - } + delete [] gLocaleCache; + gLocaleCache = NULL; + gLocaleCacheInitOnce.reset(); if (gDefaultLocalesHashT) { uhash_close(gDefaultLocalesHashT); // Automatically deletes all elements, using deleter func. gDefaultLocalesHashT = NULL; } gDefaultLocale = NULL; - return TRUE; } + + +static void U_CALLCONV locale_init(UErrorCode &status) { + U_NAMESPACE_USE + + U_ASSERT(gLocaleCache == NULL); + gLocaleCache = new Locale[(int)eMAX_LOCALES]; + if (gLocaleCache == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup); + gLocaleCache[eROOT] = Locale(""); + gLocaleCache[eENGLISH] = Locale("en"); + gLocaleCache[eFRENCH] = Locale("fr"); + gLocaleCache[eGERMAN] = Locale("de"); + gLocaleCache[eITALIAN] = Locale("it"); + gLocaleCache[eJAPANESE] = Locale("ja"); + gLocaleCache[eKOREAN] = Locale("ko"); + gLocaleCache[eCHINESE] = Locale("zh"); + gLocaleCache[eFRANCE] = Locale("fr", "FR"); + gLocaleCache[eGERMANY] = Locale("de", "DE"); + gLocaleCache[eITALY] = Locale("it", "IT"); + gLocaleCache[eJAPAN] = Locale("ja", "JP"); + gLocaleCache[eKOREA] = Locale("ko", "KR"); + gLocaleCache[eCHINA] = Locale("zh", "CN"); + gLocaleCache[eTAIWAN] = Locale("zh", "TW"); + gLocaleCache[eUK] = Locale("en", "GB"); + gLocaleCache[eUS] = Locale("en", "US"); + gLocaleCache[eCANADA] = Locale("en", "CA"); + gLocaleCache[eCANADA_FRENCH] = Locale("fr", "CA"); +} + U_CDECL_END U_NAMESPACE_BEGIN -UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale) -// -// locale_set_default_internal. -// -void locale_set_default_internal(const char *id) -{ - U_NAMESPACE_USE - UErrorCode status = U_ZERO_ERROR; +Locale *locale_set_default_internal(const char *id, UErrorCode& status) { + // Synchronize this entire function. + Mutex lock(&gDefaultLocaleMutex); + UBool canonicalize = FALSE; // If given a NULL string for the locale id, grab the default @@ -131,17 +165,10 @@ void locale_set_default_internal(const char *id) // (Different from most other locale APIs, where a null name means use // the current ICU default locale.) if (id == NULL) { - umtx_lock(NULL); - id = uprv_getDefaultLocaleID(); - umtx_unlock(NULL); + id = uprv_getDefaultLocaleID(); // This function not thread safe? TODO: verify. canonicalize = TRUE; // always canonicalize host ID } - // put the locale id into a canonical form, - // in preparation for looking up this locale in the hash table of - // already-created locale objects. - // - status = U_ZERO_ERROR; char localeNameBuf[512]; if (canonicalize) { @@ -152,79 +179,46 @@ void locale_set_default_internal(const char *id) localeNameBuf[sizeof(localeNameBuf)-1] = 0; // Force null termination in event of // a long name filling the buffer. // (long names are truncated.) + // + if (U_FAILURE(status)) { + return gDefaultLocale; + } - // Lazy creation of the hash table itself, if needed. - // - umtx_lock(NULL); - UBool hashTableNeedsInit = (gDefaultLocalesHashT == NULL); - umtx_unlock(NULL); - if (hashTableNeedsInit) { - status = U_ZERO_ERROR; - UHashtable *tHashTable = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); + if (gDefaultLocalesHashT == NULL) { + gDefaultLocalesHashT = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); if (U_FAILURE(status)) { - return; - } - uhash_setValueDeleter(tHashTable, deleteLocale); - umtx_lock(NULL); - if (gDefaultLocalesHashT == NULL) { - gDefaultLocalesHashT = tHashTable; - ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup); - umtx_unlock(NULL); - } else { - umtx_unlock(NULL); - uhash_close(tHashTable); + return gDefaultLocale; } + uhash_setValueDeleter(gDefaultLocalesHashT, deleteLocale); + ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup); } - // Hash table lookup, key is the locale full name - umtx_lock(NULL); Locale *newDefault = (Locale *)uhash_get(gDefaultLocalesHashT, localeNameBuf); - if (newDefault != NULL) { - // We have the requested locale in the hash table already. - // Just set it as default. Inside the mutex lock, for those troublesome processors. - gDefaultLocale = newDefault; - umtx_unlock(NULL); - } else { - umtx_unlock(NULL); - // We haven't seen this locale id before. - // Create a new Locale object for it. + if (newDefault == NULL) { newDefault = new Locale(Locale::eBOGUS); if (newDefault == NULL) { - // No way to report errors from here. - return; + status = U_MEMORY_ALLOCATION_ERROR; + return gDefaultLocale; } newDefault->init(localeNameBuf, FALSE); - - // Add newly created Locale to the hash table of default Locales - const char *key = newDefault->getName(); - U_ASSERT(uprv_strcmp(key, localeNameBuf) == 0); - umtx_lock(NULL); - const Locale *hashTableVal = (const Locale *)uhash_get(gDefaultLocalesHashT, key); - if (hashTableVal == NULL) { - uhash_put(gDefaultLocalesHashT, (void *)key, newDefault, &status); - gDefaultLocale = newDefault; - umtx_unlock(NULL); - // ignore errors from hash table insert. (Couldn't do anything anyway) - // We can still set the default Locale, - // it just wont be cached, and will eventually leak. - } else { - // Some other thread raced us through here, and got the new Locale - // into the hash table before us. Use that one. - gDefaultLocale = hashTableVal; // Assignment to gDefaultLocale must happen inside mutex - umtx_unlock(NULL); - delete newDefault; + uhash_put(gDefaultLocalesHashT, (char*) newDefault->getName(), newDefault, &status); + if (U_FAILURE(status)) { + return gDefaultLocale; } } + gDefaultLocale = newDefault; + return gDefaultLocale; } -U_NAMESPACE_END +U_NAMESPACE_END /* sfb 07/21/99 */ U_CFUNC void locale_set_default(const char *id) { U_NAMESPACE_USE - locale_set_default_internal(id); + UErrorCode status = U_ZERO_ERROR; + locale_set_default_internal(id, status); } /* end */ @@ -232,13 +226,14 @@ U_CFUNC const char * locale_get_default(void) { U_NAMESPACE_USE - return Locale::getDefault().getName(); } U_NAMESPACE_BEGIN +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale) + /*Character separating the posix id fields*/ // '_' // In the platform codepage. @@ -246,16 +241,16 @@ U_NAMESPACE_BEGIN Locale::~Locale() { + if (baseName != fullName) { + uprv_free(baseName); + } + baseName = NULL; /*if fullName is on the heap, we free it*/ if (fullName != fullNameBuffer) { uprv_free(fullName); fullName = NULL; } - if (baseName && baseName != baseNameBuffer) { - uprv_free(baseName); - baseName = NULL; - } } Locale::Locale() @@ -288,9 +283,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; @@ -357,20 +350,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)); - togo = togo_heap; - } - else - { - togo = togo_stack; + // If togo_heap could not be created, initialize with default settings. + if (togo.resize(size+1) == NULL) { + init(NULL, FALSE); + } } togo[0] = 0; // Now, copy it back. - p = togo; + p = togo.getAlias(); if ( lsize != 0 ) { uprv_strcpy(p, newLanguage); @@ -414,11 +405,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); } } @@ -434,12 +421,11 @@ Locale &Locale::operator=(const Locale &other) return *this; } - if (&other == NULL) { - this->setToBogus(); - return *this; - } - /* Free our current storage */ + if (baseName != fullName) { + uprv_free(baseName); + } + baseName = NULL; if(fullName != fullNameBuffer) { uprv_free(fullName); fullName = fullNameBuffer; @@ -448,22 +434,20 @@ Locale &Locale::operator=(const Locale &other) /* Allocate the full name if necessary */ if(other.fullName != other.fullNameBuffer) { fullName = (char *)uprv_malloc(sizeof(char)*(uprv_strlen(other.fullName)+1)); + if (fullName == NULL) { + return *this; + } } /* Copy the full name */ uprv_strcpy(fullName, other.fullName); - /* baseName is the cached result of getBaseName. if 'other' has a - baseName and it fits in baseNameBuffer, then copy it. otherwise set - it to NULL, and let the user lazy-create it (in getBaseName) if they - want it. */ - if(baseName && baseName != baseNameBuffer) { - uprv_free(baseName); - } - baseName = NULL; - - if(other.baseName == other.baseNameBuffer) { - uprv_strcpy(baseNameBuffer, other.baseNameBuffer); - baseName = baseNameBuffer; + /* Copy the baseName if it differs from fullName. */ + if (other.baseName == other.fullName) { + baseName = fullName; + } else { + if (other.baseName) { + baseName = uprv_strdup(other.baseName); + } } /* Copy the language and country fields */ @@ -471,7 +455,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; @@ -488,21 +472,22 @@ 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) { fIsBogus = FALSE; /* Free our current storage */ + if (baseName != fullName) { + uprv_free(baseName); + } + baseName = NULL; if(fullName != fullNameBuffer) { uprv_free(fullName); fullName = fullNameBuffer; } - if(baseName && baseName != baseNameBuffer) { - uprv_free(baseName); - baseName = NULL; - } - // not a loop: // just an easy way to have a common error-exit // without goto and without another function @@ -568,40 +553,46 @@ 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); } + err = U_ZERO_ERROR; + initBaseName(err); + if (U_FAILURE(err)) { + break; + } + // successful end of init() return *this; } while(0); /*loop doesn't iterate*/ @@ -612,17 +603,56 @@ Locale& Locale::init(const char* localeID, UBool canonicalize) return *this; } +/* + * Set up the base name. + * If there are no key words, it's exactly the full name. + * If key words exist, it's the full name truncated at the '@' character. + * Need to set up both at init() and after setting a keyword. + */ +void +Locale::initBaseName(UErrorCode &status) { + if (U_FAILURE(status)) { + return; + } + U_ASSERT(baseName==NULL || baseName==fullName); + const char *atPtr = uprv_strchr(fullName, '@'); + const char *eqPtr = uprv_strchr(fullName, '='); + if (atPtr && eqPtr && atPtr < eqPtr) { + // Key words exist. + int32_t baseNameLength = (int32_t)(atPtr - fullName); + baseName = (char *)uprv_malloc(baseNameLength + 1); + if (baseName == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + uprv_strncpy(baseName, fullName, baseNameLength); + baseName[baseNameLength] = 0; + + // The original 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. + if (variantBegin > baseNameLength) { + variantBegin = baseNameLength; + } + } else { + baseName = fullName; + } +} + + int32_t Locale::hashCode() const { - UHashTok hashKey; - hashKey.pointer = fullName; - return uhash_hashChars(hashKey); + return ustr_hashCharsN(fullName, uprv_strlen(fullName)); } void Locale::setToBogus() { /* Free our current storage */ + if(baseName != fullName) { + uprv_free(baseName); + } + baseName = NULL; if(fullName != fullNameBuffer) { uprv_free(fullName); fullName = fullNameBuffer; @@ -637,21 +667,14 @@ Locale::setToBogus() { const Locale& U_EXPORT2 Locale::getDefault() { - const Locale *retLocale; - umtx_lock(NULL); - retLocale = gDefaultLocale; - umtx_unlock(NULL); - if (retLocale == NULL) { - locale_set_default_internal(NULL); - umtx_lock(NULL); - // Need a mutex in case some other thread set a new - // default inbetween when we set and when we get the new default. For - // processors with weak memory coherency, we might not otherwise see all - // of the newly created new default locale. - retLocale = gDefaultLocale; - umtx_unlock(NULL); + { + Mutex lock(&gDefaultLocaleMutex); + if (gDefaultLocale != NULL) { + return *gDefaultLocale; + } } - return *retLocale; + UErrorCode status = U_ZERO_ERROR; + return *locale_set_default_internal(NULL, status); } @@ -668,7 +691,7 @@ Locale::setDefault( const Locale& newLocale, * This is a convenient way to access the default locale caching mechanisms. */ const char *localeID = newLocale.getName(); - locale_set_default_internal(localeID); + locale_set_default_internal(localeID, status); } Locale U_EXPORT2 @@ -717,250 +740,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. - umtx_lock(NULL); - UBool needInit = availableLocaleList == 0; - umtx_unlock(NULL); - - 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(); @@ -977,6 +756,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) { @@ -1124,45 +909,8 @@ initialization and static destruction. Locale * Locale::getLocaleCache(void) { - umtx_lock(NULL); - UBool needInit = (gLocaleCache == NULL); - umtx_unlock(NULL); - - if (needInit) { - Locale *tLocaleCache = new Locale[(int)eMAX_LOCALES]; - if (tLocaleCache == NULL) { - return NULL; - } - tLocaleCache[eENGLISH] = Locale("en"); - tLocaleCache[eFRENCH] = Locale("fr"); - tLocaleCache[eGERMAN] = Locale("de"); - tLocaleCache[eITALIAN] = Locale("it"); - tLocaleCache[eJAPANESE] = Locale("ja"); - tLocaleCache[eKOREAN] = Locale("ko"); - tLocaleCache[eCHINESE] = Locale("zh"); - tLocaleCache[eFRANCE] = Locale("fr", "FR"); - tLocaleCache[eGERMANY] = Locale("de", "DE"); - tLocaleCache[eITALY] = Locale("it", "IT"); - tLocaleCache[eJAPAN] = Locale("ja", "JP"); - tLocaleCache[eKOREA] = Locale("ko", "KR"); - tLocaleCache[eCHINA] = Locale("zh", "CN"); - tLocaleCache[eTAIWAN] = Locale("zh", "TW"); - tLocaleCache[eUK] = Locale("en", "GB"); - tLocaleCache[eUS] = Locale("en", "US"); - tLocaleCache[eCANADA] = Locale("en", "CA"); - tLocaleCache[eCANADA_FRENCH] = Locale("fr", "CA"); - - umtx_lock(NULL); - if (gLocaleCache == NULL) { - gLocaleCache = tLocaleCache; - tLocaleCache = NULL; - ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup); - } - umtx_unlock(NULL); - if (tLocaleCache) { - delete [] tLocaleCache; // Fancy array delete will destruct each member. - } - } + UErrorCode status = U_ZERO_ERROR; + umtx_initOnce(gLocaleCacheInitOnce, locale_init, status); return gLocaleCache; } @@ -1198,9 +946,7 @@ public: } } - virtual ~KeywordEnumeration() { - uprv_free(keywords); - } + virtual ~KeywordEnumeration(); virtual StringEnumeration * clone() const { @@ -1250,6 +996,10 @@ public: const char KeywordEnumeration::fgClassID = '\0'; +KeywordEnumeration::~KeywordEnumeration() { + uprv_free(keywords); +} + StringEnumeration * Locale::createKeywords(UErrorCode &status) const { @@ -1278,24 +1028,20 @@ Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, U return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status); } -const char * -Locale::getBaseName() const +void +Locale::setKeywordValue(const char* keywordName, const char* keywordValue, UErrorCode &status) { - // lazy init - UErrorCode status = U_ZERO_ERROR; - // semantically const - if(baseName == 0) { - ((Locale *)this)->baseName = ((Locale *)this)->baseNameBuffer; - int32_t baseNameSize = uloc_getBaseName(fullName, baseName, ULOC_FULLNAME_CAPACITY, &status); - if(baseNameSize >= ULOC_FULLNAME_CAPACITY) { - ((Locale *)this)->baseName = (char *)uprv_malloc(sizeof(char) * baseNameSize + 1); - uloc_getBaseName(fullName, baseName, baseNameSize+1, &status); - } - baseName[baseNameSize] = 0; + uloc_setKeywordValue(keywordName, keywordValue, fullName, ULOC_FULLNAME_CAPACITY, &status); + if (U_SUCCESS(status) && baseName == fullName) { + // May have added the first keyword, meaning that the fullName is no longer also the baseName. + initBaseName(status); } - return baseName; } +const char * +Locale::getBaseName() const { + return baseName; +} //eof U_NAMESPACE_END