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