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