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