intl/icu/source/common/locdispnames.cpp

changeset 0
6474c204b198
     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 +}

mercurial