1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 1997-2010, 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 U_CAPI int32_t U_EXPORT2 431 uloc_getDisplayName(const char *locale, 432 const char *displayLocale, 433 UChar *dest, int32_t destCapacity, 434 UErrorCode *pErrorCode) 435 { 436 int32_t length, length2, length3 = 0; 437 UBool hasLanguage, hasScript, hasCountry, hasVariant, hasKeywords; 438 UEnumeration* keywordEnum = NULL; 439 int32_t keywordCount = 0; 440 const char *keyword = NULL; 441 int32_t keywordLen = 0; 442 char keywordValue[256]; 443 int32_t keywordValueLen = 0; 444 445 int32_t locSepLen = 0; 446 int32_t locPatLen = 0; 447 int32_t p0Len = 0; 448 int32_t defaultPatternLen = 9; 449 const UChar *dispLocSeparator; 450 const UChar *dispLocPattern; 451 static const UChar defaultSeparator[3] = { 0x002c, 0x0020 , 0x0000 }; /* comma + space */ 452 static const UChar defaultPattern[10] = { 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000 }; /* {0} ({1}) */ 453 static const UChar pat0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */ 454 static const UChar pat1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */ 455 456 UResourceBundle *bundle = NULL; 457 UResourceBundle *locdsppat = NULL; 458 459 UErrorCode status = U_ZERO_ERROR; 460 461 /* argument checking */ 462 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 463 return 0; 464 } 465 466 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 467 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 468 return 0; 469 } 470 471 bundle = ures_open(U_ICUDATA_LANG, displayLocale, &status); 472 473 locdsppat = ures_getByKeyWithFallback(bundle, _kLocaleDisplayPattern, NULL, &status); 474 dispLocSeparator = ures_getStringByKeyWithFallback(locdsppat, _kSeparator, &locSepLen, &status); 475 dispLocPattern = ures_getStringByKeyWithFallback(locdsppat, _kPattern, &locPatLen, &status); 476 477 /*close the bundles */ 478 ures_close(locdsppat); 479 ures_close(bundle); 480 481 /* If we couldn't find any data, then use the defaults */ 482 if ( locSepLen == 0) { 483 dispLocSeparator = defaultSeparator; 484 locSepLen = 2; 485 } 486 487 if ( locPatLen == 0) { 488 dispLocPattern = defaultPattern; 489 locPatLen = 9; 490 } 491 492 /* 493 * if there is a language, then write "language (country, variant)" 494 * otherwise write "country, variant" 495 */ 496 497 /* write the language */ 498 length=uloc_getDisplayLanguage(locale, displayLocale, 499 dest, destCapacity, 500 pErrorCode); 501 hasLanguage= length>0; 502 503 if(hasLanguage) { 504 p0Len = length; 505 506 /* append " (" */ 507 if(length<destCapacity) { 508 dest[length]=0x20; 509 } 510 ++length; 511 if(length<destCapacity) { 512 dest[length]=0x28; 513 } 514 ++length; 515 } 516 517 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { 518 /* keep preflighting */ 519 *pErrorCode=U_ZERO_ERROR; 520 } 521 522 /* append the script */ 523 if(length<destCapacity) { 524 length2=uloc_getDisplayScript(locale, displayLocale, 525 dest+length, destCapacity-length, 526 pErrorCode); 527 } else { 528 length2=uloc_getDisplayScript(locale, displayLocale, 529 NULL, 0, 530 pErrorCode); 531 } 532 hasScript= length2>0; 533 length+=length2; 534 535 if(hasScript) { 536 /* append separator */ 537 if(length+locSepLen<=destCapacity) { 538 u_memcpy(dest+length,dispLocSeparator,locSepLen); 539 } 540 length+=locSepLen; 541 } 542 543 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { 544 /* keep preflighting */ 545 *pErrorCode=U_ZERO_ERROR; 546 } 547 548 /* append the country */ 549 if(length<destCapacity) { 550 length2=uloc_getDisplayCountry(locale, displayLocale, 551 dest+length, destCapacity-length, 552 pErrorCode); 553 } else { 554 length2=uloc_getDisplayCountry(locale, displayLocale, 555 NULL, 0, 556 pErrorCode); 557 } 558 hasCountry= length2>0; 559 length+=length2; 560 561 if(hasCountry) { 562 /* append separator */ 563 if(length+locSepLen<=destCapacity) { 564 u_memcpy(dest+length,dispLocSeparator,locSepLen); 565 } 566 length+=locSepLen; 567 } 568 569 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { 570 /* keep preflighting */ 571 *pErrorCode=U_ZERO_ERROR; 572 } 573 574 /* append the variant */ 575 if(length<destCapacity) { 576 length2=uloc_getDisplayVariant(locale, displayLocale, 577 dest+length, destCapacity-length, 578 pErrorCode); 579 } else { 580 length2=uloc_getDisplayVariant(locale, displayLocale, 581 NULL, 0, 582 pErrorCode); 583 } 584 hasVariant= length2>0; 585 length+=length2; 586 587 if(hasVariant) { 588 /* append separator */ 589 if(length+locSepLen<=destCapacity) { 590 u_memcpy(dest+length,dispLocSeparator,locSepLen); 591 } 592 length+=locSepLen; 593 } 594 595 keywordEnum = uloc_openKeywords(locale, pErrorCode); 596 597 for(keywordCount = uenum_count(keywordEnum, pErrorCode); keywordCount > 0 ; keywordCount--){ 598 if(U_FAILURE(*pErrorCode)){ 599 break; 600 } 601 /* the uenum_next returns NUL terminated string */ 602 keyword = uenum_next(keywordEnum, &keywordLen, pErrorCode); 603 if(length + length3 < destCapacity) { 604 length3 += uloc_getDisplayKeyword(keyword, displayLocale, dest+length+length3, destCapacity-length-length3, pErrorCode); 605 } else { 606 length3 += uloc_getDisplayKeyword(keyword, displayLocale, NULL, 0, pErrorCode); 607 } 608 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { 609 /* keep preflighting */ 610 *pErrorCode=U_ZERO_ERROR; 611 } 612 keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, 256, pErrorCode); 613 if(keywordValueLen) { 614 if(length + length3 < destCapacity) { 615 dest[length + length3] = 0x3D; 616 } 617 length3++; 618 if(length + length3 < destCapacity) { 619 length3 += uloc_getDisplayKeywordValue(locale, keyword, displayLocale, dest+length+length3, destCapacity-length-length3, pErrorCode); 620 } else { 621 length3 += uloc_getDisplayKeywordValue(locale, keyword, displayLocale, NULL, 0, pErrorCode); 622 } 623 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { 624 /* keep preflighting */ 625 *pErrorCode=U_ZERO_ERROR; 626 } 627 } 628 if(keywordCount > 1) { 629 if(length + length3 + locSepLen <= destCapacity && keywordCount) { 630 u_memcpy(dest+length+length3,dispLocSeparator,locSepLen); 631 length3+=locSepLen; 632 } 633 } 634 } 635 uenum_close(keywordEnum); 636 637 hasKeywords = length3 > 0; 638 length += length3; 639 640 641 if ((hasScript && !hasCountry) 642 || ((hasScript || hasCountry) && !hasVariant && !hasKeywords) 643 || ((hasScript || hasCountry || hasVariant) && !hasKeywords)) { 644 /* Remove separator */ 645 length -= locSepLen; 646 } else if (hasLanguage && !hasScript && !hasCountry && !hasVariant && !hasKeywords) { 647 /* Remove " (" */ 648 length-=2; 649 } 650 651 if (hasLanguage && (hasScript || hasCountry || hasVariant || hasKeywords)) { 652 /* append ")" */ 653 if(length<destCapacity) { 654 dest[length]=0x29; 655 } 656 ++length; 657 658 /* If the localized display pattern is something other than the default pattern of "{0} ({1})", then 659 * then we need to do the formatting here. It would be easier to use a messageFormat to do this, but we 660 * can't since we don't have the APIs in the i18n library available to us at this point. 661 */ 662 if (locPatLen != defaultPatternLen || u_strcmp(dispLocPattern,defaultPattern)) { /* Something other than the default pattern */ 663 UChar *p0 = u_strstr(dispLocPattern,pat0); 664 UChar *p1 = u_strstr(dispLocPattern,pat1); 665 u_terminateUChars(dest, destCapacity, length, pErrorCode); 666 667 if ( p0 != NULL && p1 != NULL ) { /* The pattern is well formed */ 668 if ( dest ) { 669 int32_t destLen = 0; 670 UChar *result = (UChar *)uprv_malloc((length+1)*sizeof(UChar)); 671 UChar *upos = (UChar *)dispLocPattern; 672 u_strcpy(result,dest); 673 dest[0] = 0; 674 while ( *upos ) { 675 if ( upos == p0 ) { /* Handle {0} substitution */ 676 u_strncat(dest,result,p0Len); 677 destLen += p0Len; 678 dest[destLen] = 0; /* Null terminate */ 679 upos += 3; 680 } else if ( upos == p1 ) { /* Handle {1} substitution */ 681 UChar *p1Start = &result[p0Len+2]; 682 u_strncat(dest,p1Start,length-p0Len-3); 683 destLen += (length-p0Len-3); 684 dest[destLen] = 0; /* Null terminate */ 685 upos += 3; 686 } else { /* Something from the pattern not {0} or {1} */ 687 u_strncat(dest,upos,1); 688 upos++; 689 destLen++; 690 dest[destLen] = 0; /* Null terminate */ 691 } 692 } 693 length = destLen; 694 uprv_free(result); 695 } 696 } 697 } 698 } 699 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { 700 /* keep preflighting */ 701 *pErrorCode=U_ZERO_ERROR; 702 } 703 704 return u_terminateUChars(dest, destCapacity, length, pErrorCode); 705 } 706 707 U_CAPI int32_t U_EXPORT2 708 uloc_getDisplayKeyword(const char* keyword, 709 const char* displayLocale, 710 UChar* dest, 711 int32_t destCapacity, 712 UErrorCode* status){ 713 714 /* argument checking */ 715 if(status==NULL || U_FAILURE(*status)) { 716 return 0; 717 } 718 719 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 720 *status=U_ILLEGAL_ARGUMENT_ERROR; 721 return 0; 722 } 723 724 725 /* pass itemKey=NULL to look for a top-level item */ 726 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale, 727 _kKeys, NULL, 728 keyword, 729 keyword, 730 dest, destCapacity, 731 status); 732 733 } 734 735 736 #define UCURRENCY_DISPLAY_NAME_INDEX 1 737 738 U_CAPI int32_t U_EXPORT2 739 uloc_getDisplayKeywordValue( const char* locale, 740 const char* keyword, 741 const char* displayLocale, 742 UChar* dest, 743 int32_t destCapacity, 744 UErrorCode* status){ 745 746 747 char keywordValue[ULOC_FULLNAME_CAPACITY*4]; 748 int32_t capacity = ULOC_FULLNAME_CAPACITY*4; 749 int32_t keywordValueLen =0; 750 751 /* argument checking */ 752 if(status==NULL || U_FAILURE(*status)) { 753 return 0; 754 } 755 756 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 757 *status=U_ILLEGAL_ARGUMENT_ERROR; 758 return 0; 759 } 760 761 /* get the keyword value */ 762 keywordValue[0]=0; 763 keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status); 764 765 /* 766 * if the keyword is equal to currency .. then to get the display name 767 * we need to do the fallback ourselves 768 */ 769 if(uprv_stricmp(keyword, _kCurrency)==0){ 770 771 int32_t dispNameLen = 0; 772 const UChar *dispName = NULL; 773 774 UResourceBundle *bundle = ures_open(U_ICUDATA_CURR, displayLocale, status); 775 UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status); 776 UResourceBundle *currency = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status); 777 778 dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status); 779 780 /*close the bundles */ 781 ures_close(currency); 782 ures_close(currencies); 783 ures_close(bundle); 784 785 if(U_FAILURE(*status)){ 786 if(*status == U_MISSING_RESOURCE_ERROR){ 787 /* we just want to write the value over if nothing is available */ 788 *status = U_USING_DEFAULT_WARNING; 789 }else{ 790 return 0; 791 } 792 } 793 794 /* now copy the dispName over if not NULL */ 795 if(dispName != NULL){ 796 if(dispNameLen <= destCapacity){ 797 uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR); 798 return u_terminateUChars(dest, destCapacity, dispNameLen, status); 799 }else{ 800 *status = U_BUFFER_OVERFLOW_ERROR; 801 return dispNameLen; 802 } 803 }else{ 804 /* we have not found the display name for the value .. just copy over */ 805 if(keywordValueLen <= destCapacity){ 806 u_charsToUChars(keywordValue, dest, keywordValueLen); 807 return u_terminateUChars(dest, destCapacity, keywordValueLen, status); 808 }else{ 809 *status = U_BUFFER_OVERFLOW_ERROR; 810 return keywordValueLen; 811 } 812 } 813 814 815 }else{ 816 817 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale, 818 _kTypes, keyword, 819 keywordValue, 820 keywordValue, 821 dest, destCapacity, 822 status); 823 } 824 } 825