intl/icu/source/common/locdispnames.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial