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