intl/icu/source/common/locid.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     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 */
    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"
    45 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
    47 U_CDECL_BEGIN
    48 static UBool U_CALLCONV locale_cleanup(void);
    49 U_CDECL_END
    51 U_NAMESPACE_BEGIN
    53 static Locale *gLocaleCache = NULL;
    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;
    60 U_NAMESPACE_END
    62 typedef enum ELocalePos {
    63     eENGLISH,
    64     eFRENCH,
    65     eGERMAN,
    66     eITALIAN,
    67     eJAPANESE,
    68     eKOREAN,
    69     eCHINESE,
    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,
    85     //eDEFAULT,
    86     eMAX_LOCALES
    87 } ELocalePos;
    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);
    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 }
   105 static UBool U_CALLCONV locale_cleanup(void)
   106 {
   107     U_NAMESPACE_USE
   109     if (gLocaleCache) {
   110         delete [] gLocaleCache;
   111         gLocaleCache = NULL;
   112     }
   114     if (gDefaultLocalesHashT) {
   115         uhash_close(gDefaultLocalesHashT);   // Automatically deletes all elements, using deleter func.
   116         gDefaultLocalesHashT = NULL;
   117         gDefaultLocale = NULL;
   118     }
   120     return TRUE;
   121 }
   122 U_CDECL_END
   124 U_NAMESPACE_BEGIN
   126 Locale *locale_set_default_internal(const char *id, UErrorCode& status) {
   127     // Synchronize this entire function.
   128     Mutex lock(&gDefaultLocaleMutex);
   130     UBool canonicalize = FALSE;
   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     }
   141     char localeNameBuf[512];
   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     }
   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     }
   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 }
   182 U_NAMESPACE_END
   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 */
   194 U_CFUNC const char *
   195 locale_get_default(void)
   196 {
   197     U_NAMESPACE_USE
   198     return Locale::getDefault().getName();
   199 }
   202 U_NAMESPACE_BEGIN
   204 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)
   206 /*Character separating the posix id fields*/
   207 // '_'
   208 // In the platform codepage.
   209 #define SEP_CHAR '_'
   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 }
   225 Locale::Locale()
   226     : UObject(), fullName(fullNameBuffer), baseName(NULL)
   227 {
   228     init(NULL, FALSE);
   229 }
   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 }
   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;
   263         // Calculate the size of the resulting string.
   265         // Language
   266         if ( newLanguage != NULL )
   267         {
   268             lsize = (int32_t)uprv_strlen(newLanguage);
   269             size = lsize;
   270         }
   272         // _Country
   273         if ( newCountry != NULL )
   274         {
   275             csize = (int32_t)uprv_strlen(newCountry);
   276             size += csize;
   277         }
   279         // _Variant
   280         if ( newVariant != NULL )
   281         {
   282             // remove leading _'s
   283             while(newVariant[0] == SEP_CHAR)
   284             {
   285                 newVariant++;
   286             }
   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         }
   296         if( vsize > 0 )
   297         {
   298             size += vsize;
   299         }
   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         }
   311         if ( newKeywords != NULL)
   312         {
   313             ksize = (int32_t)uprv_strlen(newKeywords);
   314             size += ksize + 1;
   315         }
   318         //  NOW we have the full locale string..
   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         }
   330         togo[0] = 0;
   332         // Now, copy it back.
   333         p = togo.getAlias();
   334         if ( lsize != 0 )
   335         {
   336             uprv_strcpy(p, newLanguage);
   337             p += lsize;
   338         }
   340         if ( ( vsize != 0 ) || (csize != 0) )  // at least:  __v
   341         {                                      //            ^
   342             *p++ = SEP_CHAR;
   343         }
   345         if ( csize != 0 )
   346         {
   347             uprv_strcpy(p, newCountry);
   348             p += csize;
   349         }
   351         if ( vsize != 0)
   352         {
   353             *p++ = SEP_CHAR; // at least: __v
   355             uprv_strncpy(p, newVariant, vsize);  // Must use strncpy because
   356             p += vsize;                          // of trimming (above).
   357             *p = 0; // terminate
   358         }
   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         }
   375         // Parse it, because for example 'language' might really be a complete
   376         // string.
   377         init(togo.getAlias(), FALSE);
   378     }
   379 }
   381 Locale::Locale(const Locale &other)
   382     : UObject(other), fullName(fullNameBuffer), baseName(NULL)
   383 {
   384     *this = other;
   385 }
   387 Locale &Locale::operator=(const Locale &other)
   388 {
   389     if (this == &other) {
   390         return *this;
   391     }
   393     if (&other == NULL) {
   394         this->setToBogus();
   395         return *this;
   396     }
   398     /* Free our current storage */
   399     if(fullName != fullNameBuffer) {
   400         uprv_free(fullName);
   401         fullName = fullNameBuffer;
   402     }
   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);
   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;
   423     if(other.baseName == other.baseNameBuffer) {
   424         uprv_strcpy(baseNameBuffer, other.baseNameBuffer);
   425         baseName = baseNameBuffer;
   426     }
   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);
   433     /* The variantBegin is an offset, just copy it */
   434     variantBegin = other.variantBegin;
   435     fIsBogus = other.fIsBogus;
   436     return *this;
   437 }
   439 Locale *
   440 Locale::clone() const {
   441     return new Locale(*this);
   442 }
   444 UBool
   445 Locale::operator==( const   Locale& other) const
   446 {
   447     return (uprv_strcmp(other.fullName, fullName) == 0);
   448 }
   450 #define ISASCIIALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
   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     }
   462     if(baseName && baseName != baseNameBuffer) {
   463         uprv_free(baseName);
   464         baseName = NULL;
   465     }
   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;
   479         if(localeID == NULL) {
   480             // not an error, just set the default locale
   481             return *this = getDefault();
   482         }
   484         /* preset all fields to empty */
   485         language[0] = script[0] = country[0] = 0;
   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);
   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         }
   510         variantBegin = length;
   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         }
   532         if (fieldLen[0] >= (int32_t)(sizeof(language)))
   533         {
   534             break; // error: the language field is too long
   535         }
   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         }
   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         }
   561         if (fieldLen[variantField] > 0) {
   562             /* We have a variant */
   563             variantBegin = (int32_t)(field[variantField] - fullName);
   564         }
   566         // successful end of init()
   567         return *this;
   568     } while(0); /*loop doesn't iterate*/
   570     // when an error occurs, then set this object to "bogus" (there is no UErrorCode here)
   571     setToBogus();
   573     return *this;
   574 }
   576 int32_t
   577 Locale::hashCode() const
   578 {
   579     return ustr_hashCharsN(fullName, uprv_strlen(fullName));
   580 }
   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 }
   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 }
   615 void U_EXPORT2
   616 Locale::setDefault( const   Locale&     newLocale,
   617                             UErrorCode&  status)
   618 {
   619     if (U_FAILURE(status)) {
   620         return;
   621     }
   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 }
   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 }
   643 Locale U_EXPORT2
   644 Locale::createCanonical(const char* name) {
   645     Locale loc("");
   646     loc.init(name, TRUE);
   647     return loc;
   648 }
   650 const char *
   651 Locale::getISO3Language() const
   652 {
   653     return uloc_getISO3Language(fullName);
   654 }
   657 const char *
   658 Locale::getISO3Country() const
   659 {
   660     return uloc_getISO3Country(fullName);
   661 }
   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 }
   676 const char* const* U_EXPORT2 Locale::getISOCountries()
   677 {
   678     return uloc_getISOCountries();
   679 }
   681 const char* const* U_EXPORT2 Locale::getISOLanguages()
   682 {
   683     return uloc_getISOLanguages();
   684 }
   686 // Set the locale's data based on a posix id.
   687 void Locale::setFromPOSIXID(const char *posixID)
   688 {
   689     init(posixID, TRUE);
   690 }
   692 const Locale & U_EXPORT2
   693 Locale::getRoot(void)
   694 {
   695     return getLocale(eROOT);
   696 }
   698 const Locale & U_EXPORT2
   699 Locale::getEnglish(void)
   700 {
   701     return getLocale(eENGLISH);
   702 }
   704 const Locale & U_EXPORT2
   705 Locale::getFrench(void)
   706 {
   707     return getLocale(eFRENCH);
   708 }
   710 const Locale & U_EXPORT2
   711 Locale::getGerman(void)
   712 {
   713     return getLocale(eGERMAN);
   714 }
   716 const Locale & U_EXPORT2
   717 Locale::getItalian(void)
   718 {
   719     return getLocale(eITALIAN);
   720 }
   722 const Locale & U_EXPORT2
   723 Locale::getJapanese(void)
   724 {
   725     return getLocale(eJAPANESE);
   726 }
   728 const Locale & U_EXPORT2
   729 Locale::getKorean(void)
   730 {
   731     return getLocale(eKOREAN);
   732 }
   734 const Locale & U_EXPORT2
   735 Locale::getChinese(void)
   736 {
   737     return getLocale(eCHINESE);
   738 }
   740 const Locale & U_EXPORT2
   741 Locale::getSimplifiedChinese(void)
   742 {
   743     return getLocale(eCHINA);
   744 }
   746 const Locale & U_EXPORT2
   747 Locale::getTraditionalChinese(void)
   748 {
   749     return getLocale(eTAIWAN);
   750 }
   753 const Locale & U_EXPORT2
   754 Locale::getFrance(void)
   755 {
   756     return getLocale(eFRANCE);
   757 }
   759 const Locale & U_EXPORT2
   760 Locale::getGermany(void)
   761 {
   762     return getLocale(eGERMANY);
   763 }
   765 const Locale & U_EXPORT2
   766 Locale::getItaly(void)
   767 {
   768     return getLocale(eITALY);
   769 }
   771 const Locale & U_EXPORT2
   772 Locale::getJapan(void)
   773 {
   774     return getLocale(eJAPAN);
   775 }
   777 const Locale & U_EXPORT2
   778 Locale::getKorea(void)
   779 {
   780     return getLocale(eKOREA);
   781 }
   783 const Locale & U_EXPORT2
   784 Locale::getChina(void)
   785 {
   786     return getLocale(eCHINA);
   787 }
   789 const Locale & U_EXPORT2
   790 Locale::getPRC(void)
   791 {
   792     return getLocale(eCHINA);
   793 }
   795 const Locale & U_EXPORT2
   796 Locale::getTaiwan(void)
   797 {
   798     return getLocale(eTAIWAN);
   799 }
   801 const Locale & U_EXPORT2
   802 Locale::getUK(void)
   803 {
   804     return getLocale(eUK);
   805 }
   807 const Locale & U_EXPORT2
   808 Locale::getUS(void)
   809 {
   810     return getLocale(eUS);
   811 }
   813 const Locale & U_EXPORT2
   814 Locale::getCanada(void)
   815 {
   816     return getLocale(eCANADA);
   817 }
   819 const Locale & U_EXPORT2
   820 Locale::getCanadaFrench(void)
   821 {
   822     return getLocale(eCANADA_FRENCH);
   823 }
   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 }
   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);
   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");
   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 }
   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. */
   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     }
   920     virtual ~KeywordEnumeration();
   922     virtual StringEnumeration * clone() const
   923     {
   924         UErrorCode status = U_ZERO_ERROR;
   925         return new KeywordEnumeration(keywords, length, (int32_t)(current - keywords), status);
   926     }
   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     }
   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     }
   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     }
   963     virtual void reset(UErrorCode& /*status*/) {
   964         current = keywords;
   965     }
   966 };
   968 const char KeywordEnumeration::fgClassID = '\0';
   970 KeywordEnumeration::~KeywordEnumeration() {
   971     uprv_free(keywords);
   972 }
   974 StringEnumeration *
   975 Locale::createKeywords(UErrorCode &status) const
   976 {
   977     char keywords[256];
   978     int32_t keywordCapacity = 256;
   979     StringEnumeration *result = NULL;
   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 }
   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);
  1002 void
  1003 Locale::setKeywordValue(const char* keywordName, const char* keywordValue, UErrorCode &status)
  1005     uloc_setKeywordValue(keywordName, keywordValue, fullName, ULOC_FULLNAME_CAPACITY, &status);
  1008 const char *
  1009 Locale::getBaseName() const
  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;
  1022             uloc_getBaseName(fullName, baseName, baseNameSize+1, &status);
  1024         baseName[baseNameSize] = 0;
  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;
  1033     return baseName;
  1036 //eof
  1037 U_NAMESPACE_END

mercurial