1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/common/locdispnames.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,882 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* 1.7 +* Copyright (C) 1997-2013, International Business Machines 1.8 +* Corporation and others. All Rights Reserved. 1.9 +* 1.10 +******************************************************************************* 1.11 +* file name: locdispnames.cpp 1.12 +* encoding: US-ASCII 1.13 +* tab size: 8 (not used) 1.14 +* indentation:4 1.15 +* 1.16 +* created on: 2010feb25 1.17 +* created by: Markus W. Scherer 1.18 +* 1.19 +* Code for locale display names, separated out from other .cpp files 1.20 +* that then do not depend on resource bundle code and display name data. 1.21 +*/ 1.22 + 1.23 +#include "unicode/utypes.h" 1.24 +#include "unicode/brkiter.h" 1.25 +#include "unicode/locid.h" 1.26 +#include "unicode/uloc.h" 1.27 +#include "unicode/ures.h" 1.28 +#include "unicode/ustring.h" 1.29 +#include "cmemory.h" 1.30 +#include "cstring.h" 1.31 +#include "putilimp.h" 1.32 +#include "ulocimp.h" 1.33 +#include "uresimp.h" 1.34 +#include "ureslocs.h" 1.35 +#include "ustr_imp.h" 1.36 + 1.37 +// C++ API ----------------------------------------------------------------- *** 1.38 + 1.39 +U_NAMESPACE_BEGIN 1.40 + 1.41 +UnicodeString& 1.42 +Locale::getDisplayLanguage(UnicodeString& dispLang) const 1.43 +{ 1.44 + return this->getDisplayLanguage(getDefault(), dispLang); 1.45 +} 1.46 + 1.47 +/*We cannot make any assumptions on the size of the output display strings 1.48 +* Yet, since we are calling through to a C API, we need to set limits on 1.49 +* buffer size. For all the following getDisplay functions we first attempt 1.50 +* to fill up a stack allocated buffer. If it is to small we heap allocated 1.51 +* the exact buffer we need copy it to the UnicodeString and delete it*/ 1.52 + 1.53 +UnicodeString& 1.54 +Locale::getDisplayLanguage(const Locale &displayLocale, 1.55 + UnicodeString &result) const { 1.56 + UChar *buffer; 1.57 + UErrorCode errorCode=U_ZERO_ERROR; 1.58 + int32_t length; 1.59 + 1.60 + buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); 1.61 + if(buffer==0) { 1.62 + result.truncate(0); 1.63 + return result; 1.64 + } 1.65 + 1.66 + length=uloc_getDisplayLanguage(fullName, displayLocale.fullName, 1.67 + buffer, result.getCapacity(), 1.68 + &errorCode); 1.69 + result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 1.70 + 1.71 + if(errorCode==U_BUFFER_OVERFLOW_ERROR) { 1.72 + buffer=result.getBuffer(length); 1.73 + if(buffer==0) { 1.74 + result.truncate(0); 1.75 + return result; 1.76 + } 1.77 + errorCode=U_ZERO_ERROR; 1.78 + length=uloc_getDisplayLanguage(fullName, displayLocale.fullName, 1.79 + buffer, result.getCapacity(), 1.80 + &errorCode); 1.81 + result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 1.82 + } 1.83 + 1.84 + return result; 1.85 +} 1.86 + 1.87 +UnicodeString& 1.88 +Locale::getDisplayScript(UnicodeString& dispScript) const 1.89 +{ 1.90 + return this->getDisplayScript(getDefault(), dispScript); 1.91 +} 1.92 + 1.93 +UnicodeString& 1.94 +Locale::getDisplayScript(const Locale &displayLocale, 1.95 + UnicodeString &result) const { 1.96 + UChar *buffer; 1.97 + UErrorCode errorCode=U_ZERO_ERROR; 1.98 + int32_t length; 1.99 + 1.100 + buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); 1.101 + if(buffer==0) { 1.102 + result.truncate(0); 1.103 + return result; 1.104 + } 1.105 + 1.106 + length=uloc_getDisplayScript(fullName, displayLocale.fullName, 1.107 + buffer, result.getCapacity(), 1.108 + &errorCode); 1.109 + result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 1.110 + 1.111 + if(errorCode==U_BUFFER_OVERFLOW_ERROR) { 1.112 + buffer=result.getBuffer(length); 1.113 + if(buffer==0) { 1.114 + result.truncate(0); 1.115 + return result; 1.116 + } 1.117 + errorCode=U_ZERO_ERROR; 1.118 + length=uloc_getDisplayScript(fullName, displayLocale.fullName, 1.119 + buffer, result.getCapacity(), 1.120 + &errorCode); 1.121 + result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 1.122 + } 1.123 + 1.124 + return result; 1.125 +} 1.126 + 1.127 +UnicodeString& 1.128 +Locale::getDisplayCountry(UnicodeString& dispCntry) const 1.129 +{ 1.130 + return this->getDisplayCountry(getDefault(), dispCntry); 1.131 +} 1.132 + 1.133 +UnicodeString& 1.134 +Locale::getDisplayCountry(const Locale &displayLocale, 1.135 + UnicodeString &result) const { 1.136 + UChar *buffer; 1.137 + UErrorCode errorCode=U_ZERO_ERROR; 1.138 + int32_t length; 1.139 + 1.140 + buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); 1.141 + if(buffer==0) { 1.142 + result.truncate(0); 1.143 + return result; 1.144 + } 1.145 + 1.146 + length=uloc_getDisplayCountry(fullName, displayLocale.fullName, 1.147 + buffer, result.getCapacity(), 1.148 + &errorCode); 1.149 + result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 1.150 + 1.151 + if(errorCode==U_BUFFER_OVERFLOW_ERROR) { 1.152 + buffer=result.getBuffer(length); 1.153 + if(buffer==0) { 1.154 + result.truncate(0); 1.155 + return result; 1.156 + } 1.157 + errorCode=U_ZERO_ERROR; 1.158 + length=uloc_getDisplayCountry(fullName, displayLocale.fullName, 1.159 + buffer, result.getCapacity(), 1.160 + &errorCode); 1.161 + result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 1.162 + } 1.163 + 1.164 + return result; 1.165 +} 1.166 + 1.167 +UnicodeString& 1.168 +Locale::getDisplayVariant(UnicodeString& dispVar) const 1.169 +{ 1.170 + return this->getDisplayVariant(getDefault(), dispVar); 1.171 +} 1.172 + 1.173 +UnicodeString& 1.174 +Locale::getDisplayVariant(const Locale &displayLocale, 1.175 + UnicodeString &result) const { 1.176 + UChar *buffer; 1.177 + UErrorCode errorCode=U_ZERO_ERROR; 1.178 + int32_t length; 1.179 + 1.180 + buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); 1.181 + if(buffer==0) { 1.182 + result.truncate(0); 1.183 + return result; 1.184 + } 1.185 + 1.186 + length=uloc_getDisplayVariant(fullName, displayLocale.fullName, 1.187 + buffer, result.getCapacity(), 1.188 + &errorCode); 1.189 + result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 1.190 + 1.191 + if(errorCode==U_BUFFER_OVERFLOW_ERROR) { 1.192 + buffer=result.getBuffer(length); 1.193 + if(buffer==0) { 1.194 + result.truncate(0); 1.195 + return result; 1.196 + } 1.197 + errorCode=U_ZERO_ERROR; 1.198 + length=uloc_getDisplayVariant(fullName, displayLocale.fullName, 1.199 + buffer, result.getCapacity(), 1.200 + &errorCode); 1.201 + result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 1.202 + } 1.203 + 1.204 + return result; 1.205 +} 1.206 + 1.207 +UnicodeString& 1.208 +Locale::getDisplayName( UnicodeString& name ) const 1.209 +{ 1.210 + return this->getDisplayName(getDefault(), name); 1.211 +} 1.212 + 1.213 +UnicodeString& 1.214 +Locale::getDisplayName(const Locale &displayLocale, 1.215 + UnicodeString &result) const { 1.216 + UChar *buffer; 1.217 + UErrorCode errorCode=U_ZERO_ERROR; 1.218 + int32_t length; 1.219 + 1.220 + buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY); 1.221 + if(buffer==0) { 1.222 + result.truncate(0); 1.223 + return result; 1.224 + } 1.225 + 1.226 + length=uloc_getDisplayName(fullName, displayLocale.fullName, 1.227 + buffer, result.getCapacity(), 1.228 + &errorCode); 1.229 + result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 1.230 + 1.231 + if(errorCode==U_BUFFER_OVERFLOW_ERROR) { 1.232 + buffer=result.getBuffer(length); 1.233 + if(buffer==0) { 1.234 + result.truncate(0); 1.235 + return result; 1.236 + } 1.237 + errorCode=U_ZERO_ERROR; 1.238 + length=uloc_getDisplayName(fullName, displayLocale.fullName, 1.239 + buffer, result.getCapacity(), 1.240 + &errorCode); 1.241 + result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0); 1.242 + } 1.243 + 1.244 + return result; 1.245 +} 1.246 + 1.247 +#if ! UCONFIG_NO_BREAK_ITERATION 1.248 + 1.249 +// ------------------------------------- 1.250 +// Gets the objectLocale display name in the default locale language. 1.251 +UnicodeString& U_EXPORT2 1.252 +BreakIterator::getDisplayName(const Locale& objectLocale, 1.253 + UnicodeString& name) 1.254 +{ 1.255 + return objectLocale.getDisplayName(name); 1.256 +} 1.257 + 1.258 +// ------------------------------------- 1.259 +// Gets the objectLocale display name in the displayLocale language. 1.260 +UnicodeString& U_EXPORT2 1.261 +BreakIterator::getDisplayName(const Locale& objectLocale, 1.262 + const Locale& displayLocale, 1.263 + UnicodeString& name) 1.264 +{ 1.265 + return objectLocale.getDisplayName(displayLocale, name); 1.266 +} 1.267 + 1.268 +#endif 1.269 + 1.270 + 1.271 +U_NAMESPACE_END 1.272 + 1.273 +// C API ------------------------------------------------------------------- *** 1.274 + 1.275 +U_NAMESPACE_USE 1.276 + 1.277 +/* ### Constants **************************************************/ 1.278 + 1.279 +/* These strings describe the resources we attempt to load from 1.280 + the locale ResourceBundle data file.*/ 1.281 +static const char _kLanguages[] = "Languages"; 1.282 +static const char _kScripts[] = "Scripts"; 1.283 +static const char _kScriptsStandAlone[] = "Scripts%stand-alone"; 1.284 +static const char _kCountries[] = "Countries"; 1.285 +static const char _kVariants[] = "Variants"; 1.286 +static const char _kKeys[] = "Keys"; 1.287 +static const char _kTypes[] = "Types"; 1.288 +//static const char _kRootName[] = "root"; 1.289 +static const char _kCurrency[] = "currency"; 1.290 +static const char _kCurrencies[] = "Currencies"; 1.291 +static const char _kLocaleDisplayPattern[] = "localeDisplayPattern"; 1.292 +static const char _kPattern[] = "pattern"; 1.293 +static const char _kSeparator[] = "separator"; 1.294 + 1.295 +/* ### Display name **************************************************/ 1.296 + 1.297 +static int32_t 1.298 +_getStringOrCopyKey(const char *path, const char *locale, 1.299 + const char *tableKey, 1.300 + const char* subTableKey, 1.301 + const char *itemKey, 1.302 + const char *substitute, 1.303 + UChar *dest, int32_t destCapacity, 1.304 + UErrorCode *pErrorCode) { 1.305 + const UChar *s = NULL; 1.306 + int32_t length = 0; 1.307 + 1.308 + if(itemKey==NULL) { 1.309 + /* top-level item: normal resource bundle access */ 1.310 + UResourceBundle *rb; 1.311 + 1.312 + rb=ures_open(path, locale, pErrorCode); 1.313 + 1.314 + if(U_SUCCESS(*pErrorCode)) { 1.315 + s=ures_getStringByKey(rb, tableKey, &length, pErrorCode); 1.316 + /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */ 1.317 + ures_close(rb); 1.318 + } 1.319 + } else { 1.320 + /* Language code should not be a number. If it is, set the error code. */ 1.321 + if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) { 1.322 + *pErrorCode = U_MISSING_RESOURCE_ERROR; 1.323 + } else { 1.324 + /* second-level item, use special fallback */ 1.325 + s=uloc_getTableStringWithFallback(path, locale, 1.326 + tableKey, 1.327 + subTableKey, 1.328 + itemKey, 1.329 + &length, 1.330 + pErrorCode); 1.331 + } 1.332 + } 1.333 + 1.334 + if(U_SUCCESS(*pErrorCode)) { 1.335 + int32_t copyLength=uprv_min(length, destCapacity); 1.336 + if(copyLength>0 && s != NULL) { 1.337 + u_memcpy(dest, s, copyLength); 1.338 + } 1.339 + } else { 1.340 + /* no string from a resource bundle: convert the substitute */ 1.341 + length=(int32_t)uprv_strlen(substitute); 1.342 + u_charsToUChars(substitute, dest, uprv_min(length, destCapacity)); 1.343 + *pErrorCode=U_USING_DEFAULT_WARNING; 1.344 + } 1.345 + 1.346 + return u_terminateUChars(dest, destCapacity, length, pErrorCode); 1.347 +} 1.348 + 1.349 +typedef int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *); 1.350 + 1.351 +static int32_t 1.352 +_getDisplayNameForComponent(const char *locale, 1.353 + const char *displayLocale, 1.354 + UChar *dest, int32_t destCapacity, 1.355 + UDisplayNameGetter *getter, 1.356 + const char *tag, 1.357 + UErrorCode *pErrorCode) { 1.358 + char localeBuffer[ULOC_FULLNAME_CAPACITY*4]; 1.359 + int32_t length; 1.360 + UErrorCode localStatus; 1.361 + const char* root = NULL; 1.362 + 1.363 + /* argument checking */ 1.364 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.365 + return 0; 1.366 + } 1.367 + 1.368 + if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 1.369 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.370 + return 0; 1.371 + } 1.372 + 1.373 + localStatus = U_ZERO_ERROR; 1.374 + length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus); 1.375 + if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) { 1.376 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.377 + return 0; 1.378 + } 1.379 + if(length==0) { 1.380 + return u_terminateUChars(dest, destCapacity, 0, pErrorCode); 1.381 + } 1.382 + 1.383 + root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG; 1.384 + 1.385 + return _getStringOrCopyKey(root, displayLocale, 1.386 + tag, NULL, localeBuffer, 1.387 + localeBuffer, 1.388 + dest, destCapacity, 1.389 + pErrorCode); 1.390 +} 1.391 + 1.392 +U_CAPI int32_t U_EXPORT2 1.393 +uloc_getDisplayLanguage(const char *locale, 1.394 + const char *displayLocale, 1.395 + UChar *dest, int32_t destCapacity, 1.396 + UErrorCode *pErrorCode) { 1.397 + return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 1.398 + uloc_getLanguage, _kLanguages, pErrorCode); 1.399 +} 1.400 + 1.401 +U_CAPI int32_t U_EXPORT2 1.402 +uloc_getDisplayScript(const char* locale, 1.403 + const char* displayLocale, 1.404 + UChar *dest, int32_t destCapacity, 1.405 + UErrorCode *pErrorCode) 1.406 +{ 1.407 + UErrorCode err = U_ZERO_ERROR; 1.408 + int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 1.409 + uloc_getScript, _kScriptsStandAlone, &err); 1.410 + 1.411 + if ( err == U_USING_DEFAULT_WARNING ) { 1.412 + return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 1.413 + uloc_getScript, _kScripts, pErrorCode); 1.414 + } else { 1.415 + *pErrorCode = err; 1.416 + return res; 1.417 + } 1.418 +} 1.419 + 1.420 +U_INTERNAL int32_t U_EXPORT2 1.421 +uloc_getDisplayScriptInContext(const char* locale, 1.422 + const char* displayLocale, 1.423 + UChar *dest, int32_t destCapacity, 1.424 + UErrorCode *pErrorCode) 1.425 +{ 1.426 + return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 1.427 + uloc_getScript, _kScripts, pErrorCode); 1.428 +} 1.429 + 1.430 +U_CAPI int32_t U_EXPORT2 1.431 +uloc_getDisplayCountry(const char *locale, 1.432 + const char *displayLocale, 1.433 + UChar *dest, int32_t destCapacity, 1.434 + UErrorCode *pErrorCode) { 1.435 + return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 1.436 + uloc_getCountry, _kCountries, pErrorCode); 1.437 +} 1.438 + 1.439 +/* 1.440 + * TODO separate variant1_variant2_variant3... 1.441 + * by getting each tag's display string and concatenating them with ", " 1.442 + * in between - similar to uloc_getDisplayName() 1.443 + */ 1.444 +U_CAPI int32_t U_EXPORT2 1.445 +uloc_getDisplayVariant(const char *locale, 1.446 + const char *displayLocale, 1.447 + UChar *dest, int32_t destCapacity, 1.448 + UErrorCode *pErrorCode) { 1.449 + return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity, 1.450 + uloc_getVariant, _kVariants, pErrorCode); 1.451 +} 1.452 + 1.453 +/* Instead of having a separate pass for 'special' patterns, reintegrate the two 1.454 + * so we don't get bitten by preflight bugs again. We can be reasonably efficient 1.455 + * without two separate code paths, this code isn't that performance-critical. 1.456 + * 1.457 + * This code is general enough to deal with patterns that have a prefix or swap the 1.458 + * language and remainder components, since we gave developers enough rope to do such 1.459 + * things if they futz with the pattern data. But since we don't give them a way to 1.460 + * specify a pattern for arbitrary combinations of components, there's not much use in 1.461 + * that. I don't think our data includes such patterns, the only variable I know if is 1.462 + * whether there is a space before the open paren, or not. Oh, and zh uses different 1.463 + * chars than the standard open/close paren (which ja and ko use, btw). 1.464 + */ 1.465 +U_CAPI int32_t U_EXPORT2 1.466 +uloc_getDisplayName(const char *locale, 1.467 + const char *displayLocale, 1.468 + UChar *dest, int32_t destCapacity, 1.469 + UErrorCode *pErrorCode) 1.470 +{ 1.471 + static const UChar defaultSeparator[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */ 1.472 + static const UChar sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */ 1.473 + static const UChar sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */ 1.474 + static const int32_t subLen = 3; 1.475 + static const UChar defaultPattern[10] = { 1.476 + 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000 1.477 + }; /* {0} ({1}) */ 1.478 + static const int32_t defaultPatLen = 9; 1.479 + static const int32_t defaultSub0Pos = 0; 1.480 + static const int32_t defaultSub1Pos = 5; 1.481 + 1.482 + int32_t length; /* of formatted result */ 1.483 + 1.484 + const UChar *separator; 1.485 + int32_t sepLen = 0; 1.486 + const UChar *pattern; 1.487 + int32_t patLen = 0; 1.488 + int32_t sub0Pos, sub1Pos; 1.489 + 1.490 + UChar formatOpenParen = 0x0028; // ( 1.491 + UChar formatReplaceOpenParen = 0x005B; // [ 1.492 + UChar formatCloseParen = 0x0029; // ) 1.493 + UChar formatReplaceCloseParen = 0x005D; // ] 1.494 + 1.495 + UBool haveLang = TRUE; /* assume true, set false if we find we don't have 1.496 + a lang component in the locale */ 1.497 + UBool haveRest = TRUE; /* assume true, set false if we find we don't have 1.498 + any other component in the locale */ 1.499 + UBool retry = FALSE; /* set true if we need to retry, see below */ 1.500 + 1.501 + int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */ 1.502 + 1.503 + if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 1.504 + return 0; 1.505 + } 1.506 + 1.507 + if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 1.508 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.509 + return 0; 1.510 + } 1.511 + 1.512 + { 1.513 + UErrorCode status = U_ZERO_ERROR; 1.514 + UResourceBundle* locbundle=ures_open(U_ICUDATA_LANG, displayLocale, &status); 1.515 + UResourceBundle* dspbundle=ures_getByKeyWithFallback(locbundle, _kLocaleDisplayPattern, 1.516 + NULL, &status); 1.517 + 1.518 + separator=ures_getStringByKeyWithFallback(dspbundle, _kSeparator, &sepLen, &status); 1.519 + pattern=ures_getStringByKeyWithFallback(dspbundle, _kPattern, &patLen, &status); 1.520 + 1.521 + ures_close(dspbundle); 1.522 + ures_close(locbundle); 1.523 + } 1.524 + 1.525 + /* If we couldn't find any data, then use the defaults */ 1.526 + if(sepLen == 0) { 1.527 + separator = defaultSeparator; 1.528 + } 1.529 + /* #10244: Even though separator is now a pattern, it is awkward to handle it as such 1.530 + * here since we are trying to build the display string in place in the dest buffer, 1.531 + * and to handle it as a pattern would entail having separate storage for the 1.532 + * substrings that need to be combined (the first of which may be the result of 1.533 + * previous such combinations). So for now we continue to treat the portion between 1.534 + * {0} and {1} as a string to be appended when joining substrings, ignoring anything 1.535 + * that is before {0} or after {1} (no existing separator pattern has any such thing). 1.536 + * This is similar to how pattern is handled below. 1.537 + */ 1.538 + { 1.539 + UChar *p0=u_strstr(separator, sub0); 1.540 + UChar *p1=u_strstr(separator, sub1); 1.541 + if (p0==NULL || p1==NULL || p1<p0) { 1.542 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.543 + return 0; 1.544 + } 1.545 + separator = (const UChar *)p0 + subLen; 1.546 + sepLen = p1 - separator; 1.547 + } 1.548 + 1.549 + if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) { 1.550 + pattern=defaultPattern; 1.551 + patLen=defaultPatLen; 1.552 + sub0Pos=defaultSub0Pos; 1.553 + sub1Pos=defaultSub1Pos; 1.554 + // use default formatOpenParen etc. set above 1.555 + } else { /* non-default pattern */ 1.556 + UChar *p0=u_strstr(pattern, sub0); 1.557 + UChar *p1=u_strstr(pattern, sub1); 1.558 + if (p0==NULL || p1==NULL) { 1.559 + *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 1.560 + return 0; 1.561 + } 1.562 + sub0Pos=p0-pattern; 1.563 + sub1Pos=p1-pattern; 1.564 + if (sub1Pos < sub0Pos) { /* a very odd pattern */ 1.565 + int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t; 1.566 + langi=1; 1.567 + } 1.568 + if (u_strchr(pattern, 0xFF08) != NULL) { 1.569 + formatOpenParen = 0xFF08; // fullwidth ( 1.570 + formatReplaceOpenParen = 0xFF3B; // fullwidth [ 1.571 + formatCloseParen = 0xFF09; // fullwidth ) 1.572 + formatReplaceCloseParen = 0xFF3D; // fullwidth ] 1.573 + } 1.574 + } 1.575 + 1.576 + /* We loop here because there is one case in which after the first pass we could need to 1.577 + * reextract the data. If there's initial padding before the first element, we put in 1.578 + * the padding and then write that element. If it turns out there's no second element, 1.579 + * we didn't need the padding. If we do need the data (no preflight), and the first element 1.580 + * would have fit but for the padding, we need to reextract. In this case (only) we 1.581 + * adjust the parameters so padding is not added, and repeat. 1.582 + */ 1.583 + do { 1.584 + UChar* p=dest; 1.585 + int32_t patPos=0; /* position in the pattern, used for non-substitution portions */ 1.586 + int32_t langLen=0; /* length of language substitution */ 1.587 + int32_t langPos=0; /* position in output of language substitution */ 1.588 + int32_t restLen=0; /* length of 'everything else' substitution */ 1.589 + int32_t restPos=0; /* position in output of 'everything else' substitution */ 1.590 + UEnumeration* kenum = NULL; /* keyword enumeration */ 1.591 + 1.592 + /* prefix of pattern, extremely likely to be empty */ 1.593 + if(sub0Pos) { 1.594 + if(destCapacity >= sub0Pos) { 1.595 + while (patPos < sub0Pos) { 1.596 + *p++ = pattern[patPos++]; 1.597 + } 1.598 + } else { 1.599 + patPos=sub0Pos; 1.600 + } 1.601 + length=sub0Pos; 1.602 + } else { 1.603 + length=0; 1.604 + } 1.605 + 1.606 + for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/ 1.607 + UBool subdone = FALSE; /* set true when ready to move to next substitution */ 1.608 + 1.609 + /* prep p and cap for calls to get display components, pin cap to 0 since 1.610 + they complain if cap is negative */ 1.611 + int32_t cap=destCapacity-length; 1.612 + if (cap <= 0) { 1.613 + cap=0; 1.614 + } else { 1.615 + p=dest+length; 1.616 + } 1.617 + 1.618 + if (subi == langi) { /* {0}*/ 1.619 + if(haveLang) { 1.620 + langPos=length; 1.621 + langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode); 1.622 + length+=langLen; 1.623 + haveLang=langLen>0; 1.624 + } 1.625 + subdone=TRUE; 1.626 + } else { /* {1} */ 1.627 + if(!haveRest) { 1.628 + subdone=TRUE; 1.629 + } else { 1.630 + int32_t len; /* length of component (plus other stuff) we just fetched */ 1.631 + switch(resti++) { 1.632 + case 0: 1.633 + restPos=length; 1.634 + len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode); 1.635 + break; 1.636 + case 1: 1.637 + len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode); 1.638 + break; 1.639 + case 2: 1.640 + len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode); 1.641 + break; 1.642 + case 3: 1.643 + kenum = uloc_openKeywords(locale, pErrorCode); 1.644 + /* fall through */ 1.645 + default: { 1.646 + const char* kw=uenum_next(kenum, &len, pErrorCode); 1.647 + if (kw == NULL) { 1.648 + uenum_close(kenum); 1.649 + len=0; /* mark that we didn't add a component */ 1.650 + subdone=TRUE; 1.651 + } else { 1.652 + /* incorporating this behavior into the loop made it even more complex, 1.653 + so just special case it here */ 1.654 + len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode); 1.655 + if(len) { 1.656 + if(len < cap) { 1.657 + p[len]=0x3d; /* '=', assume we'll need it */ 1.658 + } 1.659 + len+=1; 1.660 + 1.661 + /* adjust for call to get keyword */ 1.662 + cap-=len; 1.663 + if(cap <= 0) { 1.664 + cap=0; 1.665 + } else { 1.666 + p+=len; 1.667 + } 1.668 + } 1.669 + /* reset for call below */ 1.670 + if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) { 1.671 + *pErrorCode=U_ZERO_ERROR; 1.672 + } 1.673 + int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale, 1.674 + p, cap, pErrorCode); 1.675 + if(len) { 1.676 + if(vlen==0) { 1.677 + --len; /* remove unneeded '=' */ 1.678 + } 1.679 + /* restore cap and p to what they were at start */ 1.680 + cap=destCapacity-length; 1.681 + if(cap <= 0) { 1.682 + cap=0; 1.683 + } else { 1.684 + p=dest+length; 1.685 + } 1.686 + } 1.687 + len+=vlen; /* total we added for key + '=' + value */ 1.688 + } 1.689 + } break; 1.690 + } /* end switch */ 1.691 + 1.692 + if (len>0) { 1.693 + /* we addeed a component, so add separator and write it if there's room. */ 1.694 + if(len+sepLen<=cap) { 1.695 + const UChar * plimit = p + len; 1.696 + for (; p < plimit; p++) { 1.697 + if (*p == formatOpenParen) { 1.698 + *p = formatReplaceOpenParen; 1.699 + } else if (*p == formatCloseParen) { 1.700 + *p = formatReplaceCloseParen; 1.701 + } 1.702 + } 1.703 + for(int32_t i=0;i<sepLen;++i) { 1.704 + *p++=separator[i]; 1.705 + } 1.706 + } 1.707 + length+=len+sepLen; 1.708 + } else if(subdone) { 1.709 + /* remove separator if we added it */ 1.710 + if (length!=restPos) { 1.711 + length-=sepLen; 1.712 + } 1.713 + restLen=length-restPos; 1.714 + haveRest=restLen>0; 1.715 + } 1.716 + } 1.717 + } 1.718 + 1.719 + if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) { 1.720 + *pErrorCode=U_ZERO_ERROR; 1.721 + } 1.722 + 1.723 + if(subdone) { 1.724 + if(haveLang && haveRest) { 1.725 + /* append internal portion of pattern, the first time, 1.726 + or last portion of pattern the second time */ 1.727 + int32_t padLen; 1.728 + patPos+=subLen; 1.729 + padLen=(subi==0 ? sub1Pos : patLen)-patPos; 1.730 + if(length+padLen < destCapacity) { 1.731 + p=dest+length; 1.732 + for(int32_t i=0;i<padLen;++i) { 1.733 + *p++=pattern[patPos++]; 1.734 + } 1.735 + } else { 1.736 + patPos+=padLen; 1.737 + } 1.738 + length+=padLen; 1.739 + } else if(subi==0) { 1.740 + /* don't have first component, reset for second component */ 1.741 + sub0Pos=0; 1.742 + length=0; 1.743 + } else if(length>0) { 1.744 + /* true length is the length of just the component we got. */ 1.745 + length=haveLang?langLen:restLen; 1.746 + if(dest && sub0Pos!=0) { 1.747 + if (sub0Pos+length<=destCapacity) { 1.748 + /* first component not at start of result, 1.749 + but we have full component in buffer. */ 1.750 + u_memmove(dest, dest+(haveLang?langPos:restPos), length); 1.751 + } else { 1.752 + /* would have fit, but didn't because of pattern prefix. */ 1.753 + sub0Pos=0; /* stops initial padding (and a second retry, 1.754 + so we won't end up here again) */ 1.755 + retry=TRUE; 1.756 + } 1.757 + } 1.758 + } 1.759 + 1.760 + ++subi; /* move on to next substitution */ 1.761 + } 1.762 + } 1.763 + } while(retry); 1.764 + 1.765 + return u_terminateUChars(dest, destCapacity, length, pErrorCode); 1.766 +} 1.767 + 1.768 +U_CAPI int32_t U_EXPORT2 1.769 +uloc_getDisplayKeyword(const char* keyword, 1.770 + const char* displayLocale, 1.771 + UChar* dest, 1.772 + int32_t destCapacity, 1.773 + UErrorCode* status){ 1.774 + 1.775 + /* argument checking */ 1.776 + if(status==NULL || U_FAILURE(*status)) { 1.777 + return 0; 1.778 + } 1.779 + 1.780 + if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 1.781 + *status=U_ILLEGAL_ARGUMENT_ERROR; 1.782 + return 0; 1.783 + } 1.784 + 1.785 + 1.786 + /* pass itemKey=NULL to look for a top-level item */ 1.787 + return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale, 1.788 + _kKeys, NULL, 1.789 + keyword, 1.790 + keyword, 1.791 + dest, destCapacity, 1.792 + status); 1.793 + 1.794 +} 1.795 + 1.796 + 1.797 +#define UCURRENCY_DISPLAY_NAME_INDEX 1 1.798 + 1.799 +U_CAPI int32_t U_EXPORT2 1.800 +uloc_getDisplayKeywordValue( const char* locale, 1.801 + const char* keyword, 1.802 + const char* displayLocale, 1.803 + UChar* dest, 1.804 + int32_t destCapacity, 1.805 + UErrorCode* status){ 1.806 + 1.807 + 1.808 + char keywordValue[ULOC_FULLNAME_CAPACITY*4]; 1.809 + int32_t capacity = ULOC_FULLNAME_CAPACITY*4; 1.810 + int32_t keywordValueLen =0; 1.811 + 1.812 + /* argument checking */ 1.813 + if(status==NULL || U_FAILURE(*status)) { 1.814 + return 0; 1.815 + } 1.816 + 1.817 + if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { 1.818 + *status=U_ILLEGAL_ARGUMENT_ERROR; 1.819 + return 0; 1.820 + } 1.821 + 1.822 + /* get the keyword value */ 1.823 + keywordValue[0]=0; 1.824 + keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status); 1.825 + 1.826 + /* 1.827 + * if the keyword is equal to currency .. then to get the display name 1.828 + * we need to do the fallback ourselves 1.829 + */ 1.830 + if(uprv_stricmp(keyword, _kCurrency)==0){ 1.831 + 1.832 + int32_t dispNameLen = 0; 1.833 + const UChar *dispName = NULL; 1.834 + 1.835 + UResourceBundle *bundle = ures_open(U_ICUDATA_CURR, displayLocale, status); 1.836 + UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status); 1.837 + UResourceBundle *currency = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status); 1.838 + 1.839 + dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status); 1.840 + 1.841 + /*close the bundles */ 1.842 + ures_close(currency); 1.843 + ures_close(currencies); 1.844 + ures_close(bundle); 1.845 + 1.846 + if(U_FAILURE(*status)){ 1.847 + if(*status == U_MISSING_RESOURCE_ERROR){ 1.848 + /* we just want to write the value over if nothing is available */ 1.849 + *status = U_USING_DEFAULT_WARNING; 1.850 + }else{ 1.851 + return 0; 1.852 + } 1.853 + } 1.854 + 1.855 + /* now copy the dispName over if not NULL */ 1.856 + if(dispName != NULL){ 1.857 + if(dispNameLen <= destCapacity){ 1.858 + uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR); 1.859 + return u_terminateUChars(dest, destCapacity, dispNameLen, status); 1.860 + }else{ 1.861 + *status = U_BUFFER_OVERFLOW_ERROR; 1.862 + return dispNameLen; 1.863 + } 1.864 + }else{ 1.865 + /* we have not found the display name for the value .. just copy over */ 1.866 + if(keywordValueLen <= destCapacity){ 1.867 + u_charsToUChars(keywordValue, dest, keywordValueLen); 1.868 + return u_terminateUChars(dest, destCapacity, keywordValueLen, status); 1.869 + }else{ 1.870 + *status = U_BUFFER_OVERFLOW_ERROR; 1.871 + return keywordValueLen; 1.872 + } 1.873 + } 1.874 + 1.875 + 1.876 + }else{ 1.877 + 1.878 + return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale, 1.879 + _kTypes, keyword, 1.880 + keywordValue, 1.881 + keywordValue, 1.882 + dest, destCapacity, 1.883 + status); 1.884 + } 1.885 +}