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