LCOV - code coverage report
Current view: top level - intl/icu/source/common - locid.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 137 444 30.9 %
Date: 2017-07-14 16:53:18 Functions: 11 69 15.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13