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