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