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