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