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