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 44static U_NAMESPACE_QUALIFIER Locale* availableLocaleList = NULL; 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 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 79static U_NAMESPACE_QUALIFIER Locale *gLocaleCache = NULL; 80static U_NAMESPACE_QUALIFIER Locale *gDefaultLocale = NULL; 81static UHashtable *gDefaultLocalesHashT = NULL; 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) { 89 delete (U_NAMESPACE_QUALIFIER Locale *) obj; 90} 91 92static 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} 119U_CDECL_END 120 121U_NAMESPACE_BEGIN 122// 123// locale_set_default_internal. 124// 125void 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} 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 272UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale) 273 274/*Character separating the posix id fields*/ 275// '_' 276// In the platform codepage. 277#define SEP_CHAR '_' 278 279Locale::~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 293Locale::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 */ 304Locale::Locale(Locale::ELocaleType) 305 : UObject(), fullName(fullNameBuffer), baseName(NULL) 306{ 307 setToBogus(); 308} 309 310 311Locale::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 461Locale::Locale(const Locale &other) 462 : UObject(other), fullName(fullNameBuffer), baseName(NULL) 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)); 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 519Locale * 520Locale::clone() const { 521 return new Locale(*this); 522} 523 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*/ 531Locale& 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 654int32_t 655Locale::hashCode() const 656{ 657 UHashTok hashKey; 658 hashKey.pointer = fullName; 659 return uhash_hashChars(hashKey); 660} 661 662void 663Locale::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 676const Locale& U_EXPORT2 677Locale::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 696void U_EXPORT2 697Locale::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 711Locale U_EXPORT2 712Locale::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 724Locale U_EXPORT2 725Locale::createCanonical(const char* name) { 726 Locale loc(""); 727 loc.init(name, TRUE); 728 return loc; 729} 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 */ 751uint32_t 752Locale::getLCID() const 753{ 754 return uloc_getLCID(fullName); 755} 756 757UnicodeString& 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); 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 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); 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 843UnicodeString& 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); 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 883UnicodeString& 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); 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 923UnicodeString& 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); 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} 962const Locale* U_EXPORT2 963Locale::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 1000const char* const* U_EXPORT2 Locale::getISOCountries() 1001{ 1002 return uloc_getISOCountries(); 1003} 1004 1005const char* const* U_EXPORT2 Locale::getISOLanguages() 1006{ 1007 return uloc_getISOLanguages(); 1008} 1009 1010// Set the locale's data based on a posix id. 1011void Locale::setFromPOSIXID(const char *posixID) 1012{ 1013 init(posixID, TRUE); 1014} 1015 1016const Locale & U_EXPORT2 1017Locale::getEnglish(void) 1018{ 1019 return getLocale(eENGLISH); 1020} 1021 1022const Locale & U_EXPORT2 1023Locale::getFrench(void) 1024{ 1025 return getLocale(eFRENCH); 1026} 1027 1028const Locale & U_EXPORT2 1029Locale::getGerman(void) 1030{ 1031 return getLocale(eGERMAN); 1032} 1033 1034const Locale & U_EXPORT2 1035Locale::getItalian(void) 1036{ 1037 return getLocale(eITALIAN); 1038} 1039 1040const Locale & U_EXPORT2 1041Locale::getJapanese(void) 1042{ 1043 return getLocale(eJAPANESE); 1044} 1045 1046const Locale & U_EXPORT2 1047Locale::getKorean(void) 1048{ 1049 return getLocale(eKOREAN); 1050} 1051 1052const Locale & U_EXPORT2 1053Locale::getChinese(void) 1054{ 1055 return getLocale(eCHINESE); 1056} 1057 1058const Locale & U_EXPORT2 1059Locale::getSimplifiedChinese(void) 1060{ 1061 return getLocale(eCHINA); 1062} 1063 1064const Locale & U_EXPORT2 1065Locale::getTraditionalChinese(void) 1066{ 1067 return getLocale(eTAIWAN); 1068} 1069 1070 1071const Locale & U_EXPORT2 1072Locale::getFrance(void) 1073{ 1074 return getLocale(eFRANCE); 1075} 1076 1077const Locale & U_EXPORT2 1078Locale::getGermany(void) 1079{ 1080 return getLocale(eGERMANY); 1081} 1082 1083const Locale & U_EXPORT2 1084Locale::getItaly(void) 1085{ 1086 return getLocale(eITALY); 1087} 1088 1089const Locale & U_EXPORT2 1090Locale::getJapan(void) 1091{ 1092 return getLocale(eJAPAN); 1093} 1094 1095const Locale & U_EXPORT2 1096Locale::getKorea(void) 1097{ 1098 return getLocale(eKOREA); 1099} 1100 1101const Locale & U_EXPORT2 1102Locale::getChina(void) 1103{ 1104 return getLocale(eCHINA); 1105} 1106 1107const Locale & U_EXPORT2 1108Locale::getPRC(void) 1109{ 1110 return getLocale(eCHINA); 1111} 1112 1113const Locale & U_EXPORT2 1114Locale::getTaiwan(void) 1115{ 1116 return getLocale(eTAIWAN); 1117} 1118 1119const Locale & U_EXPORT2 1120Locale::getUK(void) 1121{ 1122 return getLocale(eUK); 1123} 1124 1125const Locale & U_EXPORT2 1126Locale::getUS(void) 1127{ 1128 return getLocale(eUS); 1129} 1130 1131const Locale & U_EXPORT2 1132Locale::getCanada(void) 1133{ 1134 return getLocale(eCANADA); 1135} 1136 1137const Locale & U_EXPORT2 1138Locale::getCanadaFrench(void) 1139{ 1140 return getLocale(eCANADA_FRENCH); 1141} 1142 1143const Locale & 1144Locale::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/* 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); 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 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; 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 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); 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 1340U_NAMESPACE_END 1341