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