1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 1997-2011, 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 _kCountries[] = "Countries"; 281 static const char _kVariants[] = "Variants"; 282 static const char _kKeys[] = "Keys"; 283 static const char _kTypes[] = "Types"; 284 static const char _kRootName[] = "root"; 285 static const char _kCurrency[] = "currency"; 286 static const char _kCurrencies[] = "Currencies"; 287 static const char _kLocaleDisplayPattern[] = "localeDisplayPattern"; 288 static const char _kPattern[] = "pattern"; 289 static const char _kSeparator[] = "separator"; 290 291 /* ### Display name **************************************************/ 292 293 static int32_t 294 _getStringOrCopyKey(const char *path, const char *locale, 295 const char *tableKey, 296 const char* subTableKey, 297 const char *itemKey, 298 const char *substitute, 299 UChar *dest, int32_t destCapacity, 300 UErrorCode *pErrorCode) { 301 const UChar *s = NULL; 302 int32_t length = 0; 303 304 if(itemKey==NULL) { 305 /* top-level item: normal resource bundle access */ 306 UResourceBundle *rb; 307 308 rb=ures_open(path, locale, pErrorCode); 309 310 if(U_SUCCESS(*pErrorCode)) { 311 s=ures_getStringByKey(rb, tableKey, &length, pErrorCode); 312 /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */ 313 ures_close(rb); 314 } 315 } else { 316 /* Language code should not be a number. If it is, set the error code. */ 317 if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) { 318 *pErrorCode = U_MISSING_RESOURCE_ERROR; 319 } else { 320 /* second-level item, use special fallback */ 321 s=uloc_getTableStringWithFallback(path, locale, 322 tableKey, 323 subTableKey, 324 itemKey, 325 &length, 326 pErrorCode); 327 } 328 } 329 330 if(U_SUCCESS(*pErrorCode)) { 331 int32_t copyLength=uprv_min(length, destCapacity); 332 if(copyLength>0 && s != NULL) { 333 u_memcpy(dest, s, copyLength); 334 } 335 } else { 336 /* no string from a resource bundle: convert the substitute */ 337 length=(int32_t)uprv_strlen(substitute); 338 u_charsToUChars(substitute, dest, uprv_min(length, destCapacity)); 339 *pErrorCode=U_USING_DEFAULT_WARNING; 340 } 341 342 return u_terminateUChars(dest, destCapacity, length, pErrorCode); 343 } 344 345 typedef int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *); 346 347 static int32_t 348 _getDisplayNameForComponent(const char *locale, 349 const char *displayLocale, 350 UChar *dest, int32_t destCapacity, 351 UDisplayNameGetter *getter, 352 const char *tag, 353 UErrorCode *pErrorCode) { 354 char localeBuffer[ULOC_FULLNAME_CAPACITY*4]; 355 int32_t length; 356 UErrorCode localStatus; 357 const char* root = NULL; 358 359 /* argument checking */ 360 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 361 return 0; 362 } 363 364 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 365 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 366 return 0; 367 } 368 369 localStatus = U_ZERO_ERROR; 370 length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus); 371 if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) { 372 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 373 return 0; 374 } 375 if(length==0) { 376 return u_terminateUChars(dest, destCapacity, 0, pErrorCode); 377 } 378 379 root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG; 380 381 return _getStringOrCopyKey(root, displayLocale, 382 tag, NULL, localeBuffer, 383 localeBuffer, 384 dest, destCapacity, 385 pErrorCode); 386 } 387 388 U_CAPI int32_t U_EXPORT2 389 uloc_getDisplayLanguage(const char *locale, 390 const char *displayLocale, 391 UChar *dest, int32_t destCapacity, 392 UErrorCode *pErrorCode) { 393 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 394 uloc_getLanguage, _kLanguages, pErrorCode); 395 } 396 397 U_CAPI int32_t U_EXPORT2 398 uloc_getDisplayScript(const char* locale, 399 const char* displayLocale, 400 UChar *dest, int32_t destCapacity, 401 UErrorCode *pErrorCode) 402 { 403 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 404 uloc_getScript, _kScripts, pErrorCode); 405 } 406 407 U_CAPI int32_t U_EXPORT2 408 uloc_getDisplayCountry(const char *locale, 409 const char *displayLocale, 410 UChar *dest, int32_t destCapacity, 411 UErrorCode *pErrorCode) { 412 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 413 uloc_getCountry, _kCountries, pErrorCode); 414 } 415 416 /* 417 * TODO separate variant1_variant2_variant3... 418 * by getting each tag's display string and concatenating them with ", " 419 * in between - similar to uloc_getDisplayName() 420 */ 421 U_CAPI int32_t U_EXPORT2 422 uloc_getDisplayVariant(const char *locale, 423 const char *displayLocale, 424 UChar *dest, int32_t destCapacity, 425 UErrorCode *pErrorCode) { 426 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 427 uloc_getVariant, _kVariants, pErrorCode); 428 } 429 430 /* Instead of having a separate pass for 'special' patterns, reintegrate the two 431 * so we don't get bitten by preflight bugs again. We can be reasonably efficient 432 * without two separate code paths, this code isn't that performance-critical. 433 * 434 * This code is general enough to deal with patterns that have a prefix or swap the 435 * language and remainder components, since we gave developers enough rope to do such 436 * things if they futz with the pattern data. But since we don't give them a way to 437 * specify a pattern for arbitrary combinations of components, there's not much use in 438 * that. I don't think our data includes such patterns, the only variable I know if is 439 * whether there is a space before the open paren, or not. Oh, and zh uses different 440 * chars than the standard open/close paren (which ja and ko use, btw). 441 */ 442 U_CAPI int32_t U_EXPORT2 443 uloc_getDisplayName(const char *locale, 444 const char *displayLocale, 445 UChar *dest, int32_t destCapacity, 446 UErrorCode *pErrorCode) 447 { 448 static const UChar defaultSeparator[3] = { 0x002c, 0x0020, 0x0000 }; /* comma + space */ 449 static const int32_t defaultSepLen = 2; 450 static const UChar sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */ 451 static const UChar sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */ 452 static const int32_t subLen = 3; 453 static const UChar defaultPattern[10] = { 454 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000 455 }; /* {0} ({1}) */ 456 static const int32_t defaultPatLen = 9; 457 static const int32_t defaultSub0Pos = 0; 458 static const int32_t defaultSub1Pos = 5; 459 460 int32_t length; /* of formatted result */ 461 462 const UChar *separator; 463 int32_t sepLen = 0; 464 const UChar *pattern; 465 int32_t patLen = 0; 466 int32_t sub0Pos, sub1Pos; 467 468 UBool haveLang = TRUE; /* assume true, set false if we find we don't have 469 a lang component in the locale */ 470 UBool haveRest = TRUE; /* assume true, set false if we find we don't have 471 any other component in the locale */ 472 UBool retry = FALSE; /* set true if we need to retry, see below */ 473 474 int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */ 475 476 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 477 return 0; 478 } 479 480 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 481 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 482 return 0; 483 } 484 485 { 486 UErrorCode status = U_ZERO_ERROR; 487 UResourceBundle* locbundle=ures_open(U_ICUDATA_LANG, displayLocale, &status); 488 UResourceBundle* dspbundle=ures_getByKeyWithFallback(locbundle, _kLocaleDisplayPattern, 489 NULL, &status); 490 491 separator=ures_getStringByKeyWithFallback(dspbundle, _kSeparator, &sepLen, &status); 492 pattern=ures_getStringByKeyWithFallback(dspbundle, _kPattern, &patLen, &status); 493 494 ures_close(dspbundle); 495 ures_close(locbundle); 496 } 497 498 /* If we couldn't find any data, then use the defaults */ 499 if(sepLen == 0) { 500 separator = defaultSeparator; 501 sepLen = defaultSepLen; 502 } 503 504 if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) { 505 pattern=defaultPattern; 506 patLen=defaultPatLen; 507 sub0Pos=defaultSub0Pos; 508 sub1Pos=defaultSub1Pos; 509 } else { /* non-default pattern */ 510 UChar *p0=u_strstr(pattern, sub0); 511 UChar *p1=u_strstr(pattern, sub1); 512 if (p0==NULL || p1==NULL) { 513 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 514 return 0; 515 } 516 sub0Pos=p0-pattern; 517 sub1Pos=p1-pattern; 518 if (sub1Pos < sub0Pos) { /* a very odd pattern */ 519 int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t; 520 langi=1; 521 } 522 } 523 524 /* We loop here because there is one case in which after the first pass we could need to 525 * reextract the data. If there's initial padding before the first element, we put in 526 * the padding and then write that element. If it turns out there's no second element, 527 * we didn't need the padding. If we do need the data (no preflight), and the first element 528 * would have fit but for the padding, we need to reextract. In this case (only) we 529 * adjust the parameters so padding is not added, and repeat. 530 */ 531 do { 532 UChar* p=dest; 533 int32_t patPos=0; /* position in the pattern, used for non-substitution portions */ 534 int32_t langLen=0; /* length of language substitution */ 535 int32_t langPos=0; /* position in output of language substitution */ 536 int32_t restLen=0; /* length of 'everything else' substitution */ 537 int32_t restPos=0; /* position in output of 'everything else' substitution */ 538 UEnumeration* kenum = NULL; /* keyword enumeration */ 539 540 /* prefix of pattern, extremely likely to be empty */ 541 if(sub0Pos) { 542 if(destCapacity >= sub0Pos) { 543 while (patPos < sub0Pos) { 544 *p++ = pattern[patPos++]; 545 } 546 } else { 547 patPos=sub0Pos; 548 } 549 length=sub0Pos; 550 } else { 551 length=0; 552 } 553 554 for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/ 555 UBool subdone = FALSE; /* set true when ready to move to next substitution */ 556 557 /* prep p and cap for calls to get display components, pin cap to 0 since 558 they complain if cap is negative */ 559 int32_t cap=destCapacity-length; 560 if (cap <= 0) { 561 cap=0; 562 } else { 563 p=dest+length; 564 } 565 566 if (subi == langi) { /* {0}*/ 567 if(haveLang) { 568 langPos=length; 569 langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode); 570 length+=langLen; 571 haveLang=langLen>0; 572 } 573 subdone=TRUE; 574 } else { /* {1} */ 575 if(!haveRest) { 576 subdone=TRUE; 577 } else { 578 int32_t len; /* length of component (plus other stuff) we just fetched */ 579 switch(resti++) { 580 case 0: 581 restPos=length; 582 len=uloc_getDisplayScript(locale, displayLocale, p, cap, pErrorCode); 583 break; 584 case 1: 585 len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode); 586 break; 587 case 2: 588 len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode); 589 break; 590 case 3: 591 kenum = uloc_openKeywords(locale, pErrorCode); 592 /* fall through */ 593 default: { 594 const char* kw=uenum_next(kenum, &len, pErrorCode); 595 if (kw == NULL) { 596 uenum_close(kenum); 597 len=0; /* mark that we didn't add a component */ 598 subdone=TRUE; 599 } else { 600 /* incorporating this behavior into the loop made it even more complex, 601 so just special case it here */ 602 len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode); 603 if(len) { 604 if(len < cap) { 605 p[len]=0x3d; /* '=', assume we'll need it */ 606 } 607 len+=1; 608 609 /* adjust for call to get keyword */ 610 cap-=len; 611 if(cap <= 0) { 612 cap=0; 613 } else { 614 p+=len; 615 } 616 } 617 /* reset for call below */ 618 if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) { 619 *pErrorCode=U_ZERO_ERROR; 620 } 621 int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale, 622 p, cap, pErrorCode); 623 if(len) { 624 if(vlen==0) { 625 --len; /* remove unneeded '=' */ 626 } 627 /* restore cap and p to what they were at start */ 628 cap=destCapacity-length; 629 if(cap <= 0) { 630 cap=0; 631 } else { 632 p=dest+length; 633 } 634 } 635 len+=vlen; /* total we added for key + '=' + value */ 636 } 637 } break; 638 } /* end switch */ 639 640 if (len>0) { 641 /* we addeed a component, so add separator and write it if there's room. */ 642 if(len+sepLen<=cap) { 643 p+=len; 644 for(int32_t i=0;i<sepLen;++i) { 645 *p++=separator[i]; 646 } 647 } 648 length+=len+sepLen; 649 } else if(subdone) { 650 /* remove separator if we added it */ 651 if (length!=restPos) { 652 length-=sepLen; 653 } 654 restLen=length-restPos; 655 haveRest=restLen>0; 656 } 657 } 658 } 659 660 if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) { 661 *pErrorCode=U_ZERO_ERROR; 662 } 663 664 if(subdone) { 665 if(haveLang && haveRest) { 666 /* append internal portion of pattern, the first time, 667 or last portion of pattern the second time */ 668 int32_t padLen; 669 patPos+=subLen; 670 padLen=(subi==0 ? sub1Pos : patLen)-patPos; 671 if(length+padLen < destCapacity) { 672 p=dest+length; 673 for(int32_t i=0;i<padLen;++i) { 674 *p++=pattern[patPos++]; 675 } 676 } else { 677 patPos+=padLen; 678 } 679 length+=padLen; 680 } else if(subi==0) { 681 /* don't have first component, reset for second component */ 682 sub0Pos=0; 683 length=0; 684 } else if(length>0) { 685 /* true length is the length of just the component we got. */ 686 length=haveLang?langLen:restLen; 687 if(dest && sub0Pos!=0) { 688 if (sub0Pos+length<=destCapacity) { 689 /* first component not at start of result, 690 but we have full component in buffer. */ 691 u_memmove(dest, dest+(haveLang?langPos:restPos), length); 692 } else { 693 /* would have fit, but didn't because of pattern prefix. */ 694 sub0Pos=0; /* stops initial padding (and a second retry, 695 so we won't end up here again) */ 696 retry=TRUE; 697 } 698 } 699 } 700 701 ++subi; /* move on to next substitution */ 702 } 703 } 704 } while(retry); 705 706 return u_terminateUChars(dest, destCapacity, length, pErrorCode); 707 } 708 709 U_CAPI int32_t U_EXPORT2 710 uloc_getDisplayKeyword(const char* keyword, 711 const char* displayLocale, 712 UChar* dest, 713 int32_t destCapacity, 714 UErrorCode* status){ 715 716 /* argument checking */ 717 if(status==NULL || U_FAILURE(*status)) { 718 return 0; 719 } 720 721 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 722 *status=U_ILLEGAL_ARGUMENT_ERROR; 723 return 0; 724 } 725 726 727 /* pass itemKey=NULL to look for a top-level item */ 728 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale, 729 _kKeys, NULL, 730 keyword, 731 keyword, 732 dest, destCapacity, 733 status); 734 735 } 736 737 738 #define UCURRENCY_DISPLAY_NAME_INDEX 1 739 740 U_CAPI int32_t U_EXPORT2 741 uloc_getDisplayKeywordValue( const char* locale, 742 const char* keyword, 743 const char* displayLocale, 744 UChar* dest, 745 int32_t destCapacity, 746 UErrorCode* status){ 747 748 749 char keywordValue[ULOC_FULLNAME_CAPACITY*4]; 750 int32_t capacity = ULOC_FULLNAME_CAPACITY*4; 751 int32_t keywordValueLen =0; 752 753 /* argument checking */ 754 if(status==NULL || U_FAILURE(*status)) { 755 return 0; 756 } 757 758 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 759 *status=U_ILLEGAL_ARGUMENT_ERROR; 760 return 0; 761 } 762 763 /* get the keyword value */ 764 keywordValue[0]=0; 765 keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status); 766 767 /* 768 * if the keyword is equal to currency .. then to get the display name 769 * we need to do the fallback ourselves 770 */ 771 if(uprv_stricmp(keyword, _kCurrency)==0){ 772 773 int32_t dispNameLen = 0; 774 const UChar *dispName = NULL; 775 776 UResourceBundle *bundle = ures_open(U_ICUDATA_CURR, displayLocale, status); 777 UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status); 778 UResourceBundle *currency = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status); 779 780 dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status); 781 782 /*close the bundles */ 783 ures_close(currency); 784 ures_close(currencies); 785 ures_close(bundle); 786 787 if(U_FAILURE(*status)){ 788 if(*status == U_MISSING_RESOURCE_ERROR){ 789 /* we just want to write the value over if nothing is available */ 790 *status = U_USING_DEFAULT_WARNING; 791 }else{ 792 return 0; 793 } 794 } 795 796 /* now copy the dispName over if not NULL */ 797 if(dispName != NULL){ 798 if(dispNameLen <= destCapacity){ 799 uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR); 800 return u_terminateUChars(dest, destCapacity, dispNameLen, status); 801 }else{ 802 *status = U_BUFFER_OVERFLOW_ERROR; 803 return dispNameLen; 804 } 805 }else{ 806 /* we have not found the display name for the value .. just copy over */ 807 if(keywordValueLen <= destCapacity){ 808 u_charsToUChars(keywordValue, dest, keywordValueLen); 809 return u_terminateUChars(dest, destCapacity, keywordValueLen, status); 810 }else{ 811 *status = U_BUFFER_OVERFLOW_ERROR; 812 return keywordValueLen; 813 } 814 } 815 816 817 }else{ 818 819 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale, 820 _kTypes, keyword, 821 keywordValue, 822 keywordValue, 823 dest, destCapacity, 824 status); 825 } 826 } 827