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