1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 1997-2013, 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[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */ 469 static const UChar sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */ 470 static const UChar sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */ 471 static const int32_t subLen = 3; 472 static const UChar defaultPattern[10] = { 473 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000 474 }; /* {0} ({1}) */ 475 static const int32_t defaultPatLen = 9; 476 static const int32_t defaultSub0Pos = 0; 477 static const int32_t defaultSub1Pos = 5; 478 479 int32_t length; /* of formatted result */ 480 481 const UChar *separator; 482 int32_t sepLen = 0; 483 const UChar *pattern; 484 int32_t patLen = 0; 485 int32_t sub0Pos, sub1Pos; 486 487 UChar formatOpenParen = 0x0028; // ( 488 UChar formatReplaceOpenParen = 0x005B; // [ 489 UChar formatCloseParen = 0x0029; // ) 490 UChar formatReplaceCloseParen = 0x005D; // ] 491 492 UBool haveLang = TRUE; /* assume true, set false if we find we don't have 493 a lang component in the locale */ 494 UBool haveRest = TRUE; /* assume true, set false if we find we don't have 495 any other component in the locale */ 496 UBool retry = FALSE; /* set true if we need to retry, see below */ 497 498 int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */ 499 500 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 501 return 0; 502 } 503 504 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 505 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 506 return 0; 507 } 508 509 { 510 UErrorCode status = U_ZERO_ERROR; 511 UResourceBundle* locbundle=ures_open(U_ICUDATA_LANG, displayLocale, &status); 512 UResourceBundle* dspbundle=ures_getByKeyWithFallback(locbundle, _kLocaleDisplayPattern, 513 NULL, &status); 514 515 separator=ures_getStringByKeyWithFallback(dspbundle, _kSeparator, &sepLen, &status); 516 pattern=ures_getStringByKeyWithFallback(dspbundle, _kPattern, &patLen, &status); 517 518 ures_close(dspbundle); 519 ures_close(locbundle); 520 } 521 522 /* If we couldn't find any data, then use the defaults */ 523 if(sepLen == 0) { 524 separator = defaultSeparator; 525 } 526 /* #10244: Even though separator is now a pattern, it is awkward to handle it as such 527 * here since we are trying to build the display string in place in the dest buffer, 528 * and to handle it as a pattern would entail having separate storage for the 529 * substrings that need to be combined (the first of which may be the result of 530 * previous such combinations). So for now we continue to treat the portion between 531 * {0} and {1} as a string to be appended when joining substrings, ignoring anything 532 * that is before {0} or after {1} (no existing separator pattern has any such thing). 533 * This is similar to how pattern is handled below. 534 */ 535 { 536 UChar *p0=u_strstr(separator, sub0); 537 UChar *p1=u_strstr(separator, sub1); 538 if (p0==NULL || p1==NULL || p1<p0) { 539 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 540 return 0; 541 } 542 separator = (const UChar *)p0 + subLen; 543 sepLen = p1 - separator; 544 } 545 546 if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) { 547 pattern=defaultPattern; 548 patLen=defaultPatLen; 549 sub0Pos=defaultSub0Pos; 550 sub1Pos=defaultSub1Pos; 551 // use default formatOpenParen etc. set above 552 } else { /* non-default pattern */ 553 UChar *p0=u_strstr(pattern, sub0); 554 UChar *p1=u_strstr(pattern, sub1); 555 if (p0==NULL || p1==NULL) { 556 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 557 return 0; 558 } 559 sub0Pos=p0-pattern; 560 sub1Pos=p1-pattern; 561 if (sub1Pos < sub0Pos) { /* a very odd pattern */ 562 int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t; 563 langi=1; 564 } 565 if (u_strchr(pattern, 0xFF08) != NULL) { 566 formatOpenParen = 0xFF08; // fullwidth ( 567 formatReplaceOpenParen = 0xFF3B; // fullwidth [ 568 formatCloseParen = 0xFF09; // fullwidth ) 569 formatReplaceCloseParen = 0xFF3D; // fullwidth ] 570 } 571 } 572 573 /* We loop here because there is one case in which after the first pass we could need to 574 * reextract the data. If there's initial padding before the first element, we put in 575 * the padding and then write that element. If it turns out there's no second element, 576 * we didn't need the padding. If we do need the data (no preflight), and the first element 577 * would have fit but for the padding, we need to reextract. In this case (only) we 578 * adjust the parameters so padding is not added, and repeat. 579 */ 580 do { 581 UChar* p=dest; 582 int32_t patPos=0; /* position in the pattern, used for non-substitution portions */ 583 int32_t langLen=0; /* length of language substitution */ 584 int32_t langPos=0; /* position in output of language substitution */ 585 int32_t restLen=0; /* length of 'everything else' substitution */ 586 int32_t restPos=0; /* position in output of 'everything else' substitution */ 587 UEnumeration* kenum = NULL; /* keyword enumeration */ 588 589 /* prefix of pattern, extremely likely to be empty */ 590 if(sub0Pos) { 591 if(destCapacity >= sub0Pos) { 592 while (patPos < sub0Pos) { 593 *p++ = pattern[patPos++]; 594 } 595 } else { 596 patPos=sub0Pos; 597 } 598 length=sub0Pos; 599 } else { 600 length=0; 601 } 602 603 for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/ 604 UBool subdone = FALSE; /* set true when ready to move to next substitution */ 605 606 /* prep p and cap for calls to get display components, pin cap to 0 since 607 they complain if cap is negative */ 608 int32_t cap=destCapacity-length; 609 if (cap <= 0) { 610 cap=0; 611 } else { 612 p=dest+length; 613 } 614 615 if (subi == langi) { /* {0}*/ 616 if(haveLang) { 617 langPos=length; 618 langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode); 619 length+=langLen; 620 haveLang=langLen>0; 621 } 622 subdone=TRUE; 623 } else { /* {1} */ 624 if(!haveRest) { 625 subdone=TRUE; 626 } else { 627 int32_t len; /* length of component (plus other stuff) we just fetched */ 628 switch(resti++) { 629 case 0: 630 restPos=length; 631 len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode); 632 break; 633 case 1: 634 len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode); 635 break; 636 case 2: 637 len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode); 638 break; 639 case 3: 640 kenum = uloc_openKeywords(locale, pErrorCode); 641 /* fall through */ 642 default: { 643 const char* kw=uenum_next(kenum, &len, pErrorCode); 644 if (kw == NULL) { 645 uenum_close(kenum); 646 len=0; /* mark that we didn't add a component */ 647 subdone=TRUE; 648 } else { 649 /* incorporating this behavior into the loop made it even more complex, 650 so just special case it here */ 651 len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode); 652 if(len) { 653 if(len < cap) { 654 p[len]=0x3d; /* '=', assume we'll need it */ 655 } 656 len+=1; 657 658 /* adjust for call to get keyword */ 659 cap-=len; 660 if(cap <= 0) { 661 cap=0; 662 } else { 663 p+=len; 664 } 665 } 666 /* reset for call below */ 667 if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) { 668 *pErrorCode=U_ZERO_ERROR; 669 } 670 int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale, 671 p, cap, pErrorCode); 672 if(len) { 673 if(vlen==0) { 674 --len; /* remove unneeded '=' */ 675 } 676 /* restore cap and p to what they were at start */ 677 cap=destCapacity-length; 678 if(cap <= 0) { 679 cap=0; 680 } else { 681 p=dest+length; 682 } 683 } 684 len+=vlen; /* total we added for key + '=' + value */ 685 } 686 } break; 687 } /* end switch */ 688 689 if (len>0) { 690 /* we addeed a component, so add separator and write it if there's room. */ 691 if(len+sepLen<=cap) { 692 const UChar * plimit = p + len; 693 for (; p < plimit; p++) { 694 if (*p == formatOpenParen) { 695 *p = formatReplaceOpenParen; 696 } else if (*p == formatCloseParen) { 697 *p = formatReplaceCloseParen; 698 } 699 } 700 for(int32_t i=0;i<sepLen;++i) { 701 *p++=separator[i]; 702 } 703 } 704 length+=len+sepLen; 705 } else if(subdone) { 706 /* remove separator if we added it */ 707 if (length!=restPos) { 708 length-=sepLen; 709 } 710 restLen=length-restPos; 711 haveRest=restLen>0; 712 } 713 } 714 } 715 716 if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) { 717 *pErrorCode=U_ZERO_ERROR; 718 } 719 720 if(subdone) { 721 if(haveLang && haveRest) { 722 /* append internal portion of pattern, the first time, 723 or last portion of pattern the second time */ 724 int32_t padLen; 725 patPos+=subLen; 726 padLen=(subi==0 ? sub1Pos : patLen)-patPos; 727 if(length+padLen < destCapacity) { 728 p=dest+length; 729 for(int32_t i=0;i<padLen;++i) { 730 *p++=pattern[patPos++]; 731 } 732 } else { 733 patPos+=padLen; 734 } 735 length+=padLen; 736 } else if(subi==0) { 737 /* don't have first component, reset for second component */ 738 sub0Pos=0; 739 length=0; 740 } else if(length>0) { 741 /* true length is the length of just the component we got. */ 742 length=haveLang?langLen:restLen; 743 if(dest && sub0Pos!=0) { 744 if (sub0Pos+length<=destCapacity) { 745 /* first component not at start of result, 746 but we have full component in buffer. */ 747 u_memmove(dest, dest+(haveLang?langPos:restPos), length); 748 } else { 749 /* would have fit, but didn't because of pattern prefix. */ 750 sub0Pos=0; /* stops initial padding (and a second retry, 751 so we won't end up here again) */ 752 retry=TRUE; 753 } 754 } 755 } 756 757 ++subi; /* move on to next substitution */ 758 } 759 } 760 } while(retry); 761 762 return u_terminateUChars(dest, destCapacity, length, pErrorCode); 763 } 764 765 U_CAPI int32_t U_EXPORT2 766 uloc_getDisplayKeyword(const char* keyword, 767 const char* displayLocale, 768 UChar* dest, 769 int32_t destCapacity, 770 UErrorCode* status){ 771 772 /* argument checking */ 773 if(status==NULL || U_FAILURE(*status)) { 774 return 0; 775 } 776 777 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 778 *status=U_ILLEGAL_ARGUMENT_ERROR; 779 return 0; 780 } 781 782 783 /* pass itemKey=NULL to look for a top-level item */ 784 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale, 785 _kKeys, NULL, 786 keyword, 787 keyword, 788 dest, destCapacity, 789 status); 790 791 } 792 793 794 #define UCURRENCY_DISPLAY_NAME_INDEX 1 795 796 U_CAPI int32_t U_EXPORT2 797 uloc_getDisplayKeywordValue( const char* locale, 798 const char* keyword, 799 const char* displayLocale, 800 UChar* dest, 801 int32_t destCapacity, 802 UErrorCode* status){ 803 804 805 char keywordValue[ULOC_FULLNAME_CAPACITY*4]; 806 int32_t capacity = ULOC_FULLNAME_CAPACITY*4; 807 int32_t keywordValueLen =0; 808 809 /* argument checking */ 810 if(status==NULL || U_FAILURE(*status)) { 811 return 0; 812 } 813 814 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 815 *status=U_ILLEGAL_ARGUMENT_ERROR; 816 return 0; 817 } 818 819 /* get the keyword value */ 820 keywordValue[0]=0; 821 keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status); 822 823 /* 824 * if the keyword is equal to currency .. then to get the display name 825 * we need to do the fallback ourselves 826 */ 827 if(uprv_stricmp(keyword, _kCurrency)==0){ 828 829 int32_t dispNameLen = 0; 830 const UChar *dispName = NULL; 831 832 UResourceBundle *bundle = ures_open(U_ICUDATA_CURR, displayLocale, status); 833 UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status); 834 UResourceBundle *currency = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status); 835 836 dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status); 837 838 /*close the bundles */ 839 ures_close(currency); 840 ures_close(currencies); 841 ures_close(bundle); 842 843 if(U_FAILURE(*status)){ 844 if(*status == U_MISSING_RESOURCE_ERROR){ 845 /* we just want to write the value over if nothing is available */ 846 *status = U_USING_DEFAULT_WARNING; 847 }else{ 848 return 0; 849 } 850 } 851 852 /* now copy the dispName over if not NULL */ 853 if(dispName != NULL){ 854 if(dispNameLen <= destCapacity){ 855 uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR); 856 return u_terminateUChars(dest, destCapacity, dispNameLen, status); 857 }else{ 858 *status = U_BUFFER_OVERFLOW_ERROR; 859 return dispNameLen; 860 } 861 }else{ 862 /* we have not found the display name for the value .. just copy over */ 863 if(keywordValueLen <= destCapacity){ 864 u_charsToUChars(keywordValue, dest, keywordValueLen); 865 return u_terminateUChars(dest, destCapacity, keywordValueLen, status); 866 }else{ 867 *status = U_BUFFER_OVERFLOW_ERROR; 868 return keywordValueLen; 869 } 870 } 871 872 873 }else{ 874 875 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale, 876 _kTypes, keyword, 877 keywordValue, 878 keywordValue, 879 dest, destCapacity, 880 status); 881 } 882 } 883