Home | History | Annotate | Download | only in common
      1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4  **********************************************************************
      5  *   Copyright (C) 1997-2016, International Business Machines
      6  *   Corporation and others.  All Rights Reserved.
      7  **********************************************************************
      8 *
      9 * File locid.cpp
     10 *
     11 * Created by: Richard Gillam
     12 *
     13 * Modification History:
     14 *
     15 *   Date        Name        Description
     16 *   02/11/97    aliu        Changed gLocPath to fgDataDirectory and added
     17 *                           methods to get and set it.
     18 *   04/02/97    aliu        Made operator!= inline; fixed return value
     19 *                           of getName().
     20 *   04/15/97    aliu        Cleanup for AIX/Win32.
     21 *   04/24/97    aliu        Numerous changes per code review.
     22 *   08/18/98    stephen     Changed getDisplayName()
     23 *                           Added SIMPLIFIED_CHINESE, TRADITIONAL_CHINESE
     24 *                           Added getISOCountries(), getISOLanguages(),
     25 *                           getLanguagesForCountry()
     26 *   03/16/99    bertrand    rehaul.
     27 *   07/21/99    stephen     Added U_CFUNC setDefault
     28 *   11/09/99    weiv        Added const char * getName() const;
     29 *   04/12/00    srl         removing unicodestring api's and cached hash code
     30 *   08/10/01    grhoten     Change the static Locales to accessor functions
     31 ******************************************************************************
     32 */
     33 
     34 
     35 #include "unicode/locid.h"
     36 #include "unicode/uloc.h"
     37 #include "putilimp.h"
     38 #include "mutex.h"
     39 #include "umutex.h"
     40 #include "uassert.h"
     41 #include "cmemory.h"
     42 #include "cstring.h"
     43 #include "uassert.h"
     44 #include "uhash.h"
     45 #include "ucln_cmn.h"
     46 #include "ustr_imp.h"
     47 #include "charstr.h"
     48 
     49 U_CDECL_BEGIN
     50 static UBool U_CALLCONV locale_cleanup(void);
     51 U_CDECL_END
     52 
     53 U_NAMESPACE_BEGIN
     54 
     55 static Locale   *gLocaleCache = NULL;
     56 static UInitOnce gLocaleCacheInitOnce = U_INITONCE_INITIALIZER;
     57 
     58 // gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale.
     59 static UMutex gDefaultLocaleMutex = U_MUTEX_INITIALIZER;
     60 static UHashtable *gDefaultLocalesHashT = NULL;
     61 static Locale *gDefaultLocale = NULL;
     62 
     63 /**
     64  * \def ULOC_STRING_LIMIT
     65  * strings beyond this value crash in CharString
     66  */
     67 #define ULOC_STRING_LIMIT 357913941
     68 
     69 U_NAMESPACE_END
     70 
     71 typedef enum ELocalePos {
     72     eENGLISH,
     73     eFRENCH,
     74     eGERMAN,
     75     eITALIAN,
     76     eJAPANESE,
     77     eKOREAN,
     78     eCHINESE,
     79 
     80     eFRANCE,
     81     eGERMANY,
     82     eITALY,
     83     eJAPAN,
     84     eKOREA,
     85     eCHINA,      /* Alias for PRC */
     86     eTAIWAN,
     87     eUK,
     88     eUS,
     89     eCANADA,
     90     eCANADA_FRENCH,
     91     eROOT,
     92 
     93 
     94     //eDEFAULT,
     95     eMAX_LOCALES
     96 } ELocalePos;
     97 
     98 U_CFUNC int32_t locale_getKeywords(const char *localeID,
     99             char prev,
    100             char *keywords, int32_t keywordCapacity,
    101             char *values, int32_t valuesCapacity, int32_t *valLen,
    102             UBool valuesToo,
    103             UErrorCode *status);
    104 
    105 U_CDECL_BEGIN
    106 //
    107 // Deleter function for Locales owned by the default Locale hash table/
    108 //
    109 static void U_CALLCONV
    110 deleteLocale(void *obj) {
    111     delete (icu::Locale *) obj;
    112 }
    113 
    114 static UBool U_CALLCONV locale_cleanup(void)
    115 {
    116     U_NAMESPACE_USE
    117 
    118     delete [] gLocaleCache;
    119     gLocaleCache = NULL;
    120     gLocaleCacheInitOnce.reset();
    121 
    122     if (gDefaultLocalesHashT) {
    123         uhash_close(gDefaultLocalesHashT);   // Automatically deletes all elements, using deleter func.
    124         gDefaultLocalesHashT = NULL;
    125     }
    126     gDefaultLocale = NULL;
    127     return TRUE;
    128 }
    129 
    130 
    131 static void U_CALLCONV locale_init(UErrorCode &status) {
    132     U_NAMESPACE_USE
    133 
    134     U_ASSERT(gLocaleCache == NULL);
    135     gLocaleCache = new Locale[(int)eMAX_LOCALES];
    136     if (gLocaleCache == NULL) {
    137         status = U_MEMORY_ALLOCATION_ERROR;
    138         return;
    139     }
    140     ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
    141     gLocaleCache[eROOT]          = Locale("");
    142     gLocaleCache[eENGLISH]       = Locale("en");
    143     gLocaleCache[eFRENCH]        = Locale("fr");
    144     gLocaleCache[eGERMAN]        = Locale("de");
    145     gLocaleCache[eITALIAN]       = Locale("it");
    146     gLocaleCache[eJAPANESE]      = Locale("ja");
    147     gLocaleCache[eKOREAN]        = Locale("ko");
    148     gLocaleCache[eCHINESE]       = Locale("zh");
    149     gLocaleCache[eFRANCE]        = Locale("fr", "FR");
    150     gLocaleCache[eGERMANY]       = Locale("de", "DE");
    151     gLocaleCache[eITALY]         = Locale("it", "IT");
    152     gLocaleCache[eJAPAN]         = Locale("ja", "JP");
    153     gLocaleCache[eKOREA]         = Locale("ko", "KR");
    154     gLocaleCache[eCHINA]         = Locale("zh", "CN");
    155     gLocaleCache[eTAIWAN]        = Locale("zh", "TW");
    156     gLocaleCache[eUK]            = Locale("en", "GB");
    157     gLocaleCache[eUS]            = Locale("en", "US");
    158     gLocaleCache[eCANADA]        = Locale("en", "CA");
    159     gLocaleCache[eCANADA_FRENCH] = Locale("fr", "CA");
    160 }
    161 
    162 U_CDECL_END
    163 
    164 U_NAMESPACE_BEGIN
    165 
    166 Locale *locale_set_default_internal(const char *id, UErrorCode& status) {
    167     // Synchronize this entire function.
    168     Mutex lock(&gDefaultLocaleMutex);
    169 
    170     UBool canonicalize = FALSE;
    171 
    172     // If given a NULL string for the locale id, grab the default
    173     //   name from the system.
    174     //   (Different from most other locale APIs, where a null name means use
    175     //    the current ICU default locale.)
    176     if (id == NULL) {
    177         id = uprv_getDefaultLocaleID();   // This function not thread safe? TODO: verify.
    178         canonicalize = TRUE; // always canonicalize host ID
    179     }
    180 
    181     char localeNameBuf[512];
    182 
    183     if (canonicalize) {
    184         uloc_canonicalize(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
    185     } else {
    186         uloc_getName(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
    187     }
    188     localeNameBuf[sizeof(localeNameBuf)-1] = 0;  // Force null termination in event of
    189                                                  //   a long name filling the buffer.
    190                                                  //   (long names are truncated.)
    191                                                  //
    192     if (U_FAILURE(status)) {
    193         return gDefaultLocale;
    194     }
    195 
    196     if (gDefaultLocalesHashT == NULL) {
    197         gDefaultLocalesHashT = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
    198         if (U_FAILURE(status)) {
    199             return gDefaultLocale;
    200         }
    201         uhash_setValueDeleter(gDefaultLocalesHashT, deleteLocale);
    202         ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
    203     }
    204 
    205     Locale *newDefault = (Locale *)uhash_get(gDefaultLocalesHashT, localeNameBuf);
    206     if (newDefault == NULL) {
    207         newDefault = new Locale(Locale::eBOGUS);
    208         if (newDefault == NULL) {
    209             status = U_MEMORY_ALLOCATION_ERROR;
    210             return gDefaultLocale;
    211         }
    212         newDefault->init(localeNameBuf, FALSE);
    213         uhash_put(gDefaultLocalesHashT, (char*) newDefault->getName(), newDefault, &status);
    214         if (U_FAILURE(status)) {
    215             return gDefaultLocale;
    216         }
    217     }
    218     gDefaultLocale = newDefault;
    219     return gDefaultLocale;
    220 }
    221 
    222 U_NAMESPACE_END
    223 
    224 /* sfb 07/21/99 */
    225 U_CFUNC void
    226 locale_set_default(const char *id)
    227 {
    228     U_NAMESPACE_USE
    229     UErrorCode status = U_ZERO_ERROR;
    230     locale_set_default_internal(id, status);
    231 }
    232 /* end */
    233 
    234 U_CFUNC const char *
    235 locale_get_default(void)
    236 {
    237     U_NAMESPACE_USE
    238     return Locale::getDefault().getName();
    239 }
    240 
    241 
    242 U_NAMESPACE_BEGIN
    243 
    244 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)
    245 
    246 /*Character separating the posix id fields*/
    247 // '_'
    248 // In the platform codepage.
    249 #define SEP_CHAR '_'
    250 
    251 Locale::~Locale()
    252 {
    253     if (baseName != fullName) {
    254         uprv_free(baseName);
    255     }
    256     baseName = NULL;
    257     /*if fullName is on the heap, we free it*/
    258     if (fullName != fullNameBuffer)
    259     {
    260         uprv_free(fullName);
    261         fullName = NULL;
    262     }
    263 }
    264 
    265 Locale::Locale()
    266     : UObject(), fullName(fullNameBuffer), baseName(NULL)
    267 {
    268     init(NULL, FALSE);
    269 }
    270 
    271 /*
    272  * Internal constructor to allow construction of a locale object with
    273  *   NO side effects.   (Default constructor tries to get
    274  *   the default locale.)
    275  */
    276 Locale::Locale(Locale::ELocaleType)
    277     : UObject(), fullName(fullNameBuffer), baseName(NULL)
    278 {
    279     setToBogus();
    280 }
    281 
    282 
    283 Locale::Locale( const   char * newLanguage,
    284                 const   char * newCountry,
    285                 const   char * newVariant,
    286                 const   char * newKeywords)
    287     : UObject(), fullName(fullNameBuffer), baseName(NULL)
    288 {
    289     if( (newLanguage==NULL) && (newCountry == NULL) && (newVariant == NULL) )
    290     {
    291         init(NULL, FALSE); /* shortcut */
    292     }
    293     else
    294     {
    295         UErrorCode status = U_ZERO_ERROR;
    296         int32_t size = 0;
    297         int32_t lsize = 0;
    298         int32_t csize = 0;
    299         int32_t vsize = 0;
    300         int32_t ksize = 0;
    301 
    302         // Calculate the size of the resulting string.
    303 
    304         // Language
    305         if ( newLanguage != NULL )
    306         {
    307             lsize = (int32_t)uprv_strlen(newLanguage);
    308             if ( lsize < 0 || lsize > ULOC_STRING_LIMIT ) { // int32 wrap
    309                 setToBogus();
    310                 return;
    311             }
    312             size = lsize;
    313         }
    314 
    315         CharString togo(newLanguage, lsize, status); // start with newLanguage
    316 
    317         // _Country
    318         if ( newCountry != NULL )
    319         {
    320             csize = (int32_t)uprv_strlen(newCountry);
    321             if ( csize < 0 || csize > ULOC_STRING_LIMIT ) { // int32 wrap
    322                 setToBogus();
    323                 return;
    324             }
    325             size += csize;
    326         }
    327 
    328         // _Variant
    329         if ( newVariant != NULL )
    330         {
    331             // remove leading _'s
    332             while(newVariant[0] == SEP_CHAR)
    333             {
    334                 newVariant++;
    335             }
    336 
    337             // remove trailing _'s
    338             vsize = (int32_t)uprv_strlen(newVariant);
    339             if ( vsize < 0 || vsize > ULOC_STRING_LIMIT ) { // int32 wrap
    340                 setToBogus();
    341                 return;
    342             }
    343             while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) )
    344             {
    345                 vsize--;
    346             }
    347         }
    348 
    349         if( vsize > 0 )
    350         {
    351             size += vsize;
    352         }
    353 
    354         // Separator rules:
    355         if ( vsize > 0 )
    356         {
    357             size += 2;  // at least: __v
    358         }
    359         else if ( csize > 0 )
    360         {
    361             size += 1;  // at least: _v
    362         }
    363 
    364         if ( newKeywords != NULL)
    365         {
    366             ksize = (int32_t)uprv_strlen(newKeywords);
    367             if ( ksize < 0 || ksize > ULOC_STRING_LIMIT ) {
    368               setToBogus();
    369               return;
    370             }
    371             size += ksize + 1;
    372         }
    373 
    374         //  NOW we have the full locale string..
    375         // Now, copy it back.
    376 
    377         // newLanguage is already copied
    378 
    379         if ( ( vsize != 0 ) || (csize != 0) )  // at least:  __v
    380         {                                      //            ^
    381             togo.append(SEP_CHAR, status);
    382         }
    383 
    384         if ( csize != 0 )
    385         {
    386             togo.append(newCountry, status);
    387         }
    388 
    389         if ( vsize != 0)
    390         {
    391             togo.append(SEP_CHAR, status)
    392                 .append(newVariant, vsize, status);
    393         }
    394 
    395         if ( ksize != 0)
    396         {
    397             if (uprv_strchr(newKeywords, '=')) {
    398                 togo.append('@', status); /* keyword parsing */
    399             }
    400             else {
    401                 togo.append('_', status); /* Variant parsing with a script */
    402                 if ( vsize == 0) {
    403                     togo.append('_', status); /* No country found */
    404                 }
    405             }
    406             togo.append(newKeywords, status);
    407         }
    408 
    409         if (U_FAILURE(status)) {
    410             // Something went wrong with appending, etc.
    411             setToBogus();
    412             return;
    413         }
    414         // Parse it, because for example 'language' might really be a complete
    415         // string.
    416         init(togo.data(), FALSE);
    417     }
    418 }
    419 
    420 Locale::Locale(const Locale &other)
    421     : UObject(other), fullName(fullNameBuffer), baseName(NULL)
    422 {
    423     *this = other;
    424 }
    425 
    426 Locale &Locale::operator=(const Locale &other)
    427 {
    428     if (this == &other) {
    429         return *this;
    430     }
    431 
    432     /* Free our current storage */
    433     if (baseName != fullName) {
    434         uprv_free(baseName);
    435     }
    436     baseName = NULL;
    437     if(fullName != fullNameBuffer) {
    438         uprv_free(fullName);
    439         fullName = fullNameBuffer;
    440     }
    441 
    442     /* Allocate the full name if necessary */
    443     if(other.fullName != other.fullNameBuffer) {
    444         fullName = (char *)uprv_malloc(sizeof(char)*(uprv_strlen(other.fullName)+1));
    445         if (fullName == NULL) {
    446             return *this;
    447         }
    448     }
    449     /* Copy the full name */
    450     uprv_strcpy(fullName, other.fullName);
    451 
    452     /* Copy the baseName if it differs from fullName. */
    453     if (other.baseName == other.fullName) {
    454         baseName = fullName;
    455     } else {
    456         if (other.baseName) {
    457             baseName = uprv_strdup(other.baseName);
    458         }
    459     }
    460 
    461     /* Copy the language and country fields */
    462     uprv_strcpy(language, other.language);
    463     uprv_strcpy(script, other.script);
    464     uprv_strcpy(country, other.country);
    465 
    466     /* The variantBegin is an offset, just copy it */
    467     variantBegin = other.variantBegin;
    468     fIsBogus = other.fIsBogus;
    469     return *this;
    470 }
    471 
    472 Locale *
    473 Locale::clone() const {
    474     return new Locale(*this);
    475 }
    476 
    477 UBool
    478 Locale::operator==( const   Locale& other) const
    479 {
    480     return (uprv_strcmp(other.fullName, fullName) == 0);
    481 }
    482 
    483 #define ISASCIIALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
    484 
    485 /*This function initializes a Locale from a C locale ID*/
    486 Locale& Locale::init(const char* localeID, UBool canonicalize)
    487 {
    488     fIsBogus = FALSE;
    489     /* Free our current storage */
    490     if (baseName != fullName) {
    491         uprv_free(baseName);
    492     }
    493     baseName = NULL;
    494     if(fullName != fullNameBuffer) {
    495         uprv_free(fullName);
    496         fullName = fullNameBuffer;
    497     }
    498 
    499     // not a loop:
    500     // just an easy way to have a common error-exit
    501     // without goto and without another function
    502     do {
    503         char *separator;
    504         char *field[5] = {0};
    505         int32_t fieldLen[5] = {0};
    506         int32_t fieldIdx;
    507         int32_t variantField;
    508         int32_t length;
    509         UErrorCode err;
    510 
    511         if(localeID == NULL) {
    512             // not an error, just set the default locale
    513             return *this = getDefault();
    514         }
    515 
    516         /* preset all fields to empty */
    517         language[0] = script[0] = country[0] = 0;
    518 
    519         // "canonicalize" the locale ID to ICU/Java format
    520         err = U_ZERO_ERROR;
    521         length = canonicalize ?
    522             uloc_canonicalize(localeID, fullName, sizeof(fullNameBuffer), &err) :
    523             uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err);
    524 
    525         if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) {
    526             /*Go to heap for the fullName if necessary*/
    527             fullName = (char *)uprv_malloc(sizeof(char)*(length + 1));
    528             if(fullName == 0) {
    529                 fullName = fullNameBuffer;
    530                 break; // error: out of memory
    531             }
    532             err = U_ZERO_ERROR;
    533             length = canonicalize ?
    534                 uloc_canonicalize(localeID, fullName, length+1, &err) :
    535                 uloc_getName(localeID, fullName, length+1, &err);
    536         }
    537         if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
    538             /* should never occur */
    539             break;
    540         }
    541 
    542         variantBegin = length;
    543 
    544         /* after uloc_getName/canonicalize() we know that only '_' are separators */
    545         separator = field[0] = fullName;
    546         fieldIdx = 1;
    547         while ((separator = uprv_strchr(field[fieldIdx-1], SEP_CHAR)) && fieldIdx < UPRV_LENGTHOF(field)-1) {
    548             field[fieldIdx] = separator + 1;
    549             fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
    550             fieldIdx++;
    551         }
    552         // variant may contain @foo or .foo POSIX cruft; remove it
    553         separator = uprv_strchr(field[fieldIdx-1], '@');
    554         char* sep2 = uprv_strchr(field[fieldIdx-1], '.');
    555         if (separator!=NULL || sep2!=NULL) {
    556             if (separator==NULL || (sep2!=NULL && separator > sep2)) {
    557                 separator = sep2;
    558             }
    559             fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
    560         } else {
    561             fieldLen[fieldIdx-1] = length - (int32_t)(field[fieldIdx-1] - fullName);
    562         }
    563 
    564         if (fieldLen[0] >= (int32_t)(sizeof(language)))
    565         {
    566             break; // error: the language field is too long
    567         }
    568 
    569         variantField = 1; /* Usually the 2nd one, except when a script or country is also used. */
    570         if (fieldLen[0] > 0) {
    571             /* We have a language */
    572             uprv_memcpy(language, fullName, fieldLen[0]);
    573             language[fieldLen[0]] = 0;
    574         }
    575         if (fieldLen[1] == 4 && ISASCIIALPHA(field[1][0]) &&
    576                 ISASCIIALPHA(field[1][1]) && ISASCIIALPHA(field[1][2]) &&
    577                 ISASCIIALPHA(field[1][3])) {
    578             /* We have at least a script */
    579             uprv_memcpy(script, field[1], fieldLen[1]);
    580             script[fieldLen[1]] = 0;
    581             variantField++;
    582         }
    583 
    584         if (fieldLen[variantField] == 2 || fieldLen[variantField] == 3) {
    585             /* We have a country */
    586             uprv_memcpy(country, field[variantField], fieldLen[variantField]);
    587             country[fieldLen[variantField]] = 0;
    588             variantField++;
    589         } else if (fieldLen[variantField] == 0) {
    590             variantField++; /* script or country empty but variant in next field (i.e. en__POSIX) */
    591         }
    592 
    593         if (fieldLen[variantField] > 0) {
    594             /* We have a variant */
    595             variantBegin = (int32_t)(field[variantField] - fullName);
    596         }
    597 
    598         err = U_ZERO_ERROR;
    599         initBaseName(err);
    600         if (U_FAILURE(err)) {
    601             break;
    602         }
    603 
    604         // successful end of init()
    605         return *this;
    606     } while(0); /*loop doesn't iterate*/
    607 
    608     // when an error occurs, then set this object to "bogus" (there is no UErrorCode here)
    609     setToBogus();
    610 
    611     return *this;
    612 }
    613 
    614 /*
    615  * Set up the base name.
    616  * If there are no key words, it's exactly the full name.
    617  * If key words exist, it's the full name truncated at the '@' character.
    618  * Need to set up both at init() and after setting a keyword.
    619  */
    620 void
    621 Locale::initBaseName(UErrorCode &status) {
    622     if (U_FAILURE(status)) {
    623         return;
    624     }
    625     U_ASSERT(baseName==NULL || baseName==fullName);
    626     const char *atPtr = uprv_strchr(fullName, '@');
    627     const char *eqPtr = uprv_strchr(fullName, '=');
    628     if (atPtr && eqPtr && atPtr < eqPtr) {
    629         // Key words exist.
    630         int32_t baseNameLength = (int32_t)(atPtr - fullName);
    631         baseName = (char *)uprv_malloc(baseNameLength + 1);
    632         if (baseName == NULL) {
    633             status = U_MEMORY_ALLOCATION_ERROR;
    634             return;
    635         }
    636         uprv_strncpy(baseName, fullName, baseNameLength);
    637         baseName[baseNameLength] = 0;
    638 
    639         // The original computation of variantBegin leaves it equal to the length
    640         // of fullName if there is no variant.  It should instead be
    641         // the length of the baseName.
    642         if (variantBegin > baseNameLength) {
    643             variantBegin = baseNameLength;
    644         }
    645     } else {
    646         baseName = fullName;
    647     }
    648 }
    649 
    650 
    651 int32_t
    652 Locale::hashCode() const
    653 {
    654     return ustr_hashCharsN(fullName, uprv_strlen(fullName));
    655 }
    656 
    657 void
    658 Locale::setToBogus() {
    659     /* Free our current storage */
    660     if(baseName != fullName) {
    661         uprv_free(baseName);
    662     }
    663     baseName = NULL;
    664     if(fullName != fullNameBuffer) {
    665         uprv_free(fullName);
    666         fullName = fullNameBuffer;
    667     }
    668     *fullNameBuffer = 0;
    669     *language = 0;
    670     *script = 0;
    671     *country = 0;
    672     fIsBogus = TRUE;
    673     variantBegin = 0;
    674 }
    675 
    676 const Locale& U_EXPORT2
    677 Locale::getDefault()
    678 {
    679     {
    680         Mutex lock(&gDefaultLocaleMutex);
    681         if (gDefaultLocale != NULL) {
    682             return *gDefaultLocale;
    683         }
    684     }
    685     UErrorCode status = U_ZERO_ERROR;
    686     return *locale_set_default_internal(NULL, status);
    687 }
    688 
    689 
    690 
    691 void U_EXPORT2
    692 Locale::setDefault( const   Locale&     newLocale,
    693                             UErrorCode&  status)
    694 {
    695     if (U_FAILURE(status)) {
    696         return;
    697     }
    698 
    699     /* Set the default from the full name string of the supplied locale.
    700      * This is a convenient way to access the default locale caching mechanisms.
    701      */
    702     const char *localeID = newLocale.getName();
    703     locale_set_default_internal(localeID, status);
    704 }
    705 
    706 Locale U_EXPORT2
    707 Locale::createFromName (const char *name)
    708 {
    709     if (name) {
    710         Locale l("");
    711         l.init(name, FALSE);
    712         return l;
    713     }
    714     else {
    715         return getDefault();
    716     }
    717 }
    718 
    719 Locale U_EXPORT2
    720 Locale::createCanonical(const char* name) {
    721     Locale loc("");
    722     loc.init(name, TRUE);
    723     return loc;
    724 }
    725 
    726 const char *
    727 Locale::getISO3Language() const
    728 {
    729     return uloc_getISO3Language(fullName);
    730 }
    731 
    732 
    733 const char *
    734 Locale::getISO3Country() const
    735 {
    736     return uloc_getISO3Country(fullName);
    737 }
    738 
    739 /**
    740  * Return the LCID value as specified in the "LocaleID" resource for this
    741  * locale.  The LocaleID must be expressed as a hexadecimal number, from
    742  * one to four digits.  If the LocaleID resource is not present, or is
    743  * in an incorrect format, 0 is returned.  The LocaleID is for use in
    744  * Windows (it is an LCID), but is available on all platforms.
    745  */
    746 uint32_t
    747 Locale::getLCID() const
    748 {
    749     return uloc_getLCID(fullName);
    750 }
    751 
    752 const char* const* U_EXPORT2 Locale::getISOCountries()
    753 {
    754     return uloc_getISOCountries();
    755 }
    756 
    757 const char* const* U_EXPORT2 Locale::getISOLanguages()
    758 {
    759     return uloc_getISOLanguages();
    760 }
    761 
    762 // Set the locale's data based on a posix id.
    763 void Locale::setFromPOSIXID(const char *posixID)
    764 {
    765     init(posixID, TRUE);
    766 }
    767 
    768 const Locale & U_EXPORT2
    769 Locale::getRoot(void)
    770 {
    771     return getLocale(eROOT);
    772 }
    773 
    774 const Locale & U_EXPORT2
    775 Locale::getEnglish(void)
    776 {
    777     return getLocale(eENGLISH);
    778 }
    779 
    780 const Locale & U_EXPORT2
    781 Locale::getFrench(void)
    782 {
    783     return getLocale(eFRENCH);
    784 }
    785 
    786 const Locale & U_EXPORT2
    787 Locale::getGerman(void)
    788 {
    789     return getLocale(eGERMAN);
    790 }
    791 
    792 const Locale & U_EXPORT2
    793 Locale::getItalian(void)
    794 {
    795     return getLocale(eITALIAN);
    796 }
    797 
    798 const Locale & U_EXPORT2
    799 Locale::getJapanese(void)
    800 {
    801     return getLocale(eJAPANESE);
    802 }
    803 
    804 const Locale & U_EXPORT2
    805 Locale::getKorean(void)
    806 {
    807     return getLocale(eKOREAN);
    808 }
    809 
    810 const Locale & U_EXPORT2
    811 Locale::getChinese(void)
    812 {
    813     return getLocale(eCHINESE);
    814 }
    815 
    816 const Locale & U_EXPORT2
    817 Locale::getSimplifiedChinese(void)
    818 {
    819     return getLocale(eCHINA);
    820 }
    821 
    822 const Locale & U_EXPORT2
    823 Locale::getTraditionalChinese(void)
    824 {
    825     return getLocale(eTAIWAN);
    826 }
    827 
    828 
    829 const Locale & U_EXPORT2
    830 Locale::getFrance(void)
    831 {
    832     return getLocale(eFRANCE);
    833 }
    834 
    835 const Locale & U_EXPORT2
    836 Locale::getGermany(void)
    837 {
    838     return getLocale(eGERMANY);
    839 }
    840 
    841 const Locale & U_EXPORT2
    842 Locale::getItaly(void)
    843 {
    844     return getLocale(eITALY);
    845 }
    846 
    847 const Locale & U_EXPORT2
    848 Locale::getJapan(void)
    849 {
    850     return getLocale(eJAPAN);
    851 }
    852 
    853 const Locale & U_EXPORT2
    854 Locale::getKorea(void)
    855 {
    856     return getLocale(eKOREA);
    857 }
    858 
    859 const Locale & U_EXPORT2
    860 Locale::getChina(void)
    861 {
    862     return getLocale(eCHINA);
    863 }
    864 
    865 const Locale & U_EXPORT2
    866 Locale::getPRC(void)
    867 {
    868     return getLocale(eCHINA);
    869 }
    870 
    871 const Locale & U_EXPORT2
    872 Locale::getTaiwan(void)
    873 {
    874     return getLocale(eTAIWAN);
    875 }
    876 
    877 const Locale & U_EXPORT2
    878 Locale::getUK(void)
    879 {
    880     return getLocale(eUK);
    881 }
    882 
    883 const Locale & U_EXPORT2
    884 Locale::getUS(void)
    885 {
    886     return getLocale(eUS);
    887 }
    888 
    889 const Locale & U_EXPORT2
    890 Locale::getCanada(void)
    891 {
    892     return getLocale(eCANADA);
    893 }
    894 
    895 const Locale & U_EXPORT2
    896 Locale::getCanadaFrench(void)
    897 {
    898     return getLocale(eCANADA_FRENCH);
    899 }
    900 
    901 const Locale &
    902 Locale::getLocale(int locid)
    903 {
    904     Locale *localeCache = getLocaleCache();
    905     U_ASSERT((locid < eMAX_LOCALES)&&(locid>=0));
    906     if (localeCache == NULL) {
    907         // Failure allocating the locale cache.
    908         //   The best we can do is return a NULL reference.
    909         locid = 0;
    910     }
    911     return localeCache[locid]; /*operating on NULL*/
    912 }
    913 
    914 /*
    915 This function is defined this way in order to get around static
    916 initialization and static destruction.
    917  */
    918 Locale *
    919 Locale::getLocaleCache(void)
    920 {
    921     UErrorCode status = U_ZERO_ERROR;
    922     umtx_initOnce(gLocaleCacheInitOnce, locale_init, status);
    923     return gLocaleCache;
    924 }
    925 
    926 class KeywordEnumeration : public StringEnumeration {
    927 private:
    928     char *keywords;
    929     char *current;
    930     int32_t length;
    931     UnicodeString currUSKey;
    932     static const char fgClassID;/* Warning this is used beyond the typical RTTI usage. */
    933 
    934 public:
    935     static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; }
    936     virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); }
    937 public:
    938     KeywordEnumeration(const char *keys, int32_t keywordLen, int32_t currentIndex, UErrorCode &status)
    939         : keywords((char *)&fgClassID), current((char *)&fgClassID), length(0) {
    940         if(U_SUCCESS(status) && keywordLen != 0) {
    941             if(keys == NULL || keywordLen < 0) {
    942                 status = U_ILLEGAL_ARGUMENT_ERROR;
    943             } else {
    944                 keywords = (char *)uprv_malloc(keywordLen+1);
    945                 if (keywords == NULL) {
    946                     status = U_MEMORY_ALLOCATION_ERROR;
    947                 }
    948                 else {
    949                     uprv_memcpy(keywords, keys, keywordLen);
    950                     keywords[keywordLen] = 0;
    951                     current = keywords + currentIndex;
    952                     length = keywordLen;
    953                 }
    954             }
    955         }
    956     }
    957 
    958     virtual ~KeywordEnumeration();
    959 
    960     virtual StringEnumeration * clone() const
    961     {
    962         UErrorCode status = U_ZERO_ERROR;
    963         return new KeywordEnumeration(keywords, length, (int32_t)(current - keywords), status);
    964     }
    965 
    966     virtual int32_t count(UErrorCode &/*status*/) const {
    967         char *kw = keywords;
    968         int32_t result = 0;
    969         while(*kw) {
    970             result++;
    971             kw += uprv_strlen(kw)+1;
    972         }
    973         return result;
    974     }
    975 
    976     virtual const char* next(int32_t* resultLength, UErrorCode& status) {
    977         const char* result;
    978         int32_t len;
    979         if(U_SUCCESS(status) && *current != 0) {
    980             result = current;
    981             len = (int32_t)uprv_strlen(current);
    982             current += len+1;
    983             if(resultLength != NULL) {
    984                 *resultLength = len;
    985             }
    986         } else {
    987             if(resultLength != NULL) {
    988                 *resultLength = 0;
    989             }
    990             result = NULL;
    991         }
    992         return result;
    993     }
    994 
    995     virtual const UnicodeString* snext(UErrorCode& status) {
    996         int32_t resultLength = 0;
    997         const char *s = next(&resultLength, status);
    998         return setChars(s, resultLength, status);
    999     }
   1000 
   1001     virtual void reset(UErrorCode& /*status*/) {
   1002         current = keywords;
   1003     }
   1004 };
   1005 
   1006 const char KeywordEnumeration::fgClassID = '\0';
   1007 
   1008 KeywordEnumeration::~KeywordEnumeration() {
   1009     uprv_free(keywords);
   1010 }
   1011 
   1012 StringEnumeration *
   1013 Locale::createKeywords(UErrorCode &status) const
   1014 {
   1015     char keywords[256];
   1016     int32_t keywordCapacity = 256;
   1017     StringEnumeration *result = NULL;
   1018 
   1019     const char* variantStart = uprv_strchr(fullName, '@');
   1020     const char* assignment = uprv_strchr(fullName, '=');
   1021     if(variantStart) {
   1022         if(assignment > variantStart) {
   1023             int32_t keyLen = locale_getKeywords(variantStart+1, '@', keywords, keywordCapacity, NULL, 0, NULL, FALSE, &status);
   1024             if(keyLen) {
   1025                 result = new KeywordEnumeration(keywords, keyLen, 0, status);
   1026             }
   1027         } else {
   1028             status = U_INVALID_FORMAT_ERROR;
   1029         }
   1030     }
   1031     return result;
   1032 }
   1033 
   1034 int32_t
   1035 Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, UErrorCode &status) const
   1036 {
   1037     return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status);
   1038 }
   1039 
   1040 void
   1041 Locale::setKeywordValue(const char* keywordName, const char* keywordValue, UErrorCode &status)
   1042 {
   1043     uloc_setKeywordValue(keywordName, keywordValue, fullName, ULOC_FULLNAME_CAPACITY, &status);
   1044     if (U_SUCCESS(status) && baseName == fullName) {
   1045         // May have added the first keyword, meaning that the fullName is no longer also the baseName.
   1046         initBaseName(status);
   1047     }
   1048 }
   1049 
   1050 const char *
   1051 Locale::getBaseName() const {
   1052     return baseName;
   1053 }
   1054 
   1055 //eof
   1056 U_NAMESPACE_END
   1057