]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/locid.cpp
ICU-400.42.tar.gz
[apple/icu.git] / icuSources / common / locid.cpp
1 /*
2 **********************************************************************
3 * Copyright (C) 1997-2008, 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
88 deleteLocale(void *obj) {
89 delete (U_NAMESPACE_QUALIFIER Locale *) obj;
90 }
91
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 //
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
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 *
262 locale_get_default(void)
263 {
264 U_NAMESPACE_USE
265
266 return Locale::getDefault().getName();
267 }
268
269
270 U_NAMESPACE_BEGIN
271
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
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 */
304 Locale::Locale(Locale::ELocaleType)
305 : UObject(), fullName(fullNameBuffer), baseName(NULL)
306 {
307 setToBogus();
308 }
309
310
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 // If togo_heap could not be created, initialize with default settings.
396 if (togo_heap == NULL) {
397 init(NULL, FALSE);
398 }
399 togo = togo_heap;
400 }
401 else
402 {
403 togo = togo_stack;
404 }
405
406 togo[0] = 0;
407
408 // Now, copy it back.
409 p = togo;
410 if ( lsize != 0 )
411 {
412 uprv_strcpy(p, newLanguage);
413 p += lsize;
414 }
415
416 if ( ( vsize != 0 ) || (csize != 0) ) // at least: __v
417 { // ^
418 *p++ = SEP_CHAR;
419 }
420
421 if ( csize != 0 )
422 {
423 uprv_strcpy(p, newCountry);
424 p += csize;
425 }
426
427 if ( vsize != 0)
428 {
429 *p++ = SEP_CHAR; // at least: __v
430
431 uprv_strncpy(p, newVariant, vsize); // Must use strncpy because
432 p += vsize; // of trimming (above).
433 *p = 0; // terminate
434 }
435
436 if ( ksize != 0)
437 {
438 if (uprv_strchr(newKeywords, '=')) {
439 *p++ = '@'; /* keyword parsing */
440 }
441 else {
442 *p++ = '_'; /* Variant parsing with a script */
443 if ( vsize == 0) {
444 *p++ = '_'; /* No country found */
445 }
446 }
447 uprv_strcpy(p, newKeywords);
448 p += ksize;
449 }
450
451 // Parse it, because for example 'language' might really be a complete
452 // string.
453 init(togo, FALSE);
454
455 if (togo_heap) {
456 uprv_free(togo_heap);
457 }
458 }
459 }
460
461 Locale::Locale(const Locale &other)
462 : UObject(other), fullName(fullNameBuffer), baseName(NULL)
463 {
464 *this = other;
465 }
466
467 Locale &Locale::operator=(const Locale &other)
468 {
469 if (this == &other) {
470 return *this;
471 }
472
473 if (&other == NULL) {
474 this->setToBogus();
475 return *this;
476 }
477
478 /* Free our current storage */
479 if(fullName != fullNameBuffer) {
480 uprv_free(fullName);
481 fullName = fullNameBuffer;
482 }
483
484 /* Allocate the full name if necessary */
485 if(other.fullName != other.fullNameBuffer) {
486 fullName = (char *)uprv_malloc(sizeof(char)*(uprv_strlen(other.fullName)+1));
487 if (fullName == NULL) {
488 return *this;
489 }
490 }
491 /* Copy the full name */
492 uprv_strcpy(fullName, other.fullName);
493
494 /* baseName is the cached result of getBaseName. if 'other' has a
495 baseName and it fits in baseNameBuffer, then copy it. otherwise set
496 it to NULL, and let the user lazy-create it (in getBaseName) if they
497 want it. */
498 if(baseName && baseName != baseNameBuffer) {
499 uprv_free(baseName);
500 }
501 baseName = NULL;
502
503 if(other.baseName == other.baseNameBuffer) {
504 uprv_strcpy(baseNameBuffer, other.baseNameBuffer);
505 baseName = baseNameBuffer;
506 }
507
508 /* Copy the language and country fields */
509 uprv_strcpy(language, other.language);
510 uprv_strcpy(script, other.script);
511 uprv_strcpy(country, other.country);
512
513 /* The variantBegin is an offset into fullName, just copy it */
514 variantBegin = other.variantBegin;
515 fIsBogus = other.fIsBogus;
516 return *this;
517 }
518
519 Locale *
520 Locale::clone() const {
521 return new Locale(*this);
522 }
523
524 UBool
525 Locale::operator==( const Locale& other) const
526 {
527 return (uprv_strcmp(other.fullName, fullName) == 0);
528 }
529
530 /*This function initializes a Locale from a C locale ID*/
531 Locale& Locale::init(const char* localeID, UBool canonicalize)
532 {
533 fIsBogus = FALSE;
534 /* Free our current storage */
535 if(fullName != fullNameBuffer) {
536 uprv_free(fullName);
537 fullName = fullNameBuffer;
538 }
539
540 if(baseName && baseName != baseNameBuffer) {
541 uprv_free(baseName);
542 baseName = NULL;
543 }
544
545 // not a loop:
546 // just an easy way to have a common error-exit
547 // without goto and without another function
548 do {
549 char *separator;
550 char *field[5] = {0};
551 int32_t fieldLen[5] = {0};
552 int32_t fieldIdx;
553 int32_t variantField;
554 int32_t length;
555 UErrorCode err;
556
557 if(localeID == NULL) {
558 // not an error, just set the default locale
559 return *this = getDefault();
560 }
561
562 /* preset all fields to empty */
563 language[0] = script[0] = country[0] = 0;
564
565 // "canonicalize" the locale ID to ICU/Java format
566 err = U_ZERO_ERROR;
567 length = canonicalize ?
568 uloc_canonicalize(localeID, fullName, sizeof(fullNameBuffer), &err) :
569 uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err);
570
571 if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) {
572 /*Go to heap for the fullName if necessary*/
573 fullName = (char *)uprv_malloc(sizeof(char)*(length + 1));
574 if(fullName == 0) {
575 fullName = fullNameBuffer;
576 break; // error: out of memory
577 }
578 err = U_ZERO_ERROR;
579 length = canonicalize ?
580 uloc_canonicalize(localeID, fullName, length+1, &err) :
581 uloc_getName(localeID, fullName, length+1, &err);
582 }
583 if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
584 /* should never occur */
585 break;
586 }
587
588 variantBegin = length;
589
590 /* after uloc_getName/canonicalize() we know that only '_' are separators */
591 separator = field[0] = fullName;
592 fieldIdx = 1;
593 while ((separator = uprv_strchr(field[fieldIdx-1], SEP_CHAR)) && fieldIdx < (int32_t)(sizeof(field)/sizeof(field[0]))-1) {
594 field[fieldIdx] = separator + 1;
595 fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
596 fieldIdx++;
597 }
598 // variant may contain @foo or .foo POSIX cruft; remove it
599 separator = uprv_strchr(field[fieldIdx-1], '@');
600 char* sep2 = uprv_strchr(field[fieldIdx-1], '.');
601 if (separator!=NULL || sep2!=NULL) {
602 if (separator==NULL || (sep2!=NULL && separator > sep2)) {
603 separator = sep2;
604 }
605 fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
606 } else {
607 fieldLen[fieldIdx-1] = length - (int32_t)(field[fieldIdx-1] - fullName);
608 }
609
610 if (fieldLen[0] >= (int32_t)(sizeof(language))
611 || (fieldLen[1] == 4 && fieldLen[2] >= (int32_t)(sizeof(country)))
612 || (fieldLen[1] != 4 && fieldLen[1] >= (int32_t)(sizeof(country))))
613 {
614 break; // error: one of the fields is too long
615 }
616
617 variantField = 2; /* Usually the 2nd one, except when a script is used. */
618 if (fieldLen[0] > 0) {
619 /* We have a language */
620 uprv_memcpy(language, fullName, fieldLen[0]);
621 language[fieldLen[0]] = 0;
622 }
623 if (fieldLen[1] == 4) {
624 /* We have at least a script */
625 uprv_memcpy(script, field[1], fieldLen[1]);
626 script[fieldLen[1]] = 0;
627 variantField = 3;
628 if (fieldLen[2] > 0) {
629 /* We have a country */
630 uprv_memcpy(country, field[2], fieldLen[2]);
631 country[fieldLen[2]] = 0;
632 }
633 }
634 else if (fieldLen[1] > 0) {
635 /* We have a country and no script */
636 uprv_memcpy(country, field[1], fieldLen[1]);
637 country[fieldLen[1]] = 0;
638 }
639 if (variantField > 0 && fieldLen[variantField] > 0) {
640 /* We have a variant */
641 variantBegin = (int32_t)(field[variantField] - fullName);
642 }
643
644 // successful end of init()
645 return *this;
646 } while(0); /*loop doesn't iterate*/
647
648 // when an error occurs, then set this object to "bogus" (there is no UErrorCode here)
649 setToBogus();
650
651 return *this;
652 }
653
654 int32_t
655 Locale::hashCode() const
656 {
657 UHashTok hashKey;
658 hashKey.pointer = fullName;
659 return uhash_hashChars(hashKey);
660 }
661
662 void
663 Locale::setToBogus() {
664 /* Free our current storage */
665 if(fullName != fullNameBuffer) {
666 uprv_free(fullName);
667 fullName = fullNameBuffer;
668 }
669 *fullNameBuffer = 0;
670 *language = 0;
671 *script = 0;
672 *country = 0;
673 fIsBogus = TRUE;
674 }
675
676 const Locale& U_EXPORT2
677 Locale::getDefault()
678 {
679 const Locale *retLocale;
680 UMTX_CHECK(NULL, gDefaultLocale, retLocale);
681 if (retLocale == NULL) {
682 locale_set_default_internal(NULL);
683 umtx_lock(NULL);
684 // Need a mutex in case some other thread set a new
685 // default inbetween when we set and when we get the new default. For
686 // processors with weak memory coherency, we might not otherwise see all
687 // of the newly created new default locale.
688 retLocale = gDefaultLocale;
689 umtx_unlock(NULL);
690 }
691 return *retLocale;
692 }
693
694
695
696 void U_EXPORT2
697 Locale::setDefault( const Locale& newLocale,
698 UErrorCode& status)
699 {
700 if (U_FAILURE(status)) {
701 return;
702 }
703
704 /* Set the default from the full name string of the supplied locale.
705 * This is a convenient way to access the default locale caching mechanisms.
706 */
707 const char *localeID = newLocale.getName();
708 locale_set_default_internal(localeID);
709 }
710
711 Locale U_EXPORT2
712 Locale::createFromName (const char *name)
713 {
714 if (name) {
715 Locale l("");
716 l.init(name, FALSE);
717 return l;
718 }
719 else {
720 return getDefault();
721 }
722 }
723
724 Locale U_EXPORT2
725 Locale::createCanonical(const char* name) {
726 Locale loc("");
727 loc.init(name, TRUE);
728 return loc;
729 }
730
731 const char *
732 Locale::getISO3Language() const
733 {
734 return uloc_getISO3Language(fullName);
735 }
736
737
738 const char *
739 Locale::getISO3Country() const
740 {
741 return uloc_getISO3Country(fullName);
742 }
743
744 /**
745 * Return the LCID value as specified in the "LocaleID" resource for this
746 * locale. The LocaleID must be expressed as a hexadecimal number, from
747 * one to four digits. If the LocaleID resource is not present, or is
748 * in an incorrect format, 0 is returned. The LocaleID is for use in
749 * Windows (it is an LCID), but is available on all platforms.
750 */
751 uint32_t
752 Locale::getLCID() const
753 {
754 return uloc_getLCID(fullName);
755 }
756
757 UnicodeString&
758 Locale::getDisplayLanguage(UnicodeString& dispLang) const
759 {
760 return this->getDisplayLanguage(getDefault(), dispLang);
761 }
762
763 /*We cannot make any assumptions on the size of the output display strings
764 * Yet, since we are calling through to a C API, we need to set limits on
765 * buffer size. For all the following getDisplay functions we first attempt
766 * to fill up a stack allocated buffer. If it is to small we heap allocated
767 * the exact buffer we need copy it to the UnicodeString and delete it*/
768
769 UnicodeString&
770 Locale::getDisplayLanguage(const Locale &displayLocale,
771 UnicodeString &result) const {
772 UChar *buffer;
773 UErrorCode errorCode=U_ZERO_ERROR;
774 int32_t length;
775
776 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
777 if(buffer==0) {
778 result.truncate(0);
779 return result;
780 }
781
782 length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
783 buffer, result.getCapacity(),
784 &errorCode);
785 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
786
787 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
788 buffer=result.getBuffer(length);
789 if(buffer==0) {
790 result.truncate(0);
791 return result;
792 }
793 errorCode=U_ZERO_ERROR;
794 length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
795 buffer, result.getCapacity(),
796 &errorCode);
797 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
798 }
799
800 return result;
801 }
802
803 UnicodeString&
804 Locale::getDisplayScript(UnicodeString& dispScript) const
805 {
806 return this->getDisplayScript(getDefault(), dispScript);
807 }
808
809 UnicodeString&
810 Locale::getDisplayScript(const Locale &displayLocale,
811 UnicodeString &result) const {
812 UChar *buffer;
813 UErrorCode errorCode=U_ZERO_ERROR;
814 int32_t length;
815
816 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
817 if(buffer==0) {
818 result.truncate(0);
819 return result;
820 }
821
822 length=uloc_getDisplayScript(fullName, displayLocale.fullName,
823 buffer, result.getCapacity(),
824 &errorCode);
825 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
826
827 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
828 buffer=result.getBuffer(length);
829 if(buffer==0) {
830 result.truncate(0);
831 return result;
832 }
833 errorCode=U_ZERO_ERROR;
834 length=uloc_getDisplayScript(fullName, displayLocale.fullName,
835 buffer, result.getCapacity(),
836 &errorCode);
837 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
838 }
839
840 return result;
841 }
842
843 UnicodeString&
844 Locale::getDisplayCountry(UnicodeString& dispCntry) const
845 {
846 return this->getDisplayCountry(getDefault(), dispCntry);
847 }
848
849 UnicodeString&
850 Locale::getDisplayCountry(const Locale &displayLocale,
851 UnicodeString &result) const {
852 UChar *buffer;
853 UErrorCode errorCode=U_ZERO_ERROR;
854 int32_t length;
855
856 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
857 if(buffer==0) {
858 result.truncate(0);
859 return result;
860 }
861
862 length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
863 buffer, result.getCapacity(),
864 &errorCode);
865 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
866
867 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
868 buffer=result.getBuffer(length);
869 if(buffer==0) {
870 result.truncate(0);
871 return result;
872 }
873 errorCode=U_ZERO_ERROR;
874 length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
875 buffer, result.getCapacity(),
876 &errorCode);
877 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
878 }
879
880 return result;
881 }
882
883 UnicodeString&
884 Locale::getDisplayVariant(UnicodeString& dispVar) const
885 {
886 return this->getDisplayVariant(getDefault(), dispVar);
887 }
888
889 UnicodeString&
890 Locale::getDisplayVariant(const Locale &displayLocale,
891 UnicodeString &result) const {
892 UChar *buffer;
893 UErrorCode errorCode=U_ZERO_ERROR;
894 int32_t length;
895
896 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
897 if(buffer==0) {
898 result.truncate(0);
899 return result;
900 }
901
902 length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
903 buffer, result.getCapacity(),
904 &errorCode);
905 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
906
907 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
908 buffer=result.getBuffer(length);
909 if(buffer==0) {
910 result.truncate(0);
911 return result;
912 }
913 errorCode=U_ZERO_ERROR;
914 length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
915 buffer, result.getCapacity(),
916 &errorCode);
917 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
918 }
919
920 return result;
921 }
922
923 UnicodeString&
924 Locale::getDisplayName( UnicodeString& name ) const
925 {
926 return this->getDisplayName(getDefault(), name);
927 }
928
929 UnicodeString&
930 Locale::getDisplayName(const Locale &displayLocale,
931 UnicodeString &result) const {
932 UChar *buffer;
933 UErrorCode errorCode=U_ZERO_ERROR;
934 int32_t length;
935
936 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
937 if(buffer==0) {
938 result.truncate(0);
939 return result;
940 }
941
942 length=uloc_getDisplayName(fullName, displayLocale.fullName,
943 buffer, result.getCapacity(),
944 &errorCode);
945 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
946
947 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
948 buffer=result.getBuffer(length);
949 if(buffer==0) {
950 result.truncate(0);
951 return result;
952 }
953 errorCode=U_ZERO_ERROR;
954 length=uloc_getDisplayName(fullName, displayLocale.fullName,
955 buffer, result.getCapacity(),
956 &errorCode);
957 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
958 }
959
960 return result;
961 }
962 const Locale* U_EXPORT2
963 Locale::getAvailableLocales(int32_t& count)
964 {
965 // for now, there is a hardcoded list, so just walk through that list and set it up.
966 UBool needInit;
967 UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
968
969 if (needInit) {
970 int32_t locCount = uloc_countAvailable();
971 Locale *newLocaleList = 0;
972 if(locCount) {
973 newLocaleList = new Locale[locCount];
974 }
975 if (newLocaleList == NULL) {
976 count = 0;
977 return NULL;
978 }
979
980 count = locCount;
981
982 while(--locCount >= 0) {
983 newLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount));
984 }
985
986 umtx_lock(NULL);
987 if(availableLocaleList == 0) {
988 availableLocaleListCount = count;
989 availableLocaleList = newLocaleList;
990 newLocaleList = NULL;
991 ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
992 }
993 umtx_unlock(NULL);
994 delete []newLocaleList;
995 }
996 count = availableLocaleListCount;
997 return availableLocaleList;
998 }
999
1000 const char* const* U_EXPORT2 Locale::getISOCountries()
1001 {
1002 return uloc_getISOCountries();
1003 }
1004
1005 const char* const* U_EXPORT2 Locale::getISOLanguages()
1006 {
1007 return uloc_getISOLanguages();
1008 }
1009
1010 // Set the locale's data based on a posix id.
1011 void Locale::setFromPOSIXID(const char *posixID)
1012 {
1013 init(posixID, TRUE);
1014 }
1015
1016 const Locale & U_EXPORT2
1017 Locale::getEnglish(void)
1018 {
1019 return getLocale(eENGLISH);
1020 }
1021
1022 const Locale & U_EXPORT2
1023 Locale::getFrench(void)
1024 {
1025 return getLocale(eFRENCH);
1026 }
1027
1028 const Locale & U_EXPORT2
1029 Locale::getGerman(void)
1030 {
1031 return getLocale(eGERMAN);
1032 }
1033
1034 const Locale & U_EXPORT2
1035 Locale::getItalian(void)
1036 {
1037 return getLocale(eITALIAN);
1038 }
1039
1040 const Locale & U_EXPORT2
1041 Locale::getJapanese(void)
1042 {
1043 return getLocale(eJAPANESE);
1044 }
1045
1046 const Locale & U_EXPORT2
1047 Locale::getKorean(void)
1048 {
1049 return getLocale(eKOREAN);
1050 }
1051
1052 const Locale & U_EXPORT2
1053 Locale::getChinese(void)
1054 {
1055 return getLocale(eCHINESE);
1056 }
1057
1058 const Locale & U_EXPORT2
1059 Locale::getSimplifiedChinese(void)
1060 {
1061 return getLocale(eCHINA);
1062 }
1063
1064 const Locale & U_EXPORT2
1065 Locale::getTraditionalChinese(void)
1066 {
1067 return getLocale(eTAIWAN);
1068 }
1069
1070
1071 const Locale & U_EXPORT2
1072 Locale::getFrance(void)
1073 {
1074 return getLocale(eFRANCE);
1075 }
1076
1077 const Locale & U_EXPORT2
1078 Locale::getGermany(void)
1079 {
1080 return getLocale(eGERMANY);
1081 }
1082
1083 const Locale & U_EXPORT2
1084 Locale::getItaly(void)
1085 {
1086 return getLocale(eITALY);
1087 }
1088
1089 const Locale & U_EXPORT2
1090 Locale::getJapan(void)
1091 {
1092 return getLocale(eJAPAN);
1093 }
1094
1095 const Locale & U_EXPORT2
1096 Locale::getKorea(void)
1097 {
1098 return getLocale(eKOREA);
1099 }
1100
1101 const Locale & U_EXPORT2
1102 Locale::getChina(void)
1103 {
1104 return getLocale(eCHINA);
1105 }
1106
1107 const Locale & U_EXPORT2
1108 Locale::getPRC(void)
1109 {
1110 return getLocale(eCHINA);
1111 }
1112
1113 const Locale & U_EXPORT2
1114 Locale::getTaiwan(void)
1115 {
1116 return getLocale(eTAIWAN);
1117 }
1118
1119 const Locale & U_EXPORT2
1120 Locale::getUK(void)
1121 {
1122 return getLocale(eUK);
1123 }
1124
1125 const Locale & U_EXPORT2
1126 Locale::getUS(void)
1127 {
1128 return getLocale(eUS);
1129 }
1130
1131 const Locale & U_EXPORT2
1132 Locale::getCanada(void)
1133 {
1134 return getLocale(eCANADA);
1135 }
1136
1137 const Locale & U_EXPORT2
1138 Locale::getCanadaFrench(void)
1139 {
1140 return getLocale(eCANADA_FRENCH);
1141 }
1142
1143 const Locale &
1144 Locale::getLocale(int locid)
1145 {
1146 Locale *localeCache = getLocaleCache();
1147 U_ASSERT((locid < eMAX_LOCALES)&&(locid>=0));
1148 if (localeCache == NULL) {
1149 // Failure allocating the locale cache.
1150 // The best we can do is return a NULL reference.
1151 locid = 0;
1152 }
1153 return localeCache[locid]; /*operating on NULL*/
1154 }
1155
1156 /*
1157 This function is defined this way in order to get around static
1158 initialization and static destruction.
1159 */
1160 Locale *
1161 Locale::getLocaleCache(void)
1162 {
1163 umtx_lock(NULL);
1164 UBool needInit = (gLocaleCache == NULL);
1165 umtx_unlock(NULL);
1166
1167 if (needInit) {
1168 Locale *tLocaleCache = new Locale[(int)eMAX_LOCALES];
1169 if (tLocaleCache == NULL) {
1170 return NULL;
1171 }
1172 tLocaleCache[eENGLISH] = Locale("en");
1173 tLocaleCache[eFRENCH] = Locale("fr");
1174 tLocaleCache[eGERMAN] = Locale("de");
1175 tLocaleCache[eITALIAN] = Locale("it");
1176 tLocaleCache[eJAPANESE] = Locale("ja");
1177 tLocaleCache[eKOREAN] = Locale("ko");
1178 tLocaleCache[eCHINESE] = Locale("zh");
1179 tLocaleCache[eFRANCE] = Locale("fr", "FR");
1180 tLocaleCache[eGERMANY] = Locale("de", "DE");
1181 tLocaleCache[eITALY] = Locale("it", "IT");
1182 tLocaleCache[eJAPAN] = Locale("ja", "JP");
1183 tLocaleCache[eKOREA] = Locale("ko", "KR");
1184 tLocaleCache[eCHINA] = Locale("zh", "CN");
1185 tLocaleCache[eTAIWAN] = Locale("zh", "TW");
1186 tLocaleCache[eUK] = Locale("en", "GB");
1187 tLocaleCache[eUS] = Locale("en", "US");
1188 tLocaleCache[eCANADA] = Locale("en", "CA");
1189 tLocaleCache[eCANADA_FRENCH] = Locale("fr", "CA");
1190
1191 umtx_lock(NULL);
1192 if (gLocaleCache == NULL) {
1193 gLocaleCache = tLocaleCache;
1194 tLocaleCache = NULL;
1195 ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
1196 }
1197 umtx_unlock(NULL);
1198 if (tLocaleCache) {
1199 delete [] tLocaleCache; // Fancy array delete will destruct each member.
1200 }
1201 }
1202 return gLocaleCache;
1203 }
1204
1205 class KeywordEnumeration : public StringEnumeration {
1206 private:
1207 char *keywords;
1208 char *current;
1209 int32_t length;
1210 UnicodeString currUSKey;
1211 static const char fgClassID;/* Warning this is used beyond the typical RTTI usage. */
1212
1213 public:
1214 static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; }
1215 virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); }
1216 public:
1217 KeywordEnumeration(const char *keys, int32_t keywordLen, int32_t currentIndex, UErrorCode &status)
1218 : keywords((char *)&fgClassID), current((char *)&fgClassID), length(0) {
1219 if(U_SUCCESS(status) && keywordLen != 0) {
1220 if(keys == NULL || keywordLen < 0) {
1221 status = U_ILLEGAL_ARGUMENT_ERROR;
1222 } else {
1223 keywords = (char *)uprv_malloc(keywordLen+1);
1224 if (keywords == NULL) {
1225 status = U_MEMORY_ALLOCATION_ERROR;
1226 }
1227 else {
1228 uprv_memcpy(keywords, keys, keywordLen);
1229 keywords[keywordLen] = 0;
1230 current = keywords + currentIndex;
1231 length = keywordLen;
1232 }
1233 }
1234 }
1235 }
1236
1237 virtual ~KeywordEnumeration() {
1238 uprv_free(keywords);
1239 }
1240
1241 virtual StringEnumeration * clone() const
1242 {
1243 UErrorCode status = U_ZERO_ERROR;
1244 return new KeywordEnumeration(keywords, length, (int32_t)(current - keywords), status);
1245 }
1246
1247 virtual int32_t count(UErrorCode &/*status*/) const {
1248 char *kw = keywords;
1249 int32_t result = 0;
1250 while(*kw) {
1251 result++;
1252 kw += uprv_strlen(kw)+1;
1253 }
1254 return result;
1255 }
1256
1257 virtual const char* next(int32_t* resultLength, UErrorCode& status) {
1258 const char* result;
1259 int32_t len;
1260 if(U_SUCCESS(status) && *current != 0) {
1261 result = current;
1262 len = (int32_t)uprv_strlen(current);
1263 current += len+1;
1264 if(resultLength != NULL) {
1265 *resultLength = len;
1266 }
1267 } else {
1268 if(resultLength != NULL) {
1269 *resultLength = 0;
1270 }
1271 result = NULL;
1272 }
1273 return result;
1274 }
1275
1276 virtual const UnicodeString* snext(UErrorCode& status) {
1277 int32_t resultLength = 0;
1278 const char *s = next(&resultLength, status);
1279 return setChars(s, resultLength, status);
1280 }
1281
1282 virtual void reset(UErrorCode& /*status*/) {
1283 current = keywords;
1284 }
1285 };
1286
1287 const char KeywordEnumeration::fgClassID = '\0';
1288
1289 StringEnumeration *
1290 Locale::createKeywords(UErrorCode &status) const
1291 {
1292 char keywords[256];
1293 int32_t keywordCapacity = 256;
1294 StringEnumeration *result = NULL;
1295
1296 const char* variantStart = uprv_strchr(fullName, '@');
1297 const char* assignment = uprv_strchr(fullName, '=');
1298 if(variantStart) {
1299 if(assignment > variantStart) {
1300 int32_t keyLen = locale_getKeywords(variantStart+1, '@', keywords, keywordCapacity, NULL, 0, NULL, FALSE, &status);
1301 if(keyLen) {
1302 result = new KeywordEnumeration(keywords, keyLen, 0, status);
1303 }
1304 } else {
1305 status = U_INVALID_FORMAT_ERROR;
1306 }
1307 }
1308 return result;
1309 }
1310
1311 int32_t
1312 Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, UErrorCode &status) const
1313 {
1314 return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status);
1315 }
1316
1317 const char *
1318 Locale::getBaseName() const
1319 {
1320 // lazy init
1321 UErrorCode status = U_ZERO_ERROR;
1322 // semantically const
1323 if(baseName == 0) {
1324 ((Locale *)this)->baseName = ((Locale *)this)->baseNameBuffer;
1325 int32_t baseNameSize = uloc_getBaseName(fullName, baseName, ULOC_FULLNAME_CAPACITY, &status);
1326 if(baseNameSize >= ULOC_FULLNAME_CAPACITY) {
1327 ((Locale *)this)->baseName = (char *)uprv_malloc(sizeof(char) * baseNameSize + 1);
1328 if (baseName == NULL) {
1329 return baseName;
1330 }
1331 uloc_getBaseName(fullName, baseName, baseNameSize+1, &status);
1332 }
1333 baseName[baseNameSize] = 0;
1334 }
1335 return baseName;
1336 }
1337
1338
1339 //eof
1340 U_NAMESPACE_END