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