1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 1997-2012, International Business Machines 5 * Corporation and others. All Rights Reserved. 6 * 7 ******************************************************************************* 8 * file name: locdispnames.cpp 9 * encoding: US-ASCII 10 * tab size: 8 (not used) 11 * indentation:4 12 * 13 * created on: 2010feb25 14 * created by: Markus W. Scherer 15 * 16 * Code for locale display names, separated out from other .cpp files 17 * that then do not depend on resource bundle code and display name data. 18 */ 19 20 #include "unicode/utypes.h" 21 #include "unicode/brkiter.h" 22 #include "unicode/locid.h" 23 #include "unicode/uloc.h" 24 #include "unicode/ures.h" 25 #include "unicode/ustring.h" 26 #include "cmemory.h" 27 #include "cstring.h" 28 #include "putilimp.h" 29 #include "ulocimp.h" 30 #include "uresimp.h" 31 #include "ureslocs.h" 32 #include "ustr_imp.h" 33 34 // C++ API ----------------------------------------------------------------- *** 35 36 U_NAMESPACE_BEGIN 37 38 UnicodeString& 39 Locale::getDisplayLanguage(UnicodeString& dispLang) const 40 { 41 return this->getDisplayLanguage(getDefault(), dispLang); 42 } 43 44 /*We cannot make any assumptions on the size of the output display strings 45 * Yet, since we are calling through to a C API, we need to set limits on 46 * buffer size. For all the following getDisplay functions we first attempt 47 * to fill up a stack allocated buffer. If it is to small we heap allocated 48 * the exact buffer we need copy it to the UnicodeString and delete it*/ 49 50 UnicodeString& 51 Locale::getDisplayLanguage(const Locale &displayLocale, 52 UnicodeString &result) const { 53 UChar *buffer; 54 UErrorCode errorCode=U_ZERO_ERROR; 55 int32_t length; 56 57 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); 58 if(buffer==0) { 59 result.truncate(0); 60 return result; 61 } 62 63 length=uloc_getDisplayLanguage(fullName, displayLocale.fullName, 64 buffer, result.getCapacity(), 65 &errorCode); 66 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 67 68 if(errorCode==U_BUFFER_OVERFLOW_ERROR) { 69 buffer=result.getBuffer(length); 70 if(buffer==0) { 71 result.truncate(0); 72 return result; 73 } 74 errorCode=U_ZERO_ERROR; 75 length=uloc_getDisplayLanguage(fullName, displayLocale.fullName, 76 buffer, result.getCapacity(), 77 &errorCode); 78 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 79 } 80 81 return result; 82 } 83 84 UnicodeString& 85 Locale::getDisplayScript(UnicodeString& dispScript) const 86 { 87 return this->getDisplayScript(getDefault(), dispScript); 88 } 89 90 UnicodeString& 91 Locale::getDisplayScript(const Locale &displayLocale, 92 UnicodeString &result) const { 93 UChar *buffer; 94 UErrorCode errorCode=U_ZERO_ERROR; 95 int32_t length; 96 97 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); 98 if(buffer==0) { 99 result.truncate(0); 100 return result; 101 } 102 103 length=uloc_getDisplayScript(fullName, displayLocale.fullName, 104 buffer, result.getCapacity(), 105 &errorCode); 106 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 107 108 if(errorCode==U_BUFFER_OVERFLOW_ERROR) { 109 buffer=result.getBuffer(length); 110 if(buffer==0) { 111 result.truncate(0); 112 return result; 113 } 114 errorCode=U_ZERO_ERROR; 115 length=uloc_getDisplayScript(fullName, displayLocale.fullName, 116 buffer, result.getCapacity(), 117 &errorCode); 118 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 119 } 120 121 return result; 122 } 123 124 UnicodeString& 125 Locale::getDisplayCountry(UnicodeString& dispCntry) const 126 { 127 return this->getDisplayCountry(getDefault(), dispCntry); 128 } 129 130 UnicodeString& 131 Locale::getDisplayCountry(const Locale &displayLocale, 132 UnicodeString &result) const { 133 UChar *buffer; 134 UErrorCode errorCode=U_ZERO_ERROR; 135 int32_t length; 136 137 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); 138 if(buffer==0) { 139 result.truncate(0); 140 return result; 141 } 142 143 length=uloc_getDisplayCountry(fullName, displayLocale.fullName, 144 buffer, result.getCapacity(), 145 &errorCode); 146 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 147 148 if(errorCode==U_BUFFER_OVERFLOW_ERROR) { 149 buffer=result.getBuffer(length); 150 if(buffer==0) { 151 result.truncate(0); 152 return result; 153 } 154 errorCode=U_ZERO_ERROR; 155 length=uloc_getDisplayCountry(fullName, displayLocale.fullName, 156 buffer, result.getCapacity(), 157 &errorCode); 158 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 159 } 160 161 return result; 162 } 163 164 UnicodeString& 165 Locale::getDisplayVariant(UnicodeString& dispVar) const 166 { 167 return this->getDisplayVariant(getDefault(), dispVar); 168 } 169 170 UnicodeString& 171 Locale::getDisplayVariant(const Locale &displayLocale, 172 UnicodeString &result) const { 173 UChar *buffer; 174 UErrorCode errorCode=U_ZERO_ERROR; 175 int32_t length; 176 177 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); 178 if(buffer==0) { 179 result.truncate(0); 180 return result; 181 } 182 183 length=uloc_getDisplayVariant(fullName, displayLocale.fullName, 184 buffer, result.getCapacity(), 185 &errorCode); 186 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 187 188 if(errorCode==U_BUFFER_OVERFLOW_ERROR) { 189 buffer=result.getBuffer(length); 190 if(buffer==0) { 191 result.truncate(0); 192 return result; 193 } 194 errorCode=U_ZERO_ERROR; 195 length=uloc_getDisplayVariant(fullName, displayLocale.fullName, 196 buffer, result.getCapacity(), 197 &errorCode); 198 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 199 } 200 201 return result; 202 } 203 204 UnicodeString& 205 Locale::getDisplayName( UnicodeString& name ) const 206 { 207 return this->getDisplayName(getDefault(), name); 208 } 209 210 UnicodeString& 211 Locale::getDisplayName(const Locale &displayLocale, 212 UnicodeString &result) const { 213 UChar *buffer; 214 UErrorCode errorCode=U_ZERO_ERROR; 215 int32_t length; 216 217 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); 218 if(buffer==0) { 219 result.truncate(0); 220 return result; 221 } 222 223 length=uloc_getDisplayName(fullName, displayLocale.fullName, 224 buffer, result.getCapacity(), 225 &errorCode); 226 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 227 228 if(errorCode==U_BUFFER_OVERFLOW_ERROR) { 229 buffer=result.getBuffer(length); 230 if(buffer==0) { 231 result.truncate(0); 232 return result; 233 } 234 errorCode=U_ZERO_ERROR; 235 length=uloc_getDisplayName(fullName, displayLocale.fullName, 236 buffer, result.getCapacity(), 237 &errorCode); 238 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 239 } 240 241 return result; 242 } 243 244 #if ! UCONFIG_NO_BREAK_ITERATION 245 246 // ------------------------------------- 247 // Gets the objectLocale display name in the default locale language. 248 UnicodeString& U_EXPORT2 249 BreakIterator::getDisplayName(const Locale& objectLocale, 250 UnicodeString& name) 251 { 252 return objectLocale.getDisplayName(name); 253 } 254 255 // ------------------------------------- 256 // Gets the objectLocale display name in the displayLocale language. 257 UnicodeString& U_EXPORT2 258 BreakIterator::getDisplayName(const Locale& objectLocale, 259 const Locale& displayLocale, 260 UnicodeString& name) 261 { 262 return objectLocale.getDisplayName(displayLocale, name); 263 } 264 265 #endif 266 267 268 U_NAMESPACE_END 269 270 // C API ------------------------------------------------------------------- *** 271 272 U_NAMESPACE_USE 273 274 /* ### Constants **************************************************/ 275 276 /* These strings describe the resources we attempt to load from 277 the locale ResourceBundle data file.*/ 278 static const char _kLanguages[] = "Languages"; 279 static const char _kScripts[] = "Scripts"; 280 static const char _kScriptsStandAlone[] = "Scripts%stand-alone"; 281 static const char _kCountries[] = "Countries"; 282 static const char _kVariants[] = "Variants"; 283 static const char _kKeys[] = "Keys"; 284 static const char _kTypes[] = "Types"; 285 //static const char _kRootName[] = "root"; 286 static const char _kCurrency[] = "currency"; 287 static const char _kCurrencies[] = "Currencies"; 288 static const char _kLocaleDisplayPattern[] = "localeDisplayPattern"; 289 static const char _kPattern[] = "pattern"; 290 static const char _kSeparator[] = "separator"; 291 292 /* ### Display name **************************************************/ 293 294 static int32_t 295 _getStringOrCopyKey(const char *path, const char *locale, 296 const char *tableKey, 297 const char* subTableKey, 298 const char *itemKey, 299 const char *substitute, 300 UChar *dest, int32_t destCapacity, 301 UErrorCode *pErrorCode) { 302 const UChar *s = NULL; 303 int32_t length = 0; 304 305 if(itemKey==NULL) { 306 /* top-level item: normal resource bundle access */ 307 UResourceBundle *rb; 308 309 rb=ures_open(path, locale, pErrorCode); 310 311 if(U_SUCCESS(*pErrorCode)) { 312 s=ures_getStringByKey(rb, tableKey, &length, pErrorCode); 313 /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */ 314 ures_close(rb); 315 } 316 } else { 317 /* Language code should not be a number. If it is, set the error code. */ 318 if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) { 319 *pErrorCode = U_MISSING_RESOURCE_ERROR; 320 } else { 321 /* second-level item, use special fallback */ 322 s=uloc_getTableStringWithFallback(path, locale, 323 tableKey, 324 subTableKey, 325 itemKey, 326 &length, 327 pErrorCode); 328 } 329 } 330 331 if(U_SUCCESS(*pErrorCode)) { 332 int32_t copyLength=uprv_min(length, destCapacity); 333 if(copyLength>0 && s != NULL) { 334 u_memcpy(dest, s, copyLength); 335 } 336 } else { 337 /* no string from a resource bundle: convert the substitute */ 338 length=(int32_t)uprv_strlen(substitute); 339 u_charsToUChars(substitute, dest, uprv_min(length, destCapacity)); 340 *pErrorCode=U_USING_DEFAULT_WARNING; 341 } 342 343 return u_terminateUChars(dest, destCapacity, length, pErrorCode); 344 } 345 346 typedef int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *); 347 348 static int32_t 349 _getDisplayNameForComponent(const char *locale, 350 const char *displayLocale, 351 UChar *dest, int32_t destCapacity, 352 UDisplayNameGetter *getter, 353 const char *tag, 354 UErrorCode *pErrorCode) { 355 char localeBuffer[ULOC_FULLNAME_CAPACITY*4]; 356 int32_t length; 357 UErrorCode localStatus; 358 const char* root = NULL; 359 360 /* argument checking */ 361 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 362 return 0; 363 } 364 365 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 366 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 367 return 0; 368 } 369 370 localStatus = U_ZERO_ERROR; 371 length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus); 372 if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) { 373 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 374 return 0; 375 } 376 if(length==0) { 377 return u_terminateUChars(dest, destCapacity, 0, pErrorCode); 378 } 379 380 root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG; 381 382 return _getStringOrCopyKey(root, displayLocale, 383 tag, NULL, localeBuffer, 384 localeBuffer, 385 dest, destCapacity, 386 pErrorCode); 387 } 388 389 U_CAPI int32_t U_EXPORT2 390 uloc_getDisplayLanguage(const char *locale, 391 const char *displayLocale, 392 UChar *dest, int32_t destCapacity, 393 UErrorCode *pErrorCode) { 394 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 395 uloc_getLanguage, _kLanguages, pErrorCode); 396 } 397 398 U_CAPI int32_t U_EXPORT2 399 uloc_getDisplayScript(const char* locale, 400 const char* displayLocale, 401 UChar *dest, int32_t destCapacity, 402 UErrorCode *pErrorCode) 403 { 404 UErrorCode err = U_ZERO_ERROR; 405 int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 406 uloc_getScript, _kScriptsStandAlone, &err); 407 408 if ( err == U_USING_DEFAULT_WARNING ) { 409 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 410 uloc_getScript, _kScripts, pErrorCode); 411 } else { 412 *pErrorCode = err; 413 return res; 414 } 415 } 416 417 U_INTERNAL int32_t U_EXPORT2 418 uloc_getDisplayScriptInContext(const char* locale, 419 const char* displayLocale, 420 UChar *dest, int32_t destCapacity, 421 UErrorCode *pErrorCode) 422 { 423 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 424 uloc_getScript, _kScripts, pErrorCode); 425 } 426 427 U_CAPI int32_t U_EXPORT2 428 uloc_getDisplayCountry(const char *locale, 429 const char *displayLocale, 430 UChar *dest, int32_t destCapacity, 431 UErrorCode *pErrorCode) { 432 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 433 uloc_getCountry, _kCountries, pErrorCode); 434 } 435 436 /* 437 * TODO separate variant1_variant2_variant3... 438 * by getting each tag's display string and concatenating them with ", " 439 * in between - similar to uloc_getDisplayName() 440 */ 441 U_CAPI int32_t U_EXPORT2 442 uloc_getDisplayVariant(const char *locale, 443 const char *displayLocale, 444 UChar *dest, int32_t destCapacity, 445 UErrorCode *pErrorCode) { 446 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 447 uloc_getVariant, _kVariants, pErrorCode); 448 } 449 450 /* Instead of having a separate pass for 'special' patterns, reintegrate the two 451 * so we don't get bitten by preflight bugs again. We can be reasonably efficient 452 * without two separate code paths, this code isn't that performance-critical. 453 * 454 * This code is general enough to deal with patterns that have a prefix or swap the 455 * language and remainder components, since we gave developers enough rope to do such 456 * things if they futz with the pattern data. But since we don't give them a way to 457 * specify a pattern for arbitrary combinations of components, there's not much use in 458 * that. I don't think our data includes such patterns, the only variable I know if is 459 * whether there is a space before the open paren, or not. Oh, and zh uses different 460 * chars than the standard open/close paren (which ja and ko use, btw). 461 */ 462 U_CAPI int32_t U_EXPORT2 463 uloc_getDisplayName(const char *locale, 464 const char *displayLocale, 465 UChar *dest, int32_t destCapacity, 466 UErrorCode *pErrorCode) 467 { 468 static const UChar defaultSeparator[3] = { 0x002c, 0x0020, 0x0000 }; /* comma + space */ 469 static const int32_t defaultSepLen = 2; 470 static const UChar sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */ 471 static const UChar sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */ 472 static const int32_t subLen = 3; 473 static const UChar defaultPattern[10] = { 474 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000 475 }; /* {0} ({1}) */ 476 static const int32_t defaultPatLen = 9; 477 static const int32_t defaultSub0Pos = 0; 478 static const int32_t defaultSub1Pos = 5; 479 480 int32_t length; /* of formatted result */ 481 482 const UChar *separator; 483 int32_t sepLen = 0; 484 const UChar *pattern; 485 int32_t patLen = 0; 486 int32_t sub0Pos, sub1Pos; 487 488 UBool haveLang = TRUE; /* assume true, set false if we find we don't have 489 a lang component in the locale */ 490 UBool haveRest = TRUE; /* assume true, set false if we find we don't have 491 any other component in the locale */ 492 UBool retry = FALSE; /* set true if we need to retry, see below */ 493 494 int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */ 495 496 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 497 return 0; 498 } 499 500 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 501 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 502 return 0; 503 } 504 505 { 506 UErrorCode status = U_ZERO_ERROR; 507 UResourceBundle* locbundle=ures_open(U_ICUDATA_LANG, displayLocale, &status); 508 UResourceBundle* dspbundle=ures_getByKeyWithFallback(locbundle, _kLocaleDisplayPattern, 509 NULL, &status); 510 511 separator=ures_getStringByKeyWithFallback(dspbundle, _kSeparator, &sepLen, &status); 512 pattern=ures_getStringByKeyWithFallback(dspbundle, _kPattern, &patLen, &status); 513 514 ures_close(dspbundle); 515 ures_close(locbundle); 516 } 517 518 /* If we couldn't find any data, then use the defaults */ 519 if(sepLen == 0) { 520 separator = defaultSeparator; 521 sepLen = defaultSepLen; 522 } 523 524 if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) { 525 pattern=defaultPattern; 526 patLen=defaultPatLen; 527 sub0Pos=defaultSub0Pos; 528 sub1Pos=defaultSub1Pos; 529 } else { /* non-default pattern */ 530 UChar *p0=u_strstr(pattern, sub0); 531 UChar *p1=u_strstr(pattern, sub1); 532 if (p0==NULL || p1==NULL) { 533 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 534 return 0; 535 } 536 sub0Pos=p0-pattern; 537 sub1Pos=p1-pattern; 538 if (sub1Pos < sub0Pos) { /* a very odd pattern */ 539 int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t; 540 langi=1; 541 } 542 } 543 544 /* We loop here because there is one case in which after the first pass we could need to 545 * reextract the data. If there's initial padding before the first element, we put in 546 * the padding and then write that element. If it turns out there's no second element, 547 * we didn't need the padding. If we do need the data (no preflight), and the first element 548 * would have fit but for the padding, we need to reextract. In this case (only) we 549 * adjust the parameters so padding is not added, and repeat. 550 */ 551 do { 552 UChar* p=dest; 553 int32_t patPos=0; /* position in the pattern, used for non-substitution portions */ 554 int32_t langLen=0; /* length of language substitution */ 555 int32_t langPos=0; /* position in output of language substitution */ 556 int32_t restLen=0; /* length of 'everything else' substitution */ 557 int32_t restPos=0; /* position in output of 'everything else' substitution */ 558 UEnumeration* kenum = NULL; /* keyword enumeration */ 559 560 /* prefix of pattern, extremely likely to be empty */ 561 if(sub0Pos) { 562 if(destCapacity >= sub0Pos) { 563 while (patPos < sub0Pos) { 564 *p++ = pattern[patPos++]; 565 } 566 } else { 567 patPos=sub0Pos; 568 } 569 length=sub0Pos; 570 } else { 571 length=0; 572 } 573 574 for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/ 575 UBool subdone = FALSE; /* set true when ready to move to next substitution */ 576 577 /* prep p and cap for calls to get display components, pin cap to 0 since 578 they complain if cap is negative */ 579 int32_t cap=destCapacity-length; 580 if (cap <= 0) { 581 cap=0; 582 } else { 583 p=dest+length; 584 } 585 586 if (subi == langi) { /* {0}*/ 587 if(haveLang) { 588 langPos=length; 589 langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode); 590 length+=langLen; 591 haveLang=langLen>0; 592 } 593 subdone=TRUE; 594 } else { /* {1} */ 595 if(!haveRest) { 596 subdone=TRUE; 597 } else { 598 int32_t len; /* length of component (plus other stuff) we just fetched */ 599 switch(resti++) { 600 case 0: 601 restPos=length; 602 len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode); 603 break; 604 case 1: 605 len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode); 606 break; 607 case 2: 608 len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode); 609 break; 610 case 3: 611 kenum = uloc_openKeywords(locale, pErrorCode); 612 /* fall through */ 613 default: { 614 const char* kw=uenum_next(kenum, &len, pErrorCode); 615 if (kw == NULL) { 616 uenum_close(kenum); 617 len=0; /* mark that we didn't add a component */ 618 subdone=TRUE; 619 } else { 620 /* incorporating this behavior into the loop made it even more complex, 621 so just special case it here */ 622 len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode); 623 if(len) { 624 if(len < cap) { 625 p[len]=0x3d; /* '=', assume we'll need it */ 626 } 627 len+=1; 628 629 /* adjust for call to get keyword */ 630 cap-=len; 631 if(cap <= 0) { 632 cap=0; 633 } else { 634 p+=len; 635 } 636 } 637 /* reset for call below */ 638 if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) { 639 *pErrorCode=U_ZERO_ERROR; 640 } 641 int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale, 642 p, cap, pErrorCode); 643 if(len) { 644 if(vlen==0) { 645 --len; /* remove unneeded '=' */ 646 } 647 /* restore cap and p to what they were at start */ 648 cap=destCapacity-length; 649 if(cap <= 0) { 650 cap=0; 651 } else { 652 p=dest+length; 653 } 654 } 655 len+=vlen; /* total we added for key + '=' + value */ 656 } 657 } break; 658 } /* end switch */ 659 660 if (len>0) { 661 /* we addeed a component, so add separator and write it if there's room. */ 662 if(len+sepLen<=cap) { 663 p+=len; 664 for(int32_t i=0;i<sepLen;++i) { 665 *p++=separator[i]; 666 } 667 } 668 length+=len+sepLen; 669 } else if(subdone) { 670 /* remove separator if we added it */ 671 if (length!=restPos) { 672 length-=sepLen; 673 } 674 restLen=length-restPos; 675 haveRest=restLen>0; 676 } 677 } 678 } 679 680 if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) { 681 *pErrorCode=U_ZERO_ERROR; 682 } 683 684 if(subdone) { 685 if(haveLang && haveRest) { 686 /* append internal portion of pattern, the first time, 687 or last portion of pattern the second time */ 688 int32_t padLen; 689 patPos+=subLen; 690 padLen=(subi==0 ? sub1Pos : patLen)-patPos; 691 if(length+padLen < destCapacity) { 692 p=dest+length; 693 for(int32_t i=0;i<padLen;++i) { 694 *p++=pattern[patPos++]; 695 } 696 } else { 697 patPos+=padLen; 698 } 699 length+=padLen; 700 } else if(subi==0) { 701 /* don't have first component, reset for second component */ 702 sub0Pos=0; 703 length=0; 704 } else if(length>0) { 705 /* true length is the length of just the component we got. */ 706 length=haveLang?langLen:restLen; 707 if(dest && sub0Pos!=0) { 708 if (sub0Pos+length<=destCapacity) { 709 /* first component not at start of result, 710 but we have full component in buffer. */ 711 u_memmove(dest, dest+(haveLang?langPos:restPos), length); 712 } else { 713 /* would have fit, but didn't because of pattern prefix. */ 714 sub0Pos=0; /* stops initial padding (and a second retry, 715 so we won't end up here again) */ 716 retry=TRUE; 717 } 718 } 719 } 720 721 ++subi; /* move on to next substitution */ 722 } 723 } 724 } while(retry); 725 726 return u_terminateUChars(dest, destCapacity, length, pErrorCode); 727 } 728 729 U_CAPI int32_t U_EXPORT2 730 uloc_getDisplayKeyword(const char* keyword, 731 const char* displayLocale, 732 UChar* dest, 733 int32_t destCapacity, 734 UErrorCode* status){ 735 736 /* argument checking */ 737 if(status==NULL || U_FAILURE(*status)) { 738 return 0; 739 } 740 741 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 742 *status=U_ILLEGAL_ARGUMENT_ERROR; 743 return 0; 744 } 745 746 747 /* pass itemKey=NULL to look for a top-level item */ 748 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale, 749 _kKeys, NULL, 750 keyword, 751 keyword, 752 dest, destCapacity, 753 status); 754 755 } 756 757 758 #define UCURRENCY_DISPLAY_NAME_INDEX 1 759 760 U_CAPI int32_t U_EXPORT2 761 uloc_getDisplayKeywordValue( const char* locale, 762 const char* keyword, 763 const char* displayLocale, 764 UChar* dest, 765 int32_t destCapacity, 766 UErrorCode* status){ 767 768 769 char keywordValue[ULOC_FULLNAME_CAPACITY*4]; 770 int32_t capacity = ULOC_FULLNAME_CAPACITY*4; 771 int32_t keywordValueLen =0; 772 773 /* argument checking */ 774 if(status==NULL || U_FAILURE(*status)) { 775 return 0; 776 } 777 778 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 779 *status=U_ILLEGAL_ARGUMENT_ERROR; 780 return 0; 781 } 782 783 /* get the keyword value */ 784 keywordValue[0]=0; 785 keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status); 786 787 /* 788 * if the keyword is equal to currency .. then to get the display name 789 * we need to do the fallback ourselves 790 */ 791 if(uprv_stricmp(keyword, _kCurrency)==0){ 792 793 int32_t dispNameLen = 0; 794 const UChar *dispName = NULL; 795 796 UResourceBundle *bundle = ures_open(U_ICUDATA_CURR, displayLocale, status); 797 UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status); 798 UResourceBundle *currency = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status); 799 800 dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status); 801 802 /*close the bundles */ 803 ures_close(currency); 804 ures_close(currencies); 805 ures_close(bundle); 806 807 if(U_FAILURE(*status)){ 808 if(*status == U_MISSING_RESOURCE_ERROR){ 809 /* we just want to write the value over if nothing is available */ 810 *status = U_USING_DEFAULT_WARNING; 811 }else{ 812 return 0; 813 } 814 } 815 816 /* now copy the dispName over if not NULL */ 817 if(dispName != NULL){ 818 if(dispNameLen <= destCapacity){ 819 uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR); 820 return u_terminateUChars(dest, destCapacity, dispNameLen, status); 821 }else{ 822 *status = U_BUFFER_OVERFLOW_ERROR; 823 return dispNameLen; 824 } 825 }else{ 826 /* we have not found the display name for the value .. just copy over */ 827 if(keywordValueLen <= destCapacity){ 828 u_charsToUChars(keywordValue, dest, keywordValueLen); 829 return u_terminateUChars(dest, destCapacity, keywordValueLen, status); 830 }else{ 831 *status = U_BUFFER_OVERFLOW_ERROR; 832 return keywordValueLen; 833 } 834 } 835 836 837 }else{ 838 839 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale, 840 _kTypes, keyword, 841 keywordValue, 842 keywordValue, 843 dest, destCapacity, 844 status); 845 } 846 } 847