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
deleteLocale(void * obj)111 deleteLocale(void *obj) {
112     delete (icu::Locale *) obj;
113 }
114 
locale_cleanup(void)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 
locale_init(UErrorCode & status)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 
locale_set_default_internal(const char * id,UErrorCode & status)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
locale_set_default(const char * id)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 *
locale_get_default(void)236 locale_get_default(void)
237 {
238     U_NAMESPACE_USE
239     return Locale::getDefault().getName();
240 }
241 
242 
243 U_NAMESPACE_BEGIN
244 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)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 
Locale()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  */
Locale(Locale::ELocaleType)277 Locale::Locale(Locale::ELocaleType)
278     : UObject(), fullName(fullNameBuffer), baseName(NULL)
279 {
280     setToBogus();
281 }
282 
283 
Locale(const char * newLanguage,const char * newCountry,const char * newVariant,const char * newKeywords)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 
Locale(const Locale & other)421 Locale::Locale(const Locale &other)
422     : UObject(other), fullName(fullNameBuffer), baseName(NULL)
423 {
424     *this = other;
425 }
426 
operator =(const Locale & other)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 *
clone() const474 Locale::clone() const {
475     return new Locale(*this);
476 }
477 
478 UBool
operator ==(const Locale & other) const479 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*/
init(const char * localeID,UBool canonicalize)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
initBaseName(UErrorCode & status)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
hashCode() const653 Locale::hashCode() const
654 {
655     return ustr_hashCharsN(fullName, uprv_strlen(fullName));
656 }
657 
658 void
setToBogus()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
getDefault()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
setDefault(const Locale & newLocale,UErrorCode & status)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
createFromName(const char * name)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
createCanonical(const char * name)721 Locale::createCanonical(const char* name) {
722     Locale loc("");
723     loc.init(name, TRUE);
724     return loc;
725 }
726 
727 const char *
getISO3Language() const728 Locale::getISO3Language() const
729 {
730     return uloc_getISO3Language(fullName);
731 }
732 
733 
734 const char *
getISO3Country() const735 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
getLCID() const748 Locale::getLCID() const
749 {
750     return uloc_getLCID(fullName);
751 }
752 
getISOCountries()753 const char* const* U_EXPORT2 Locale::getISOCountries()
754 {
755     return uloc_getISOCountries();
756 }
757 
getISOLanguages()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.
setFromPOSIXID(const char * posixID)764 void Locale::setFromPOSIXID(const char *posixID)
765 {
766     init(posixID, TRUE);
767 }
768 
769 const Locale & U_EXPORT2
getRoot(void)770 Locale::getRoot(void)
771 {
772     return getLocale(eROOT);
773 }
774 
775 const Locale & U_EXPORT2
getEnglish(void)776 Locale::getEnglish(void)
777 {
778     return getLocale(eENGLISH);
779 }
780 
781 const Locale & U_EXPORT2
getFrench(void)782 Locale::getFrench(void)
783 {
784     return getLocale(eFRENCH);
785 }
786 
787 const Locale & U_EXPORT2
getGerman(void)788 Locale::getGerman(void)
789 {
790     return getLocale(eGERMAN);
791 }
792 
793 const Locale & U_EXPORT2
getItalian(void)794 Locale::getItalian(void)
795 {
796     return getLocale(eITALIAN);
797 }
798 
799 const Locale & U_EXPORT2
getJapanese(void)800 Locale::getJapanese(void)
801 {
802     return getLocale(eJAPANESE);
803 }
804 
805 const Locale & U_EXPORT2
getKorean(void)806 Locale::getKorean(void)
807 {
808     return getLocale(eKOREAN);
809 }
810 
811 const Locale & U_EXPORT2
getChinese(void)812 Locale::getChinese(void)
813 {
814     return getLocale(eCHINESE);
815 }
816 
817 const Locale & U_EXPORT2
getSimplifiedChinese(void)818 Locale::getSimplifiedChinese(void)
819 {
820     return getLocale(eCHINA);
821 }
822 
823 const Locale & U_EXPORT2
getTraditionalChinese(void)824 Locale::getTraditionalChinese(void)
825 {
826     return getLocale(eTAIWAN);
827 }
828 
829 
830 const Locale & U_EXPORT2
getFrance(void)831 Locale::getFrance(void)
832 {
833     return getLocale(eFRANCE);
834 }
835 
836 const Locale & U_EXPORT2
getGermany(void)837 Locale::getGermany(void)
838 {
839     return getLocale(eGERMANY);
840 }
841 
842 const Locale & U_EXPORT2
getItaly(void)843 Locale::getItaly(void)
844 {
845     return getLocale(eITALY);
846 }
847 
848 const Locale & U_EXPORT2
getJapan(void)849 Locale::getJapan(void)
850 {
851     return getLocale(eJAPAN);
852 }
853 
854 const Locale & U_EXPORT2
getKorea(void)855 Locale::getKorea(void)
856 {
857     return getLocale(eKOREA);
858 }
859 
860 const Locale & U_EXPORT2
getChina(void)861 Locale::getChina(void)
862 {
863     return getLocale(eCHINA);
864 }
865 
866 const Locale & U_EXPORT2
getPRC(void)867 Locale::getPRC(void)
868 {
869     return getLocale(eCHINA);
870 }
871 
872 const Locale & U_EXPORT2
getTaiwan(void)873 Locale::getTaiwan(void)
874 {
875     return getLocale(eTAIWAN);
876 }
877 
878 const Locale & U_EXPORT2
getUK(void)879 Locale::getUK(void)
880 {
881     return getLocale(eUK);
882 }
883 
884 const Locale & U_EXPORT2
getUS(void)885 Locale::getUS(void)
886 {
887     return getLocale(eUS);
888 }
889 
890 const Locale & U_EXPORT2
getCanada(void)891 Locale::getCanada(void)
892 {
893     return getLocale(eCANADA);
894 }
895 
896 const Locale & U_EXPORT2
getCanadaFrench(void)897 Locale::getCanadaFrench(void)
898 {
899     return getLocale(eCANADA_FRENCH);
900 }
901 
902 const Locale &
getLocale(int locid)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 *
getLocaleCache(void)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:
getStaticClassID(void)936     static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; }
getDynamicClassID(void) const937     virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); }
938 public:
KeywordEnumeration(const char * keys,int32_t keywordLen,int32_t currentIndex,UErrorCode & status)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 
clone() const961     virtual StringEnumeration * clone() const
962     {
963         UErrorCode status = U_ZERO_ERROR;
964         return new KeywordEnumeration(keywords, length, (int32_t)(current - keywords), status);
965     }
966 
count(UErrorCode &) const967     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 
next(int32_t * resultLength,UErrorCode & status)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 
snext(UErrorCode & status)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 
reset(UErrorCode &)1002     virtual void reset(UErrorCode& /*status*/) {
1003         current = keywords;
1004     }
1005 };
1006 
1007 const char KeywordEnumeration::fgClassID = '\0';
1008 
~KeywordEnumeration()1009 KeywordEnumeration::~KeywordEnumeration() {
1010     uprv_free(keywords);
1011 }
1012 
1013 StringEnumeration *
createKeywords(UErrorCode & status) const1014 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
getKeywordValue(const char * keywordName,char * buffer,int32_t bufLen,UErrorCode & status) const1036 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
setKeywordValue(const char * keywordName,const char * keywordValue,UErrorCode & status)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 *
getBaseName() const1052 Locale::getBaseName() const {
1053     return baseName;
1054 }
1055 
1056 //eof
1057 U_NAMESPACE_END
1058