• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  **********************************************************************
3  *   Copyright (C) 1997-2007, 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 "umutex.h"
36 #include "uassert.h"
37 #include "cmemory.h"
38 #include "cstring.h"
39 #include "uhash.h"
40 #include "ucln_cmn.h"
41 
42 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
43 
44 static U_NAMESPACE_QUALIFIER Locale*  availableLocaleList = NULL;
45 static int32_t  availableLocaleListCount;
46 typedef enum ELocalePos {
47     eENGLISH,
48     eFRENCH,
49     eGERMAN,
50     eITALIAN,
51     eJAPANESE,
52     eKOREAN,
53     eCHINESE,
54 
55     eFRANCE,
56     eGERMANY,
57     eITALY,
58     eJAPAN,
59     eKOREA,
60     eCHINA,      /* Alias for PRC */
61     eTAIWAN,
62     eUK,
63     eUS,
64     eCANADA,
65     eCANADA_FRENCH,
66 
67 
68     //eDEFAULT,
69     eMAX_LOCALES
70 } ELocalePos;
71 
72 U_CFUNC int32_t locale_getKeywords(const char *localeID,
73             char prev,
74             char *keywords, int32_t keywordCapacity,
75             char *values, int32_t valuesCapacity, int32_t *valLen,
76             UBool valuesToo,
77             UErrorCode *status);
78 
79 static U_NAMESPACE_QUALIFIER Locale *gLocaleCache         = NULL;
80 static U_NAMESPACE_QUALIFIER Locale *gDefaultLocale       = NULL;
81 static UHashtable                   *gDefaultLocalesHashT = NULL;
82 
83 U_CDECL_BEGIN
84 //
85 // Deleter function for Locales owned by the default Locale hash table/
86 //
87 static void U_CALLCONV
deleteLocale(void * obj)88 deleteLocale(void *obj) {
89     delete (U_NAMESPACE_QUALIFIER Locale *) obj;
90 }
91 
locale_cleanup(void)92 static UBool U_CALLCONV locale_cleanup(void)
93 {
94     U_NAMESPACE_USE
95 
96     if (availableLocaleList) {
97         delete []availableLocaleList;
98         availableLocaleList = NULL;
99     }
100     availableLocaleListCount = 0;
101 
102     if (gLocaleCache) {
103         delete [] gLocaleCache;
104         gLocaleCache = NULL;
105     }
106 
107     if (gDefaultLocalesHashT) {
108         uhash_close(gDefaultLocalesHashT);   // Automatically deletes all elements, using deleter func.
109         gDefaultLocalesHashT = NULL;
110     }
111     else if (gDefaultLocale) {
112         // The cache wasn't created, and only one default locale was created.
113         delete gDefaultLocale;
114     }
115     gDefaultLocale = NULL;
116 
117     return TRUE;
118 }
119 U_CDECL_END
120 
121 U_NAMESPACE_BEGIN
122 //
123 //  locale_set_default_internal.
124 //
locale_set_default_internal(const char * id)125 void locale_set_default_internal(const char *id)
126 {
127     UErrorCode   status = U_ZERO_ERROR;
128     UBool canonicalize = FALSE;
129 
130     // If given a NULL string for the locale id, grab the default
131     //   name from the system.
132     //   (Different from most other locale APIs, where a null name means use
133     //    the current ICU default locale.)
134     if (id == NULL) {
135         umtx_lock(NULL);
136         id = uprv_getDefaultLocaleID();
137         umtx_unlock(NULL);
138         canonicalize = TRUE; // always canonicalize host ID
139     }
140 
141     // put the locale id into a canonical form,
142     //   in preparation for looking up this locale in the hash table of
143     //   already-created locale objects.
144     //
145     status = U_ZERO_ERROR;
146     char localeNameBuf[512];
147 
148     if (canonicalize) {
149         uloc_canonicalize(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
150     } else {
151         uloc_getName(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
152     }
153     localeNameBuf[sizeof(localeNameBuf)-1] = 0;  // Force null termination in event of
154                                                  //   a long name filling the buffer.
155                                                  //   (long names are truncated.)
156 
157     // Lazy creation of the hash table itself, if needed.
158     UBool isOnlyLocale;
159     UMTX_CHECK(NULL, (gDefaultLocale == NULL), isOnlyLocale);
160     if (isOnlyLocale) {
161         // We haven't seen this locale id before.
162         // Create a new Locale object for it.
163         Locale *newFirstDefault = new Locale(Locale::eBOGUS);
164         if (newFirstDefault == NULL) {
165             // No way to report errors from here.
166             return;
167         }
168         newFirstDefault->init(localeNameBuf, FALSE);
169         umtx_lock(NULL);
170         if (gDefaultLocale == NULL) {
171             gDefaultLocale = newFirstDefault;  // Assignment to gDefaultLocale must happen inside mutex
172             newFirstDefault = NULL;
173             ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
174         }
175         // Else some other thread raced us through here, and set the new Locale.
176         // Use the hash table next.
177         umtx_unlock(NULL);
178         if (newFirstDefault == NULL) {
179             // We were successful in setting the locale, and we were the first one to set it.
180             return;
181         }
182         // else start using the hash table.
183     }
184 
185     // Lazy creation of the hash table itself, if needed.
186     UBool hashTableNeedsInit;
187     UMTX_CHECK(NULL, (gDefaultLocalesHashT == NULL), hashTableNeedsInit);
188     if (hashTableNeedsInit) {
189         status = U_ZERO_ERROR;
190         UHashtable *tHashTable = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
191         if (U_FAILURE(status)) {
192             return;
193         }
194         uhash_setValueDeleter(tHashTable, deleteLocale);
195         umtx_lock(NULL);
196         if (gDefaultLocalesHashT == NULL) {
197             gDefaultLocalesHashT = tHashTable;
198             ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
199         } else {
200             uhash_close(tHashTable);
201             hashTableNeedsInit = FALSE;
202         }
203         umtx_unlock(NULL);
204     }
205 
206     // Hash table lookup, key is the locale full name
207     umtx_lock(NULL);
208     Locale *newDefault = (Locale *)uhash_get(gDefaultLocalesHashT, localeNameBuf);
209     if (newDefault != NULL) {
210         // We have the requested locale in the hash table already.
211         // Just set it as default.  Inside the mutex lock, for those troublesome processors.
212         gDefaultLocale = newDefault;
213         umtx_unlock(NULL);
214     } else {
215         umtx_unlock(NULL);
216         // We haven't seen this locale id before.
217         // Create a new Locale object for it.
218         newDefault = new Locale(Locale::eBOGUS);
219         if (newDefault == NULL) {
220             // No way to report errors from here.
221             return;
222         }
223         newDefault->init(localeNameBuf, FALSE);
224 
225         // Add newly created Locale to the hash table of default Locales
226         const char *key = newDefault->getName();
227         U_ASSERT(uprv_strcmp(key, localeNameBuf) == 0);
228         umtx_lock(NULL);
229         Locale *hashTableVal = (Locale *)uhash_get(gDefaultLocalesHashT, key);
230         if (hashTableVal == NULL) {
231             if (hashTableNeedsInit) {
232                 // This is the second request to set the locale.
233                 // Cache the first one.
234                 uhash_put(gDefaultLocalesHashT, (void *)gDefaultLocale->getName(), gDefaultLocale, &status);
235             }
236             uhash_put(gDefaultLocalesHashT, (void *)key, newDefault, &status);
237             gDefaultLocale = newDefault;
238             // ignore errors from hash table insert.  (Couldn't do anything anyway)
239             // We can still set the default Locale,
240             //  it just wont be cached, and will eventually leak.
241         } else {
242             // Some other thread raced us through here, and got the new Locale
243             //   into the hash table before us.  Use that one.
244             gDefaultLocale = hashTableVal;  // Assignment to gDefaultLocale must happen inside mutex
245             delete newDefault;
246         }
247         umtx_unlock(NULL);
248     }
249 }
250 U_NAMESPACE_END
251 
252 /* sfb 07/21/99 */
253 U_CFUNC void
locale_set_default(const char * id)254 locale_set_default(const char *id)
255 {
256     U_NAMESPACE_USE
257     locale_set_default_internal(id);
258 }
259 /* end */
260 
261 U_CFUNC const char *
locale_get_default(void)262 locale_get_default(void)
263 {
264     U_NAMESPACE_USE
265 
266     return Locale::getDefault().getName();
267 }
268 
269 
270 U_NAMESPACE_BEGIN
271 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)272 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)
273 
274 /*Character separating the posix id fields*/
275 // '_'
276 // In the platform codepage.
277 #define SEP_CHAR '_'
278 
279 Locale::~Locale()
280 {
281     /*if fullName is on the heap, we free it*/
282     if (fullName != fullNameBuffer)
283     {
284         uprv_free(fullName);
285         fullName = NULL;
286     }
287     if (baseName && baseName != baseNameBuffer) {
288         uprv_free(baseName);
289         baseName = NULL;
290     }
291 }
292 
Locale()293 Locale::Locale()
294     : UObject(), fullName(fullNameBuffer), baseName(NULL)
295 {
296     init(NULL, FALSE);
297 }
298 
299 /*
300  * Internal constructor to allow construction of a locale object with
301  *   NO side effects.   (Default constructor tries to get
302  *   the default locale.)
303  */
Locale(Locale::ELocaleType)304 Locale::Locale(Locale::ELocaleType)
305     : UObject(), fullName(fullNameBuffer), baseName(NULL)
306 {
307     setToBogus();
308 }
309 
310 
Locale(const char * newLanguage,const char * newCountry,const char * newVariant,const char * newKeywords)311 Locale::Locale( const   char * newLanguage,
312                 const   char * newCountry,
313                 const   char * newVariant,
314                 const   char * newKeywords)
315     : UObject(), fullName(fullNameBuffer), baseName(NULL)
316 {
317     if( (newLanguage==NULL) && (newCountry == NULL) && (newVariant == NULL) )
318     {
319         init(NULL, FALSE); /* shortcut */
320     }
321     else
322     {
323         char togo_stack[ULOC_FULLNAME_CAPACITY];
324         char *togo;
325         char *togo_heap = NULL;
326         int32_t size = 0;
327         int32_t lsize = 0;
328         int32_t csize = 0;
329         int32_t vsize = 0;
330         int32_t ksize = 0;
331         char    *p;
332 
333         // Calculate the size of the resulting string.
334 
335         // Language
336         if ( newLanguage != NULL )
337         {
338             lsize = (int32_t)uprv_strlen(newLanguage);
339             size = lsize;
340         }
341 
342         // _Country
343         if ( newCountry != NULL )
344         {
345             csize = (int32_t)uprv_strlen(newCountry);
346             size += csize;
347         }
348 
349         // _Variant
350         if ( newVariant != NULL )
351         {
352             // remove leading _'s
353             while(newVariant[0] == SEP_CHAR)
354             {
355                 newVariant++;
356             }
357 
358             // remove trailing _'s
359             vsize = (int32_t)uprv_strlen(newVariant);
360             while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) )
361             {
362                 vsize--;
363             }
364         }
365 
366         if( vsize > 0 )
367         {
368             size += vsize;
369         }
370 
371         // Separator rules:
372         if ( vsize > 0 )
373         {
374             size += 2;  // at least: __v
375         }
376         else if ( csize > 0 )
377         {
378             size += 1;  // at least: _v
379         }
380 
381         if ( newKeywords != NULL)
382         {
383             ksize = (int32_t)uprv_strlen(newKeywords);
384             size += ksize + 1;
385         }
386 
387 
388         //  NOW we have the full locale string..
389 
390         /*if the whole string is longer than our internal limit, we need
391         to go to the heap for temporary buffers*/
392         if (size >= ULOC_FULLNAME_CAPACITY)
393         {
394             togo_heap = (char *)uprv_malloc(sizeof(char)*(size+1));
395             togo = togo_heap;
396         }
397         else
398         {
399             togo = togo_stack;
400         }
401 
402         togo[0] = 0;
403 
404         // Now, copy it back.
405         p = togo;
406         if ( lsize != 0 )
407         {
408             uprv_strcpy(p, newLanguage);
409             p += lsize;
410         }
411 
412         if ( ( vsize != 0 ) || (csize != 0) )  // at least:  __v
413         {                                      //            ^
414             *p++ = SEP_CHAR;
415         }
416 
417         if ( csize != 0 )
418         {
419             uprv_strcpy(p, newCountry);
420             p += csize;
421         }
422 
423         if ( vsize != 0)
424         {
425             *p++ = SEP_CHAR; // at least: __v
426 
427             uprv_strncpy(p, newVariant, vsize);  // Must use strncpy because
428             p += vsize;                          // of trimming (above).
429             *p = 0; // terminate
430         }
431 
432         if ( ksize != 0)
433         {
434             if (uprv_strchr(newKeywords, '=')) {
435                 *p++ = '@'; /* keyword parsing */
436             }
437             else {
438                 *p++ = '_'; /* Variant parsing with a script */
439                 if ( vsize == 0) {
440                     *p++ = '_'; /* No country found */
441                 }
442             }
443             uprv_strcpy(p, newKeywords);
444             p += ksize;
445         }
446 
447         // Parse it, because for example 'language' might really be a complete
448         // string.
449         init(togo, FALSE);
450 
451         if (togo_heap) {
452             uprv_free(togo_heap);
453         }
454     }
455 }
456 
Locale(const Locale & other)457 Locale::Locale(const Locale &other)
458     : UObject(other), fullName(fullNameBuffer), baseName(NULL)
459 {
460     *this = other;
461 }
462 
operator =(const Locale & other)463 Locale &Locale::operator=(const Locale &other)
464 {
465     if (this == &other) {
466         return *this;
467     }
468 
469     if (&other == NULL) {
470         this->setToBogus();
471         return *this;
472     }
473 
474     /* Free our current storage */
475     if(fullName != fullNameBuffer) {
476         uprv_free(fullName);
477         fullName = fullNameBuffer;
478     }
479 
480     /* Allocate the full name if necessary */
481     if(other.fullName != other.fullNameBuffer) {
482         fullName = (char *)uprv_malloc(sizeof(char)*(uprv_strlen(other.fullName)+1));
483     }
484     /* Copy the full name */
485     uprv_strcpy(fullName, other.fullName);
486 
487     /* baseName is the cached result of getBaseName.  if 'other' has a
488        baseName and it fits in baseNameBuffer, then copy it. otherwise set
489        it to NULL, and let the user lazy-create it (in getBaseName) if they
490        want it. */
491     if(baseName && baseName != baseNameBuffer) {
492         uprv_free(baseName);
493     }
494     baseName = NULL;
495 
496     if(other.baseName == other.baseNameBuffer) {
497         uprv_strcpy(baseNameBuffer, other.baseNameBuffer);
498         baseName = baseNameBuffer;
499     }
500 
501     /* Copy the language and country fields */
502     uprv_strcpy(language, other.language);
503     uprv_strcpy(script, other.script);
504     uprv_strcpy(country, other.country);
505 
506     /* The variantBegin is an offset into fullName, just copy it */
507     variantBegin = other.variantBegin;
508     fIsBogus = other.fIsBogus;
509     return *this;
510 }
511 
512 Locale *
clone() const513 Locale::clone() const {
514     return new Locale(*this);
515 }
516 
517 UBool
operator ==(const Locale & other) const518 Locale::operator==( const   Locale& other) const
519 {
520     return (uprv_strcmp(other.fullName, fullName) == 0);
521 }
522 
523 /*This function initializes a Locale from a C locale ID*/
init(const char * localeID,UBool canonicalize)524 Locale& Locale::init(const char* localeID, UBool canonicalize)
525 {
526     fIsBogus = FALSE;
527     /* Free our current storage */
528     if(fullName != fullNameBuffer) {
529         uprv_free(fullName);
530         fullName = fullNameBuffer;
531     }
532 
533     if(baseName && baseName != baseNameBuffer) {
534         uprv_free(baseName);
535         baseName = NULL;
536     }
537 
538     // not a loop:
539     // just an easy way to have a common error-exit
540     // without goto and without another function
541     do {
542         char *separator;
543         char *field[5] = {0};
544         int32_t fieldLen[5] = {0};
545         int32_t fieldIdx;
546         int32_t variantField;
547         int32_t length;
548         UErrorCode err;
549 
550         if(localeID == NULL) {
551             // not an error, just set the default locale
552             return *this = getDefault();
553         }
554 
555         /* preset all fields to empty */
556         language[0] = script[0] = country[0] = 0;
557 
558         // "canonicalize" the locale ID to ICU/Java format
559         err = U_ZERO_ERROR;
560         length = canonicalize ?
561             uloc_canonicalize(localeID, fullName, sizeof(fullNameBuffer), &err) :
562             uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err);
563 
564         if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) {
565             /*Go to heap for the fullName if necessary*/
566             fullName = (char *)uprv_malloc(sizeof(char)*(length + 1));
567             if(fullName == 0) {
568                 fullName = fullNameBuffer;
569                 break; // error: out of memory
570             }
571             err = U_ZERO_ERROR;
572             length = canonicalize ?
573                 uloc_canonicalize(localeID, fullName, length+1, &err) :
574                 uloc_getName(localeID, fullName, length+1, &err);
575         }
576         if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
577             /* should never occur */
578             break;
579         }
580 
581         variantBegin = length;
582 
583         /* after uloc_getName/canonicalize() we know that only '_' are separators */
584         separator = field[0] = fullName;
585         fieldIdx = 1;
586         while ((separator = uprv_strchr(field[fieldIdx-1], SEP_CHAR)) && fieldIdx < (int32_t)(sizeof(field)/sizeof(field[0]))-1) {
587             field[fieldIdx] = separator + 1;
588             fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
589             fieldIdx++;
590         }
591         // variant may contain @foo or .foo POSIX cruft; remove it
592         separator = uprv_strchr(field[fieldIdx-1], '@');
593         char* sep2 = uprv_strchr(field[fieldIdx-1], '.');
594         if (separator!=NULL || sep2!=NULL) {
595             if (separator==NULL || (sep2!=NULL && separator > sep2)) {
596                 separator = sep2;
597             }
598             fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
599         } else {
600             fieldLen[fieldIdx-1] = length - (int32_t)(field[fieldIdx-1] - fullName);
601         }
602 
603         if (fieldLen[0] >= (int32_t)(sizeof(language))
604             || (fieldLen[1] == 4 && fieldLen[2] >= (int32_t)(sizeof(country)))
605             || (fieldLen[1] != 4 && fieldLen[1] >= (int32_t)(sizeof(country))))
606         {
607             break; // error: one of the fields is too long
608         }
609 
610         variantField = 2; /* Usually the 2nd one, except when a script is used. */
611         if (fieldLen[0] > 0) {
612             /* We have a language */
613             uprv_memcpy(language, fullName, fieldLen[0]);
614             language[fieldLen[0]] = 0;
615         }
616         if (fieldLen[1] == 4) {
617             /* We have at least a script */
618             uprv_memcpy(script, field[1], fieldLen[1]);
619             script[fieldLen[1]] = 0;
620             variantField = 3;
621             if (fieldLen[2] > 0) {
622                 /* We have a country */
623                 uprv_memcpy(country, field[2], fieldLen[2]);
624                 country[fieldLen[2]] = 0;
625             }
626         }
627         else if (fieldLen[1] > 0) {
628             /* We have a country and no script */
629             uprv_memcpy(country, field[1], fieldLen[1]);
630             country[fieldLen[1]] = 0;
631         }
632         if (variantField > 0 && fieldLen[variantField] > 0) {
633             /* We have a variant */
634             variantBegin = (int32_t)(field[variantField] - fullName);
635         }
636 
637         // successful end of init()
638         return *this;
639     } while(0); /*loop doesn't iterate*/
640 
641     // when an error occurs, then set this object to "bogus" (there is no UErrorCode here)
642     setToBogus();
643 
644     return *this;
645 }
646 
647 int32_t
hashCode() const648 Locale::hashCode() const
649 {
650     UHashTok hashKey;
651     hashKey.pointer = fullName;
652     return uhash_hashChars(hashKey);
653 }
654 
655 void
setToBogus()656 Locale::setToBogus() {
657     /* Free our current storage */
658     if(fullName != fullNameBuffer) {
659         uprv_free(fullName);
660         fullName = fullNameBuffer;
661     }
662     *fullNameBuffer = 0;
663     *language = 0;
664     *script = 0;
665     *country = 0;
666     fIsBogus = TRUE;
667 }
668 
669 const Locale& U_EXPORT2
getDefault()670 Locale::getDefault()
671 {
672     const Locale *retLocale;
673     UMTX_CHECK(NULL, gDefaultLocale, retLocale);
674     if (retLocale == NULL) {
675         locale_set_default_internal(NULL);
676         umtx_lock(NULL);
677         // Need a mutex  in case some other thread set a new
678         // default inbetween when we set and when we get the new default.  For
679         // processors with weak memory coherency, we might not otherwise see all
680         // of the newly created new default locale.
681         retLocale = gDefaultLocale;
682         umtx_unlock(NULL);
683     }
684     return *retLocale;
685 }
686 
687 
688 
689 void U_EXPORT2
setDefault(const Locale & newLocale,UErrorCode & status)690 Locale::setDefault( const   Locale&     newLocale,
691                             UErrorCode&  status)
692 {
693     if (U_FAILURE(status)) {
694         return;
695     }
696 
697     /* Set the default from the full name string of the supplied locale.
698      * This is a convenient way to access the default locale caching mechanisms.
699      */
700     const char *localeID = newLocale.getName();
701     locale_set_default_internal(localeID);
702 }
703 
704 Locale U_EXPORT2
createFromName(const char * name)705 Locale::createFromName (const char *name)
706 {
707     if (name) {
708         Locale l("");
709         l.init(name, FALSE);
710         return l;
711     }
712     else {
713         return getDefault();
714     }
715 }
716 
717 Locale U_EXPORT2
createCanonical(const char * name)718 Locale::createCanonical(const char* name) {
719     Locale loc("");
720     loc.init(name, TRUE);
721     return loc;
722 }
723 
724 const char *
getISO3Language() const725 Locale::getISO3Language() const
726 {
727     return uloc_getISO3Language(fullName);
728 }
729 
730 
731 const char *
getISO3Country() const732 Locale::getISO3Country() const
733 {
734     return uloc_getISO3Country(fullName);
735 }
736 
737 /**
738  * Return the LCID value as specified in the "LocaleID" resource for this
739  * locale.  The LocaleID must be expressed as a hexadecimal number, from
740  * one to four digits.  If the LocaleID resource is not present, or is
741  * in an incorrect format, 0 is returned.  The LocaleID is for use in
742  * Windows (it is an LCID), but is available on all platforms.
743  */
744 uint32_t
getLCID() const745 Locale::getLCID() const
746 {
747     return uloc_getLCID(fullName);
748 }
749 
750 UnicodeString&
getDisplayLanguage(UnicodeString & dispLang) const751 Locale::getDisplayLanguage(UnicodeString& dispLang) const
752 {
753     return this->getDisplayLanguage(getDefault(), dispLang);
754 }
755 
756 /*We cannot make any assumptions on the size of the output display strings
757 * Yet, since we are calling through to a C API, we need to set limits on
758 * buffer size. For all the following getDisplay functions we first attempt
759 * to fill up a stack allocated buffer. If it is to small we heap allocated
760 * the exact buffer we need copy it to the UnicodeString and delete it*/
761 
762 UnicodeString&
getDisplayLanguage(const Locale & displayLocale,UnicodeString & result) const763 Locale::getDisplayLanguage(const Locale &displayLocale,
764                            UnicodeString &result) const {
765     UChar *buffer;
766     UErrorCode errorCode=U_ZERO_ERROR;
767     int32_t length;
768 
769     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
770     if(buffer==0) {
771         result.truncate(0);
772         return result;
773     }
774 
775     length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
776                                    buffer, result.getCapacity(),
777                                    &errorCode);
778     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
779 
780     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
781         buffer=result.getBuffer(length);
782         if(buffer==0) {
783             result.truncate(0);
784             return result;
785         }
786         errorCode=U_ZERO_ERROR;
787         length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
788                                        buffer, result.getCapacity(),
789                                        &errorCode);
790         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
791     }
792 
793     return result;
794 }
795 
796 UnicodeString&
getDisplayScript(UnicodeString & dispScript) const797 Locale::getDisplayScript(UnicodeString& dispScript) const
798 {
799     return this->getDisplayScript(getDefault(), dispScript);
800 }
801 
802 UnicodeString&
getDisplayScript(const Locale & displayLocale,UnicodeString & result) const803 Locale::getDisplayScript(const Locale &displayLocale,
804                           UnicodeString &result) const {
805     UChar *buffer;
806     UErrorCode errorCode=U_ZERO_ERROR;
807     int32_t length;
808 
809     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
810     if(buffer==0) {
811         result.truncate(0);
812         return result;
813     }
814 
815     length=uloc_getDisplayScript(fullName, displayLocale.fullName,
816                                   buffer, result.getCapacity(),
817                                   &errorCode);
818     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
819 
820     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
821         buffer=result.getBuffer(length);
822         if(buffer==0) {
823             result.truncate(0);
824             return result;
825         }
826         errorCode=U_ZERO_ERROR;
827         length=uloc_getDisplayScript(fullName, displayLocale.fullName,
828                                       buffer, result.getCapacity(),
829                                       &errorCode);
830         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
831     }
832 
833     return result;
834 }
835 
836 UnicodeString&
getDisplayCountry(UnicodeString & dispCntry) const837 Locale::getDisplayCountry(UnicodeString& dispCntry) const
838 {
839     return this->getDisplayCountry(getDefault(), dispCntry);
840 }
841 
842 UnicodeString&
getDisplayCountry(const Locale & displayLocale,UnicodeString & result) const843 Locale::getDisplayCountry(const Locale &displayLocale,
844                           UnicodeString &result) const {
845     UChar *buffer;
846     UErrorCode errorCode=U_ZERO_ERROR;
847     int32_t length;
848 
849     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
850     if(buffer==0) {
851         result.truncate(0);
852         return result;
853     }
854 
855     length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
856                                   buffer, result.getCapacity(),
857                                   &errorCode);
858     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
859 
860     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
861         buffer=result.getBuffer(length);
862         if(buffer==0) {
863             result.truncate(0);
864             return result;
865         }
866         errorCode=U_ZERO_ERROR;
867         length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
868                                       buffer, result.getCapacity(),
869                                       &errorCode);
870         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
871     }
872 
873     return result;
874 }
875 
876 UnicodeString&
getDisplayVariant(UnicodeString & dispVar) const877 Locale::getDisplayVariant(UnicodeString& dispVar) const
878 {
879     return this->getDisplayVariant(getDefault(), dispVar);
880 }
881 
882 UnicodeString&
getDisplayVariant(const Locale & displayLocale,UnicodeString & result) const883 Locale::getDisplayVariant(const Locale &displayLocale,
884                           UnicodeString &result) const {
885     UChar *buffer;
886     UErrorCode errorCode=U_ZERO_ERROR;
887     int32_t length;
888 
889     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
890     if(buffer==0) {
891         result.truncate(0);
892         return result;
893     }
894 
895     length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
896                                   buffer, result.getCapacity(),
897                                   &errorCode);
898     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
899 
900     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
901         buffer=result.getBuffer(length);
902         if(buffer==0) {
903             result.truncate(0);
904             return result;
905         }
906         errorCode=U_ZERO_ERROR;
907         length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
908                                       buffer, result.getCapacity(),
909                                       &errorCode);
910         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
911     }
912 
913     return result;
914 }
915 
916 UnicodeString&
getDisplayName(UnicodeString & name) const917 Locale::getDisplayName( UnicodeString& name ) const
918 {
919     return this->getDisplayName(getDefault(), name);
920 }
921 
922 UnicodeString&
getDisplayName(const Locale & displayLocale,UnicodeString & result) const923 Locale::getDisplayName(const Locale &displayLocale,
924                        UnicodeString &result) const {
925     UChar *buffer;
926     UErrorCode errorCode=U_ZERO_ERROR;
927     int32_t length;
928 
929     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
930     if(buffer==0) {
931         result.truncate(0);
932         return result;
933     }
934 
935     length=uloc_getDisplayName(fullName, displayLocale.fullName,
936                                buffer, result.getCapacity(),
937                                &errorCode);
938     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
939 
940     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
941         buffer=result.getBuffer(length);
942         if(buffer==0) {
943             result.truncate(0);
944             return result;
945         }
946         errorCode=U_ZERO_ERROR;
947         length=uloc_getDisplayName(fullName, displayLocale.fullName,
948                                    buffer, result.getCapacity(),
949                                    &errorCode);
950         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
951     }
952 
953     return result;
954 }
955 const Locale* U_EXPORT2
getAvailableLocales(int32_t & count)956 Locale::getAvailableLocales(int32_t& count)
957 {
958     // for now, there is a hardcoded list, so just walk through that list and set it up.
959     UBool needInit;
960     UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
961 
962     if (needInit) {
963         int32_t locCount = uloc_countAvailable();
964         Locale *newLocaleList = 0;
965         if(locCount) {
966            newLocaleList = new Locale[locCount];
967         }
968         if (newLocaleList == NULL) {
969             count = 0;
970             return NULL;
971         }
972 
973         count = locCount;
974 
975         while(--locCount >= 0) {
976             newLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount));
977         }
978 
979         umtx_lock(NULL);
980         if(availableLocaleList == 0) {
981             availableLocaleListCount = count;
982             availableLocaleList = newLocaleList;
983             newLocaleList = NULL;
984             ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
985         }
986         umtx_unlock(NULL);
987         delete []newLocaleList;
988     }
989     count = availableLocaleListCount;
990     return availableLocaleList;
991 }
992 
getISOCountries()993 const char* const* U_EXPORT2 Locale::getISOCountries()
994 {
995     return uloc_getISOCountries();
996 }
997 
getISOLanguages()998 const char* const* U_EXPORT2 Locale::getISOLanguages()
999 {
1000     return uloc_getISOLanguages();
1001 }
1002 
1003 // Set the locale's data based on a posix id.
setFromPOSIXID(const char * posixID)1004 void Locale::setFromPOSIXID(const char *posixID)
1005 {
1006     init(posixID, TRUE);
1007 }
1008 
1009 const Locale & U_EXPORT2
getEnglish(void)1010 Locale::getEnglish(void)
1011 {
1012     return getLocale(eENGLISH);
1013 }
1014 
1015 const Locale & U_EXPORT2
getFrench(void)1016 Locale::getFrench(void)
1017 {
1018     return getLocale(eFRENCH);
1019 }
1020 
1021 const Locale & U_EXPORT2
getGerman(void)1022 Locale::getGerman(void)
1023 {
1024     return getLocale(eGERMAN);
1025 }
1026 
1027 const Locale & U_EXPORT2
getItalian(void)1028 Locale::getItalian(void)
1029 {
1030     return getLocale(eITALIAN);
1031 }
1032 
1033 const Locale & U_EXPORT2
getJapanese(void)1034 Locale::getJapanese(void)
1035 {
1036     return getLocale(eJAPANESE);
1037 }
1038 
1039 const Locale & U_EXPORT2
getKorean(void)1040 Locale::getKorean(void)
1041 {
1042     return getLocale(eKOREAN);
1043 }
1044 
1045 const Locale & U_EXPORT2
getChinese(void)1046 Locale::getChinese(void)
1047 {
1048     return getLocale(eCHINESE);
1049 }
1050 
1051 const Locale & U_EXPORT2
getSimplifiedChinese(void)1052 Locale::getSimplifiedChinese(void)
1053 {
1054     return getLocale(eCHINA);
1055 }
1056 
1057 const Locale & U_EXPORT2
getTraditionalChinese(void)1058 Locale::getTraditionalChinese(void)
1059 {
1060     return getLocale(eTAIWAN);
1061 }
1062 
1063 
1064 const Locale & U_EXPORT2
getFrance(void)1065 Locale::getFrance(void)
1066 {
1067     return getLocale(eFRANCE);
1068 }
1069 
1070 const Locale & U_EXPORT2
getGermany(void)1071 Locale::getGermany(void)
1072 {
1073     return getLocale(eGERMANY);
1074 }
1075 
1076 const Locale & U_EXPORT2
getItaly(void)1077 Locale::getItaly(void)
1078 {
1079     return getLocale(eITALY);
1080 }
1081 
1082 const Locale & U_EXPORT2
getJapan(void)1083 Locale::getJapan(void)
1084 {
1085     return getLocale(eJAPAN);
1086 }
1087 
1088 const Locale & U_EXPORT2
getKorea(void)1089 Locale::getKorea(void)
1090 {
1091     return getLocale(eKOREA);
1092 }
1093 
1094 const Locale & U_EXPORT2
getChina(void)1095 Locale::getChina(void)
1096 {
1097     return getLocale(eCHINA);
1098 }
1099 
1100 const Locale & U_EXPORT2
getPRC(void)1101 Locale::getPRC(void)
1102 {
1103     return getLocale(eCHINA);
1104 }
1105 
1106 const Locale & U_EXPORT2
getTaiwan(void)1107 Locale::getTaiwan(void)
1108 {
1109     return getLocale(eTAIWAN);
1110 }
1111 
1112 const Locale & U_EXPORT2
getUK(void)1113 Locale::getUK(void)
1114 {
1115     return getLocale(eUK);
1116 }
1117 
1118 const Locale & U_EXPORT2
getUS(void)1119 Locale::getUS(void)
1120 {
1121     return getLocale(eUS);
1122 }
1123 
1124 const Locale & U_EXPORT2
getCanada(void)1125 Locale::getCanada(void)
1126 {
1127     return getLocale(eCANADA);
1128 }
1129 
1130 const Locale & U_EXPORT2
getCanadaFrench(void)1131 Locale::getCanadaFrench(void)
1132 {
1133     return getLocale(eCANADA_FRENCH);
1134 }
1135 
1136 const Locale &
getLocale(int locid)1137 Locale::getLocale(int locid)
1138 {
1139     Locale *localeCache = getLocaleCache();
1140     U_ASSERT((locid < eMAX_LOCALES)&&(locid>=0));
1141     if (localeCache == NULL) {
1142         // Failure allocating the locale cache.
1143         //   The best we can do is return a NULL reference.
1144         locid = 0;
1145     }
1146     return localeCache[locid]; /*operating on NULL*/
1147 }
1148 
1149 /*
1150 This function is defined this way in order to get around static
1151 initialization and static destruction.
1152  */
1153 Locale *
getLocaleCache(void)1154 Locale::getLocaleCache(void)
1155 {
1156     umtx_lock(NULL);
1157     UBool needInit = (gLocaleCache == NULL);
1158     umtx_unlock(NULL);
1159 
1160     if (needInit) {
1161         Locale *tLocaleCache = new Locale[(int)eMAX_LOCALES];
1162         if (tLocaleCache == NULL) {
1163             return NULL;
1164         }
1165         tLocaleCache[eENGLISH]       = Locale("en");
1166         tLocaleCache[eFRENCH]        = Locale("fr");
1167         tLocaleCache[eGERMAN]        = Locale("de");
1168         tLocaleCache[eITALIAN]       = Locale("it");
1169         tLocaleCache[eJAPANESE]      = Locale("ja");
1170         tLocaleCache[eKOREAN]        = Locale("ko");
1171         tLocaleCache[eCHINESE]       = Locale("zh");
1172         tLocaleCache[eFRANCE]        = Locale("fr", "FR");
1173         tLocaleCache[eGERMANY]       = Locale("de", "DE");
1174         tLocaleCache[eITALY]         = Locale("it", "IT");
1175         tLocaleCache[eJAPAN]         = Locale("ja", "JP");
1176         tLocaleCache[eKOREA]         = Locale("ko", "KR");
1177         tLocaleCache[eCHINA]         = Locale("zh", "CN");
1178         tLocaleCache[eTAIWAN]        = Locale("zh", "TW");
1179         tLocaleCache[eUK]            = Locale("en", "GB");
1180         tLocaleCache[eUS]            = Locale("en", "US");
1181         tLocaleCache[eCANADA]        = Locale("en", "CA");
1182         tLocaleCache[eCANADA_FRENCH] = Locale("fr", "CA");
1183 
1184         umtx_lock(NULL);
1185         if (gLocaleCache == NULL) {
1186             gLocaleCache = tLocaleCache;
1187             tLocaleCache = NULL;
1188             ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
1189         }
1190         umtx_unlock(NULL);
1191         if (tLocaleCache) {
1192             delete [] tLocaleCache;  // Fancy array delete will destruct each member.
1193         }
1194     }
1195     return gLocaleCache;
1196 }
1197 
1198 class KeywordEnumeration : public StringEnumeration {
1199 private:
1200     char *keywords;
1201     char *current;
1202     int32_t length;
1203     UnicodeString currUSKey;
1204     static const char fgClassID;/* Warning this is used beyond the typical RTTI usage. */
1205 
1206 public:
getStaticClassID(void)1207     static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; }
getDynamicClassID(void) const1208     virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); }
1209 public:
KeywordEnumeration(const char * keys,int32_t keywordLen,int32_t currentIndex,UErrorCode & status)1210     KeywordEnumeration(const char *keys, int32_t keywordLen, int32_t currentIndex, UErrorCode &status)
1211         : keywords((char *)&fgClassID), current((char *)&fgClassID), length(0) {
1212         if(U_SUCCESS(status) && keywordLen != 0) {
1213             if(keys == NULL || keywordLen < 0) {
1214                 status = U_ILLEGAL_ARGUMENT_ERROR;
1215             } else {
1216                 keywords = (char *)uprv_malloc(keywordLen+1);
1217                 if (keywords == NULL) {
1218                     status = U_MEMORY_ALLOCATION_ERROR;
1219                 }
1220                 else {
1221                     uprv_memcpy(keywords, keys, keywordLen);
1222                     keywords[keywordLen] = 0;
1223                     current = keywords + currentIndex;
1224                     length = keywordLen;
1225                 }
1226             }
1227         }
1228     }
1229 
~KeywordEnumeration()1230     virtual ~KeywordEnumeration() {
1231         uprv_free(keywords);
1232     }
1233 
clone() const1234     virtual StringEnumeration * clone() const
1235     {
1236         UErrorCode status = U_ZERO_ERROR;
1237         return new KeywordEnumeration(keywords, length, (int32_t)(current - keywords), status);
1238     }
1239 
count(UErrorCode &) const1240     virtual int32_t count(UErrorCode &/*status*/) const {
1241         char *kw = keywords;
1242         int32_t result = 0;
1243         while(*kw) {
1244             result++;
1245             kw += uprv_strlen(kw)+1;
1246         }
1247         return result;
1248     }
1249 
next(int32_t * resultLength,UErrorCode & status)1250     virtual const char* next(int32_t* resultLength, UErrorCode& status) {
1251         const char* result;
1252         int32_t len;
1253         if(U_SUCCESS(status) && *current != 0) {
1254             result = current;
1255             len = (int32_t)uprv_strlen(current);
1256             current += len+1;
1257             if(resultLength != NULL) {
1258                 *resultLength = len;
1259             }
1260         } else {
1261             if(resultLength != NULL) {
1262                 *resultLength = 0;
1263             }
1264             result = NULL;
1265         }
1266         return result;
1267     }
1268 
snext(UErrorCode & status)1269     virtual const UnicodeString* snext(UErrorCode& status) {
1270         int32_t resultLength = 0;
1271         const char *s = next(&resultLength, status);
1272         return setChars(s, resultLength, status);
1273     }
1274 
reset(UErrorCode &)1275     virtual void reset(UErrorCode& /*status*/) {
1276         current = keywords;
1277     }
1278 };
1279 
1280 const char KeywordEnumeration::fgClassID = '\0';
1281 
1282 StringEnumeration *
createKeywords(UErrorCode & status) const1283 Locale::createKeywords(UErrorCode &status) const
1284 {
1285     char keywords[256];
1286     int32_t keywordCapacity = 256;
1287     StringEnumeration *result = NULL;
1288 
1289     const char* variantStart = uprv_strchr(fullName, '@');
1290     const char* assignment = uprv_strchr(fullName, '=');
1291     if(variantStart) {
1292         if(assignment > variantStart) {
1293             int32_t keyLen = locale_getKeywords(variantStart+1, '@', keywords, keywordCapacity, NULL, 0, NULL, FALSE, &status);
1294             if(keyLen) {
1295                 result = new KeywordEnumeration(keywords, keyLen, 0, status);
1296             }
1297         } else {
1298             status = U_INVALID_FORMAT_ERROR;
1299         }
1300     }
1301     return result;
1302 }
1303 
1304 int32_t
getKeywordValue(const char * keywordName,char * buffer,int32_t bufLen,UErrorCode & status) const1305 Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, UErrorCode &status) const
1306 {
1307     return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status);
1308 }
1309 
1310 const char *
getBaseName() const1311 Locale::getBaseName() const
1312 {
1313     // lazy init
1314     UErrorCode status = U_ZERO_ERROR;
1315     // semantically const
1316     if(baseName == 0) {
1317         ((Locale *)this)->baseName = ((Locale *)this)->baseNameBuffer;
1318         int32_t baseNameSize = uloc_getBaseName(fullName, baseName, ULOC_FULLNAME_CAPACITY, &status);
1319         if(baseNameSize >= ULOC_FULLNAME_CAPACITY) {
1320             ((Locale *)this)->baseName = (char *)uprv_malloc(sizeof(char) * baseNameSize + 1);
1321             uloc_getBaseName(fullName, baseName, baseNameSize+1, &status);
1322         }
1323         baseName[baseNameSize] = 0;
1324     }
1325     return baseName;
1326 }
1327 
1328 
1329 //eof
1330 U_NAMESPACE_END
1331