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