]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/locid.cpp
ICU-400.42.tar.gz
[apple/icu.git] / icuSources / common / locid.cpp
CommitLineData
b75a7d8f
A
1/*
2 **********************************************************************
46f4442e 3 * Copyright (C) 1997-2008, International Business Machines
b75a7d8f
A
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
374ca955 14* 02/11/97 aliu Changed gLocPath to fgDataDirectory and added
b75a7d8f 15* methods to get and set it.
374ca955 16* 04/02/97 aliu Made operator!= inline; fixed return value
b75a7d8f
A
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
374ca955
A
42#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
43
46f4442e 44static U_NAMESPACE_QUALIFIER Locale* availableLocaleList = NULL;
b75a7d8f
A
45static int32_t availableLocaleListCount;
46typedef 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
374ca955
A
72U_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
46f4442e
A
79static U_NAMESPACE_QUALIFIER Locale *gLocaleCache = NULL;
80static U_NAMESPACE_QUALIFIER Locale *gDefaultLocale = NULL;
81static UHashtable *gDefaultLocalesHashT = NULL;
374ca955
A
82
83U_CDECL_BEGIN
84//
85// Deleter function for Locales owned by the default Locale hash table/
86//
87static void U_CALLCONV
88deleteLocale(void *obj) {
46f4442e 89 delete (U_NAMESPACE_QUALIFIER Locale *) obj;
374ca955 90}
b75a7d8f 91
374ca955 92static UBool U_CALLCONV locale_cleanup(void)
b75a7d8f
A
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 }
374ca955
A
106
107 if (gDefaultLocalesHashT) {
108 uhash_close(gDefaultLocalesHashT); // Automatically deletes all elements, using deleter func.
109 gDefaultLocalesHashT = NULL;
b75a7d8f 110 }
46f4442e
A
111 else if (gDefaultLocale) {
112 // The cache wasn't created, and only one default locale was created.
113 delete gDefaultLocale;
114 }
374ca955
A
115 gDefaultLocale = NULL;
116
b75a7d8f
A
117 return TRUE;
118}
374ca955 119U_CDECL_END
b75a7d8f
A
120
121U_NAMESPACE_BEGIN
374ca955
A
122//
123// locale_set_default_internal.
124//
b75a7d8f
A
125void locale_set_default_internal(const char *id)
126{
374ca955
A
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) {
b75a7d8f
A
135 umtx_lock(NULL);
136 id = uprv_getDefaultLocaleID();
137 umtx_unlock(NULL);
374ca955
A
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);
b75a7d8f 152 }
374ca955
A
153 localeNameBuf[sizeof(localeNameBuf)-1] = 0; // Force null termination in event of
154 // a long name filling the buffer.
155 // (long names are truncated.)
b75a7d8f 156
374ca955 157 // Lazy creation of the hash table itself, if needed.
46f4442e
A
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);
374ca955
A
188 if (hashTableNeedsInit) {
189 status = U_ZERO_ERROR;
73c04bcf 190 UHashtable *tHashTable = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
374ca955
A
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);
374ca955 199 } else {
374ca955 200 uhash_close(tHashTable);
46f4442e 201 hashTableNeedsInit = FALSE;
374ca955 202 }
46f4442e 203 umtx_unlock(NULL);
374ca955
A
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);
46f4442e 229 Locale *hashTableVal = (Locale *)uhash_get(gDefaultLocalesHashT, key);
374ca955 230 if (hashTableVal == NULL) {
46f4442e
A
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 }
374ca955
A
236 uhash_put(gDefaultLocalesHashT, (void *)key, newDefault, &status);
237 gDefaultLocale = newDefault;
374ca955
A
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
374ca955
A
245 delete newDefault;
246 }
46f4442e 247 umtx_unlock(NULL);
374ca955 248 }
b75a7d8f
A
249}
250U_NAMESPACE_END
251
252/* sfb 07/21/99 */
253U_CFUNC void
254locale_set_default(const char *id)
255{
256 U_NAMESPACE_USE
257 locale_set_default_internal(id);
258}
259/* end */
260
261U_CFUNC const char *
262locale_get_default(void)
263{
264 U_NAMESPACE_USE
265
266 return Locale::getDefault().getName();
267}
268
269
270U_NAMESPACE_BEGIN
271
46f4442e
A
272UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)
273
b75a7d8f
A
274/*Character separating the posix id fields*/
275// '_'
276// In the platform codepage.
277#define SEP_CHAR '_'
278
279Locale::~Locale()
374ca955 280{
b75a7d8f 281 /*if fullName is on the heap, we free it*/
374ca955 282 if (fullName != fullNameBuffer)
b75a7d8f
A
283 {
284 uprv_free(fullName);
285 fullName = NULL;
286 }
374ca955
A
287 if (baseName && baseName != baseNameBuffer) {
288 uprv_free(baseName);
289 baseName = NULL;
290 }
b75a7d8f
A
291}
292
293Locale::Locale()
374ca955 294 : UObject(), fullName(fullNameBuffer), baseName(NULL)
b75a7d8f 295{
374ca955 296 init(NULL, FALSE);
b75a7d8f
A
297}
298
374ca955
A
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 */
304Locale::Locale(Locale::ELocaleType)
305 : UObject(), fullName(fullNameBuffer), baseName(NULL)
b75a7d8f
A
306{
307 setToBogus();
308}
309
310
374ca955
A
311Locale::Locale( const char * newLanguage,
312 const char * newCountry,
313 const char * newVariant,
314 const char * newKeywords)
315 : UObject(), fullName(fullNameBuffer), baseName(NULL)
b75a7d8f
A
316{
317 if( (newLanguage==NULL) && (newCountry == NULL) && (newVariant == NULL) )
318 {
374ca955 319 init(NULL, FALSE); /* shortcut */
b75a7d8f
A
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;
374ca955 330 int32_t ksize = 0;
b75a7d8f
A
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 }
374ca955 357
b75a7d8f
A
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 {
374ca955 374 size += 2; // at least: __v
b75a7d8f
A
375 }
376 else if ( csize > 0 )
377 {
374ca955
A
378 size += 1; // at least: _v
379 }
380
381 if ( newKeywords != NULL)
382 {
383 ksize = (int32_t)uprv_strlen(newKeywords);
384 size += ksize + 1;
b75a7d8f
A
385 }
386
374ca955 387
b75a7d8f
A
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*/
73c04bcf 392 if (size >= ULOC_FULLNAME_CAPACITY)
b75a7d8f
A
393 {
394 togo_heap = (char *)uprv_malloc(sizeof(char)*(size+1));
46f4442e
A
395 // If togo_heap could not be created, initialize with default settings.
396 if (togo_heap == NULL) {
397 init(NULL, FALSE);
398 }
b75a7d8f
A
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 )
374ca955 422 {
b75a7d8f
A
423 uprv_strcpy(p, newCountry);
424 p += csize;
425 }
426
427 if ( vsize != 0)
428 {
429 *p++ = SEP_CHAR; // at least: __v
430
374ca955 431 uprv_strncpy(p, newVariant, vsize); // Must use strncpy because
b75a7d8f
A
432 p += vsize; // of trimming (above).
433 *p = 0; // terminate
434 }
435
374ca955
A
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
b75a7d8f
A
451 // Parse it, because for example 'language' might really be a complete
452 // string.
374ca955 453 init(togo, FALSE);
b75a7d8f
A
454
455 if (togo_heap) {
456 uprv_free(togo_heap);
457 }
458 }
459}
460
461Locale::Locale(const Locale &other)
374ca955 462 : UObject(other), fullName(fullNameBuffer), baseName(NULL)
b75a7d8f
A
463{
464 *this = other;
465}
466
467Locale &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));
46f4442e
A
487 if (fullName == NULL) {
488 return *this;
489 }
b75a7d8f 490 }
b75a7d8f
A
491 /* Copy the full name */
492 uprv_strcpy(fullName, other.fullName);
493
374ca955
A
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
b75a7d8f
A
508 /* Copy the language and country fields */
509 uprv_strcpy(language, other.language);
374ca955 510 uprv_strcpy(script, other.script);
b75a7d8f
A
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
374ca955
A
519Locale *
520Locale::clone() const {
521 return new Locale(*this);
522}
523
b75a7d8f
A
524UBool
525Locale::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*/
374ca955 531Locale& Locale::init(const char* localeID, UBool canonicalize)
b75a7d8f
A
532{
533 fIsBogus = FALSE;
534 /* Free our current storage */
535 if(fullName != fullNameBuffer) {
536 uprv_free(fullName);
537 fullName = fullNameBuffer;
538 }
539
374ca955
A
540 if(baseName && baseName != baseNameBuffer) {
541 uprv_free(baseName);
542 baseName = NULL;
543 }
544
b75a7d8f
A
545 // not a loop:
546 // just an easy way to have a common error-exit
547 // without goto and without another function
548 do {
374ca955
A
549 char *separator;
550 char *field[5] = {0};
551 int32_t fieldLen[5] = {0};
552 int32_t fieldIdx;
553 int32_t variantField;
b75a7d8f
A
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
374ca955
A
562 /* preset all fields to empty */
563 language[0] = script[0] = country[0] = 0;
564
b75a7d8f
A
565 // "canonicalize" the locale ID to ICU/Java format
566 err = U_ZERO_ERROR;
374ca955
A
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)) {
b75a7d8f
A
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;
374ca955
A
579 length = canonicalize ?
580 uloc_canonicalize(localeID, fullName, length+1, &err) :
581 uloc_getName(localeID, fullName, length+1, &err);
b75a7d8f
A
582 }
583 if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
584 /* should never occur */
585 break;
586 }
587
374ca955 588 variantBegin = length;
b75a7d8f 589
374ca955
A
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;
73c04bcf 595 fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
374ca955
A
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;
b75a7d8f 604 }
73c04bcf 605 fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
b75a7d8f 606 } else {
374ca955
A
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;
b75a7d8f 632 }
374ca955
A
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);
b75a7d8f
A
642 }
643
644 // successful end of init()
645 return *this;
73c04bcf 646 } while(0); /*loop doesn't iterate*/
b75a7d8f
A
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
654int32_t
374ca955 655Locale::hashCode() const
b75a7d8f
A
656{
657 UHashTok hashKey;
658 hashKey.pointer = fullName;
659 return uhash_hashChars(hashKey);
660}
661
374ca955 662void
b75a7d8f 663Locale::setToBogus() {
374ca955
A
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;
b75a7d8f
A
674}
675
374ca955
A
676const Locale& U_EXPORT2
677Locale::getDefault()
b75a7d8f 678{
374ca955 679 const Locale *retLocale;
46f4442e 680 UMTX_CHECK(NULL, gDefaultLocale, retLocale);
374ca955
A
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);
b75a7d8f 690 }
374ca955 691 return *retLocale;
b75a7d8f
A
692}
693
374ca955
A
694
695
696void U_EXPORT2
697Locale::setDefault( const Locale& newLocale,
698 UErrorCode& status)
b75a7d8f 699{
374ca955 700 if (U_FAILURE(status)) {
b75a7d8f 701 return;
374ca955
A
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);
b75a7d8f
A
709}
710
374ca955 711Locale U_EXPORT2
b75a7d8f
A
712Locale::createFromName (const char *name)
713{
714 if (name) {
374ca955
A
715 Locale l("");
716 l.init(name, FALSE);
b75a7d8f
A
717 return l;
718 }
719 else {
720 return getDefault();
721 }
722}
723
374ca955
A
724Locale U_EXPORT2
725Locale::createCanonical(const char* name) {
726 Locale loc("");
727 loc.init(name, TRUE);
728 return loc;
729}
b75a7d8f
A
730
731const char *
732Locale::getISO3Language() const
733{
734 return uloc_getISO3Language(fullName);
735}
736
737
738const char *
739Locale::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 */
374ca955 751uint32_t
b75a7d8f
A
752Locale::getLCID() const
753{
754 return uloc_getLCID(fullName);
755}
756
374ca955 757UnicodeString&
b75a7d8f
A
758Locale::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
769UnicodeString&
770Locale::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);
73c04bcf 785 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
b75a7d8f
A
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);
73c04bcf 797 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
b75a7d8f
A
798 }
799
800 return result;
801}
802
374ca955
A
803UnicodeString&
804Locale::getDisplayScript(UnicodeString& dispScript) const
805{
806 return this->getDisplayScript(getDefault(), dispScript);
807}
808
809UnicodeString&
810Locale::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);
73c04bcf 825 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
374ca955
A
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);
73c04bcf 837 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
374ca955
A
838 }
839
840 return result;
841}
842
843UnicodeString&
b75a7d8f
A
844Locale::getDisplayCountry(UnicodeString& dispCntry) const
845{
846 return this->getDisplayCountry(getDefault(), dispCntry);
847}
848
849UnicodeString&
850Locale::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);
73c04bcf 865 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
b75a7d8f
A
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);
73c04bcf 877 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
b75a7d8f
A
878 }
879
880 return result;
881}
882
374ca955 883UnicodeString&
b75a7d8f
A
884Locale::getDisplayVariant(UnicodeString& dispVar) const
885{
886 return this->getDisplayVariant(getDefault(), dispVar);
887}
888
889UnicodeString&
890Locale::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);
73c04bcf 905 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
b75a7d8f
A
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);
73c04bcf 917 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
b75a7d8f
A
918 }
919
920 return result;
921}
922
374ca955 923UnicodeString&
b75a7d8f
A
924Locale::getDisplayName( UnicodeString& name ) const
925{
926 return this->getDisplayName(getDefault(), name);
927}
928
929UnicodeString&
930Locale::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);
73c04bcf 945 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
b75a7d8f
A
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);
73c04bcf 957 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
b75a7d8f
A
958 }
959
960 return result;
961}
374ca955
A
962const Locale* U_EXPORT2
963Locale::getAvailableLocales(int32_t& count)
b75a7d8f
A
964{
965 // for now, there is a hardcoded list, so just walk through that list and set it up.
46f4442e
A
966 UBool needInit;
967 UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
374ca955 968
b75a7d8f
A
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) {
73c04bcf 976 count = 0;
b75a7d8f
A
977 return NULL;
978 }
374ca955 979
b75a7d8f 980 count = locCount;
374ca955 981
b75a7d8f
A
982 while(--locCount >= 0) {
983 newLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount));
984 }
374ca955 985
b75a7d8f
A
986 umtx_lock(NULL);
987 if(availableLocaleList == 0) {
988 availableLocaleListCount = count;
989 availableLocaleList = newLocaleList;
990 newLocaleList = NULL;
374ca955 991 ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
b75a7d8f
A
992 }
993 umtx_unlock(NULL);
994 delete []newLocaleList;
995 }
996 count = availableLocaleListCount;
997 return availableLocaleList;
998}
999
374ca955 1000const char* const* U_EXPORT2 Locale::getISOCountries()
b75a7d8f
A
1001{
1002 return uloc_getISOCountries();
1003}
1004
374ca955 1005const char* const* U_EXPORT2 Locale::getISOLanguages()
b75a7d8f
A
1006{
1007 return uloc_getISOLanguages();
1008}
1009
374ca955 1010// Set the locale's data based on a posix id.
b75a7d8f
A
1011void Locale::setFromPOSIXID(const char *posixID)
1012{
374ca955 1013 init(posixID, TRUE);
b75a7d8f
A
1014}
1015
374ca955 1016const Locale & U_EXPORT2
b75a7d8f
A
1017Locale::getEnglish(void)
1018{
1019 return getLocale(eENGLISH);
1020}
1021
374ca955 1022const Locale & U_EXPORT2
b75a7d8f
A
1023Locale::getFrench(void)
1024{
1025 return getLocale(eFRENCH);
1026}
1027
374ca955 1028const Locale & U_EXPORT2
b75a7d8f
A
1029Locale::getGerman(void)
1030{
1031 return getLocale(eGERMAN);
1032}
1033
374ca955 1034const Locale & U_EXPORT2
b75a7d8f
A
1035Locale::getItalian(void)
1036{
1037 return getLocale(eITALIAN);
1038}
1039
374ca955 1040const Locale & U_EXPORT2
b75a7d8f
A
1041Locale::getJapanese(void)
1042{
1043 return getLocale(eJAPANESE);
1044}
1045
374ca955 1046const Locale & U_EXPORT2
b75a7d8f
A
1047Locale::getKorean(void)
1048{
1049 return getLocale(eKOREAN);
1050}
1051
374ca955 1052const Locale & U_EXPORT2
b75a7d8f
A
1053Locale::getChinese(void)
1054{
1055 return getLocale(eCHINESE);
1056}
1057
374ca955 1058const Locale & U_EXPORT2
b75a7d8f
A
1059Locale::getSimplifiedChinese(void)
1060{
1061 return getLocale(eCHINA);
1062}
1063
374ca955 1064const Locale & U_EXPORT2
b75a7d8f
A
1065Locale::getTraditionalChinese(void)
1066{
1067 return getLocale(eTAIWAN);
1068}
1069
1070
374ca955 1071const Locale & U_EXPORT2
b75a7d8f
A
1072Locale::getFrance(void)
1073{
1074 return getLocale(eFRANCE);
1075}
1076
374ca955 1077const Locale & U_EXPORT2
b75a7d8f
A
1078Locale::getGermany(void)
1079{
1080 return getLocale(eGERMANY);
1081}
1082
374ca955 1083const Locale & U_EXPORT2
b75a7d8f
A
1084Locale::getItaly(void)
1085{
1086 return getLocale(eITALY);
1087}
1088
374ca955 1089const Locale & U_EXPORT2
b75a7d8f
A
1090Locale::getJapan(void)
1091{
1092 return getLocale(eJAPAN);
1093}
1094
374ca955 1095const Locale & U_EXPORT2
b75a7d8f
A
1096Locale::getKorea(void)
1097{
1098 return getLocale(eKOREA);
1099}
1100
374ca955 1101const Locale & U_EXPORT2
b75a7d8f
A
1102Locale::getChina(void)
1103{
1104 return getLocale(eCHINA);
1105}
1106
374ca955 1107const Locale & U_EXPORT2
b75a7d8f
A
1108Locale::getPRC(void)
1109{
1110 return getLocale(eCHINA);
1111}
1112
374ca955 1113const Locale & U_EXPORT2
b75a7d8f
A
1114Locale::getTaiwan(void)
1115{
1116 return getLocale(eTAIWAN);
1117}
1118
374ca955 1119const Locale & U_EXPORT2
b75a7d8f
A
1120Locale::getUK(void)
1121{
1122 return getLocale(eUK);
1123}
1124
374ca955 1125const Locale & U_EXPORT2
b75a7d8f
A
1126Locale::getUS(void)
1127{
1128 return getLocale(eUS);
1129}
1130
374ca955 1131const Locale & U_EXPORT2
b75a7d8f
A
1132Locale::getCanada(void)
1133{
1134 return getLocale(eCANADA);
1135}
1136
374ca955 1137const Locale & U_EXPORT2
b75a7d8f
A
1138Locale::getCanadaFrench(void)
1139{
1140 return getLocale(eCANADA_FRENCH);
1141}
1142
1143const Locale &
1144Locale::getLocale(int locid)
1145{
1146 Locale *localeCache = getLocaleCache();
73c04bcf 1147 U_ASSERT((locid < eMAX_LOCALES)&&(locid>=0));
b75a7d8f
A
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 }
73c04bcf 1153 return localeCache[locid]; /*operating on NULL*/
b75a7d8f
A
1154}
1155
1156/*
1157This function is defined this way in order to get around static
1158initialization and static destruction.
1159 */
1160Locale *
1161Locale::getLocaleCache(void)
1162{
1163 umtx_lock(NULL);
1164 UBool needInit = (gLocaleCache == NULL);
1165 umtx_unlock(NULL);
374ca955 1166
b75a7d8f 1167 if (needInit) {
374ca955 1168 Locale *tLocaleCache = new Locale[(int)eMAX_LOCALES];
b75a7d8f
A
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");
374ca955 1190
b75a7d8f
A
1191 umtx_lock(NULL);
1192 if (gLocaleCache == NULL) {
1193 gLocaleCache = tLocaleCache;
1194 tLocaleCache = NULL;
374ca955 1195 ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
b75a7d8f
A
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
374ca955
A
1205class KeywordEnumeration : public StringEnumeration {
1206private:
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
1213public:
1214 static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; }
1215 virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); }
1216public:
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;
73c04bcf 1262 len = (int32_t)uprv_strlen(current);
374ca955
A
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
1287const char KeywordEnumeration::fgClassID = '\0';
1288
1289StringEnumeration *
1290Locale::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
1311int32_t
1312Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, UErrorCode &status) const
1313{
1314 return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status);
1315}
1316
1317const char *
1318Locale::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);
46f4442e
A
1328 if (baseName == NULL) {
1329 return baseName;
1330 }
374ca955
A
1331 uloc_getBaseName(fullName, baseName, baseNameSize+1, &status);
1332 }
1333 baseName[baseNameSize] = 0;
1334 }
1335 return baseName;
1336}
1337
1338
b75a7d8f
A
1339//eof
1340U_NAMESPACE_END