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 46 U_CDECL_BEGIN 47 static UBool U_CALLCONV locale_cleanup(void); 48 U_CDECL_END 49 50 U_NAMESPACE_BEGIN 51 52 static Locale *gLocaleCache = NULL; 53 static UInitOnce gLocaleCacheInitOnce = U_INITONCE_INITIALIZER; 54 55 // gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale. 56 static UMutex gDefaultLocaleMutex = U_MUTEX_INITIALIZER; 57 static UHashtable *gDefaultLocalesHashT = NULL; 58 static Locale *gDefaultLocale = NULL; 59 60 U_NAMESPACE_END 61 62 typedef 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 89 U_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 96 U_CDECL_BEGIN 97 // 98 // Deleter function for Locales owned by the default Locale hash table/ 99 // 100 static void U_CALLCONV 101 deleteLocale(void *obj) { 102 delete (icu::Locale *) obj; 103 } 104 105 static 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 122 static 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 153 U_CDECL_END 154 155 U_NAMESPACE_BEGIN 156 157 Locale *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 213 U_NAMESPACE_END 214 215 /* sfb 07/21/99 */ 216 U_CFUNC void 217 locale_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 225 U_CFUNC const char * 226 locale_get_default(void) 227 { 228 U_NAMESPACE_USE 229 return Locale::getDefault().getName(); 230 } 231 232 233 U_NAMESPACE_BEGIN 234 235 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale) 236 237 /*Character separating the posix id fields*/ 238 // '_' 239 // In the platform codepage. 240 #define SEP_CHAR '_' 241 242 Locale::~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 256 Locale::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 */ 267 Locale::Locale(Locale::ELocaleType) 268 : UObject(), fullName(fullNameBuffer), baseName(NULL) 269 { 270 setToBogus(); 271 } 272 273 274 Locale::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 412 Locale::Locale(const Locale &other) 413 : UObject(other), fullName(fullNameBuffer), baseName(NULL) 414 { 415 *this = other; 416 } 417 418 Locale &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 464 Locale * 465 Locale::clone() const { 466 return new Locale(*this); 467 } 468 469 UBool 470 Locale::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*/ 478 Locale& 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 */ 612 void 613 Locale::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 643 int32_t 644 Locale::hashCode() const 645 { 646 return ustr_hashCharsN(fullName, uprv_strlen(fullName)); 647 } 648 649 void 650 Locale::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 667 const Locale& U_EXPORT2 668 Locale::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 682 void U_EXPORT2 683 Locale::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 697 Locale U_EXPORT2 698 Locale::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 710 Locale U_EXPORT2 711 Locale::createCanonical(const char* name) { 712 Locale loc(""); 713 loc.init(name, TRUE); 714 return loc; 715 } 716 717 const char * 718 Locale::getISO3Language() const 719 { 720 return uloc_getISO3Language(fullName); 721 } 722 723 724 const char * 725 Locale::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 */ 737 uint32_t 738 Locale::getLCID() const 739 { 740 return uloc_getLCID(fullName); 741 } 742 743 const char* const* U_EXPORT2 Locale::getISOCountries() 744 { 745 return uloc_getISOCountries(); 746 } 747 748 const char* const* U_EXPORT2 Locale::getISOLanguages() 749 { 750 return uloc_getISOLanguages(); 751 } 752 753 // Set the locale's data based on a posix id. 754 void Locale::setFromPOSIXID(const char *posixID) 755 { 756 init(posixID, TRUE); 757 } 758 759 const Locale & U_EXPORT2 760 Locale::getRoot(void) 761 { 762 return getLocale(eROOT); 763 } 764 765 const Locale & U_EXPORT2 766 Locale::getEnglish(void) 767 { 768 return getLocale(eENGLISH); 769 } 770 771 const Locale & U_EXPORT2 772 Locale::getFrench(void) 773 { 774 return getLocale(eFRENCH); 775 } 776 777 const Locale & U_EXPORT2 778 Locale::getGerman(void) 779 { 780 return getLocale(eGERMAN); 781 } 782 783 const Locale & U_EXPORT2 784 Locale::getItalian(void) 785 { 786 return getLocale(eITALIAN); 787 } 788 789 const Locale & U_EXPORT2 790 Locale::getJapanese(void) 791 { 792 return getLocale(eJAPANESE); 793 } 794 795 const Locale & U_EXPORT2 796 Locale::getKorean(void) 797 { 798 return getLocale(eKOREAN); 799 } 800 801 const Locale & U_EXPORT2 802 Locale::getChinese(void) 803 { 804 return getLocale(eCHINESE); 805 } 806 807 const Locale & U_EXPORT2 808 Locale::getSimplifiedChinese(void) 809 { 810 return getLocale(eCHINA); 811 } 812 813 const Locale & U_EXPORT2 814 Locale::getTraditionalChinese(void) 815 { 816 return getLocale(eTAIWAN); 817 } 818 819 820 const Locale & U_EXPORT2 821 Locale::getFrance(void) 822 { 823 return getLocale(eFRANCE); 824 } 825 826 const Locale & U_EXPORT2 827 Locale::getGermany(void) 828 { 829 return getLocale(eGERMANY); 830 } 831 832 const Locale & U_EXPORT2 833 Locale::getItaly(void) 834 { 835 return getLocale(eITALY); 836 } 837 838 const Locale & U_EXPORT2 839 Locale::getJapan(void) 840 { 841 return getLocale(eJAPAN); 842 } 843 844 const Locale & U_EXPORT2 845 Locale::getKorea(void) 846 { 847 return getLocale(eKOREA); 848 } 849 850 const Locale & U_EXPORT2 851 Locale::getChina(void) 852 { 853 return getLocale(eCHINA); 854 } 855 856 const Locale & U_EXPORT2 857 Locale::getPRC(void) 858 { 859 return getLocale(eCHINA); 860 } 861 862 const Locale & U_EXPORT2 863 Locale::getTaiwan(void) 864 { 865 return getLocale(eTAIWAN); 866 } 867 868 const Locale & U_EXPORT2 869 Locale::getUK(void) 870 { 871 return getLocale(eUK); 872 } 873 874 const Locale & U_EXPORT2 875 Locale::getUS(void) 876 { 877 return getLocale(eUS); 878 } 879 880 const Locale & U_EXPORT2 881 Locale::getCanada(void) 882 { 883 return getLocale(eCANADA); 884 } 885 886 const Locale & U_EXPORT2 887 Locale::getCanadaFrench(void) 888 { 889 return getLocale(eCANADA_FRENCH); 890 } 891 892 const Locale & 893 Locale::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 /* 906 This function is defined this way in order to get around static 907 initialization and static destruction. 908 */ 909 Locale * 910 Locale::getLocaleCache(void) 911 { 912 UErrorCode status = U_ZERO_ERROR; 913 umtx_initOnce(gLocaleCacheInitOnce, locale_init, status); 914 return gLocaleCache; 915 } 916 917 class KeywordEnumeration : public StringEnumeration { 918 private: 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 925 public: 926 static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; } 927 virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); } 928 public: 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 997 const char KeywordEnumeration::fgClassID = '\0'; 998 999 KeywordEnumeration::~KeywordEnumeration() { 1000 uprv_free(keywords); 1001 } 1002 1003 StringEnumeration * 1004 Locale::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 1025 int32_t 1026 Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, UErrorCode &status) const 1027 { 1028 return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status); 1029 } 1030 1031 void 1032 Locale::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 1041 const char * 1042 Locale::getBaseName() const { 1043 return baseName; 1044 } 1045 1046 //eof 1047 U_NAMESPACE_END 1048