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