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