Home | History | Annotate | Download | only in common
      1 /*
      2 *******************************************************************************
      3 *
      4 *   Copyright (C) 1997-2010, 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 _kCountries[]       = "Countries";
    281 static const char _kVariants[]        = "Variants";
    282 static const char _kKeys[]            = "Keys";
    283 static const char _kTypes[]           = "Types";
    284 static const char _kRootName[]        = "root";
    285 static const char _kCurrency[]        = "currency";
    286 static const char _kCurrencies[]      = "Currencies";
    287 static const char _kLocaleDisplayPattern[] = "localeDisplayPattern";
    288 static const char _kPattern[]         = "pattern";
    289 static const char _kSeparator[]       = "separator";
    290 
    291 /* ### Display name **************************************************/
    292 
    293 static int32_t
    294 _getStringOrCopyKey(const char *path, const char *locale,
    295                     const char *tableKey,
    296                     const char* subTableKey,
    297                     const char *itemKey,
    298                     const char *substitute,
    299                     UChar *dest, int32_t destCapacity,
    300                     UErrorCode *pErrorCode) {
    301     const UChar *s = NULL;
    302     int32_t length = 0;
    303 
    304     if(itemKey==NULL) {
    305         /* top-level item: normal resource bundle access */
    306         UResourceBundle *rb;
    307 
    308         rb=ures_open(path, locale, pErrorCode);
    309 
    310         if(U_SUCCESS(*pErrorCode)) {
    311             s=ures_getStringByKey(rb, tableKey, &length, pErrorCode);
    312             /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
    313             ures_close(rb);
    314         }
    315     } else {
    316         /* Language code should not be a number. If it is, set the error code. */
    317         if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) {
    318             *pErrorCode = U_MISSING_RESOURCE_ERROR;
    319         } else {
    320             /* second-level item, use special fallback */
    321             s=uloc_getTableStringWithFallback(path, locale,
    322                                                tableKey,
    323                                                subTableKey,
    324                                                itemKey,
    325                                                &length,
    326                                                pErrorCode);
    327         }
    328     }
    329 
    330     if(U_SUCCESS(*pErrorCode)) {
    331         int32_t copyLength=uprv_min(length, destCapacity);
    332         if(copyLength>0 && s != NULL) {
    333             u_memcpy(dest, s, copyLength);
    334         }
    335     } else {
    336         /* no string from a resource bundle: convert the substitute */
    337         length=(int32_t)uprv_strlen(substitute);
    338         u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
    339         *pErrorCode=U_USING_DEFAULT_WARNING;
    340     }
    341 
    342     return u_terminateUChars(dest, destCapacity, length, pErrorCode);
    343 }
    344 
    345 typedef  int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *);
    346 
    347 static int32_t
    348 _getDisplayNameForComponent(const char *locale,
    349                             const char *displayLocale,
    350                             UChar *dest, int32_t destCapacity,
    351                             UDisplayNameGetter *getter,
    352                             const char *tag,
    353                             UErrorCode *pErrorCode) {
    354     char localeBuffer[ULOC_FULLNAME_CAPACITY*4];
    355     int32_t length;
    356     UErrorCode localStatus;
    357     const char* root = NULL;
    358 
    359     /* argument checking */
    360     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    361         return 0;
    362     }
    363 
    364     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
    365         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    366         return 0;
    367     }
    368 
    369     localStatus = U_ZERO_ERROR;
    370     length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
    371     if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
    372         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    373         return 0;
    374     }
    375     if(length==0) {
    376         return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
    377     }
    378 
    379     root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
    380 
    381     return _getStringOrCopyKey(root, displayLocale,
    382                                tag, NULL, localeBuffer,
    383                                localeBuffer,
    384                                dest, destCapacity,
    385                                pErrorCode);
    386 }
    387 
    388 U_CAPI int32_t U_EXPORT2
    389 uloc_getDisplayLanguage(const char *locale,
    390                         const char *displayLocale,
    391                         UChar *dest, int32_t destCapacity,
    392                         UErrorCode *pErrorCode) {
    393     return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
    394                 uloc_getLanguage, _kLanguages, pErrorCode);
    395 }
    396 
    397 U_CAPI int32_t U_EXPORT2
    398 uloc_getDisplayScript(const char* locale,
    399                       const char* displayLocale,
    400                       UChar *dest, int32_t destCapacity,
    401                       UErrorCode *pErrorCode)
    402 {
    403     return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
    404                 uloc_getScript, _kScripts, pErrorCode);
    405 }
    406 
    407 U_CAPI int32_t U_EXPORT2
    408 uloc_getDisplayCountry(const char *locale,
    409                        const char *displayLocale,
    410                        UChar *dest, int32_t destCapacity,
    411                        UErrorCode *pErrorCode) {
    412     return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
    413                 uloc_getCountry, _kCountries, pErrorCode);
    414 }
    415 
    416 /*
    417  * TODO separate variant1_variant2_variant3...
    418  * by getting each tag's display string and concatenating them with ", "
    419  * in between - similar to uloc_getDisplayName()
    420  */
    421 U_CAPI int32_t U_EXPORT2
    422 uloc_getDisplayVariant(const char *locale,
    423                        const char *displayLocale,
    424                        UChar *dest, int32_t destCapacity,
    425                        UErrorCode *pErrorCode) {
    426     return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
    427                 uloc_getVariant, _kVariants, pErrorCode);
    428 }
    429 
    430 U_CAPI int32_t U_EXPORT2
    431 uloc_getDisplayName(const char *locale,
    432                     const char *displayLocale,
    433                     UChar *dest, int32_t destCapacity,
    434                     UErrorCode *pErrorCode)
    435 {
    436     int32_t length, length2, length3 = 0;
    437     UBool hasLanguage, hasScript, hasCountry, hasVariant, hasKeywords;
    438     UEnumeration* keywordEnum = NULL;
    439     int32_t keywordCount = 0;
    440     const char *keyword = NULL;
    441     int32_t keywordLen = 0;
    442     char keywordValue[256];
    443     int32_t keywordValueLen = 0;
    444 
    445     int32_t locSepLen = 0;
    446     int32_t locPatLen = 0;
    447     int32_t p0Len = 0;
    448     int32_t defaultPatternLen = 9;
    449     const UChar *dispLocSeparator;
    450     const UChar *dispLocPattern;
    451     static const UChar defaultSeparator[3] = { 0x002c, 0x0020 , 0x0000 }; /* comma + space */
    452     static const UChar defaultPattern[10] = { 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000 }; /* {0} ({1}) */
    453     static const UChar pat0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
    454     static const UChar pat1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
    455 
    456     UResourceBundle *bundle = NULL;
    457     UResourceBundle *locdsppat = NULL;
    458 
    459     UErrorCode status = U_ZERO_ERROR;
    460 
    461     /* argument checking */
    462     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
    463         return 0;
    464     }
    465 
    466     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
    467         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    468         return 0;
    469     }
    470 
    471     bundle    = ures_open(U_ICUDATA_LANG, displayLocale, &status);
    472 
    473     locdsppat = ures_getByKeyWithFallback(bundle, _kLocaleDisplayPattern, NULL, &status);
    474     dispLocSeparator = ures_getStringByKeyWithFallback(locdsppat, _kSeparator, &locSepLen, &status);
    475     dispLocPattern = ures_getStringByKeyWithFallback(locdsppat, _kPattern, &locPatLen, &status);
    476 
    477     /*close the bundles */
    478     ures_close(locdsppat);
    479     ures_close(bundle);
    480 
    481     /* If we couldn't find any data, then use the defaults */
    482     if ( locSepLen == 0) {
    483        dispLocSeparator = defaultSeparator;
    484        locSepLen = 2;
    485     }
    486 
    487     if ( locPatLen == 0) {
    488        dispLocPattern = defaultPattern;
    489        locPatLen = 9;
    490     }
    491 
    492     /*
    493      * if there is a language, then write "language (country, variant)"
    494      * otherwise write "country, variant"
    495      */
    496 
    497     /* write the language */
    498     length=uloc_getDisplayLanguage(locale, displayLocale,
    499                                    dest, destCapacity,
    500                                    pErrorCode);
    501     hasLanguage= length>0;
    502 
    503     if(hasLanguage) {
    504         p0Len = length;
    505 
    506         /* append " (" */
    507         if(length<destCapacity) {
    508             dest[length]=0x20;
    509         }
    510         ++length;
    511         if(length<destCapacity) {
    512             dest[length]=0x28;
    513         }
    514         ++length;
    515     }
    516 
    517     if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
    518         /* keep preflighting */
    519         *pErrorCode=U_ZERO_ERROR;
    520     }
    521 
    522     /* append the script */
    523     if(length<destCapacity) {
    524         length2=uloc_getDisplayScript(locale, displayLocale,
    525                                        dest+length, destCapacity-length,
    526                                        pErrorCode);
    527     } else {
    528         length2=uloc_getDisplayScript(locale, displayLocale,
    529                                        NULL, 0,
    530                                        pErrorCode);
    531     }
    532     hasScript= length2>0;
    533     length+=length2;
    534 
    535     if(hasScript) {
    536         /* append separator */
    537         if(length+locSepLen<=destCapacity) {
    538             u_memcpy(dest+length,dispLocSeparator,locSepLen);
    539         }
    540         length+=locSepLen;
    541     }
    542 
    543     if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
    544         /* keep preflighting */
    545         *pErrorCode=U_ZERO_ERROR;
    546     }
    547 
    548     /* append the country */
    549     if(length<destCapacity) {
    550         length2=uloc_getDisplayCountry(locale, displayLocale,
    551                                        dest+length, destCapacity-length,
    552                                        pErrorCode);
    553     } else {
    554         length2=uloc_getDisplayCountry(locale, displayLocale,
    555                                        NULL, 0,
    556                                        pErrorCode);
    557     }
    558     hasCountry= length2>0;
    559     length+=length2;
    560 
    561     if(hasCountry) {
    562         /* append separator */
    563         if(length+locSepLen<=destCapacity) {
    564             u_memcpy(dest+length,dispLocSeparator,locSepLen);
    565         }
    566         length+=locSepLen;
    567     }
    568 
    569     if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
    570         /* keep preflighting */
    571         *pErrorCode=U_ZERO_ERROR;
    572     }
    573 
    574     /* append the variant */
    575     if(length<destCapacity) {
    576         length2=uloc_getDisplayVariant(locale, displayLocale,
    577                                        dest+length, destCapacity-length,
    578                                        pErrorCode);
    579     } else {
    580         length2=uloc_getDisplayVariant(locale, displayLocale,
    581                                        NULL, 0,
    582                                        pErrorCode);
    583     }
    584     hasVariant= length2>0;
    585     length+=length2;
    586 
    587     if(hasVariant) {
    588         /* append separator */
    589         if(length+locSepLen<=destCapacity) {
    590             u_memcpy(dest+length,dispLocSeparator,locSepLen);
    591         }
    592         length+=locSepLen;
    593     }
    594 
    595     keywordEnum = uloc_openKeywords(locale, pErrorCode);
    596 
    597     for(keywordCount = uenum_count(keywordEnum, pErrorCode); keywordCount > 0 ; keywordCount--){
    598           if(U_FAILURE(*pErrorCode)){
    599               break;
    600           }
    601           /* the uenum_next returns NUL terminated string */
    602           keyword = uenum_next(keywordEnum, &keywordLen, pErrorCode);
    603           if(length + length3 < destCapacity) {
    604             length3 += uloc_getDisplayKeyword(keyword, displayLocale, dest+length+length3, destCapacity-length-length3, pErrorCode);
    605           } else {
    606             length3 += uloc_getDisplayKeyword(keyword, displayLocale, NULL, 0, pErrorCode);
    607           }
    608           if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
    609               /* keep preflighting */
    610               *pErrorCode=U_ZERO_ERROR;
    611           }
    612           keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, 256, pErrorCode);
    613           if(keywordValueLen) {
    614             if(length + length3 < destCapacity) {
    615               dest[length + length3] = 0x3D;
    616             }
    617             length3++;
    618             if(length + length3 < destCapacity) {
    619               length3 += uloc_getDisplayKeywordValue(locale, keyword, displayLocale, dest+length+length3, destCapacity-length-length3, pErrorCode);
    620             } else {
    621               length3 += uloc_getDisplayKeywordValue(locale, keyword, displayLocale, NULL, 0, pErrorCode);
    622             }
    623             if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
    624                 /* keep preflighting */
    625                 *pErrorCode=U_ZERO_ERROR;
    626             }
    627           }
    628           if(keywordCount > 1) {
    629               if(length + length3 + locSepLen <= destCapacity && keywordCount) {
    630                   u_memcpy(dest+length+length3,dispLocSeparator,locSepLen);
    631                   length3+=locSepLen;
    632               }
    633           }
    634     }
    635     uenum_close(keywordEnum);
    636 
    637     hasKeywords = length3 > 0;
    638     length += length3;
    639 
    640 
    641     if ((hasScript && !hasCountry)
    642         || ((hasScript || hasCountry) && !hasVariant && !hasKeywords)
    643         || ((hasScript || hasCountry || hasVariant) && !hasKeywords)) {
    644         /* Remove separator  */
    645         length -= locSepLen;
    646     } else if (hasLanguage && !hasScript && !hasCountry && !hasVariant && !hasKeywords) {
    647         /* Remove " (" */
    648         length-=2;
    649     }
    650 
    651     if (hasLanguage && (hasScript || hasCountry || hasVariant || hasKeywords)) {
    652         /* append ")" */
    653         if(length<destCapacity) {
    654             dest[length]=0x29;
    655         }
    656         ++length;
    657 
    658         /* If the localized display pattern is something other than the default pattern of "{0} ({1})", then
    659          * then we need to do the formatting here.  It would be easier to use a messageFormat to do this, but we
    660          * can't since we don't have the APIs in the i18n library available to us at this point.
    661          */
    662         if (locPatLen != defaultPatternLen || u_strcmp(dispLocPattern,defaultPattern)) { /* Something other than the default pattern */
    663            UChar *p0 = u_strstr(dispLocPattern,pat0);
    664            UChar *p1 = u_strstr(dispLocPattern,pat1);
    665            u_terminateUChars(dest, destCapacity, length, pErrorCode);
    666 
    667            if ( p0 != NULL && p1 != NULL ) { /* The pattern is well formed */
    668               if ( dest ) {
    669                   int32_t destLen = 0;
    670                   UChar *result = (UChar *)uprv_malloc((length+1)*sizeof(UChar));
    671                   UChar *upos = (UChar *)dispLocPattern;
    672                   u_strcpy(result,dest);
    673                   dest[0] = 0;
    674                   while ( *upos ) {
    675                      if ( upos == p0 ) { /* Handle {0} substitution */
    676                          u_strncat(dest,result,p0Len);
    677                          destLen += p0Len;
    678                          dest[destLen] = 0; /* Null terminate */
    679                          upos += 3;
    680                      } else if ( upos == p1 ) { /* Handle {1} substitution */
    681                          UChar *p1Start = &result[p0Len+2];
    682                          u_strncat(dest,p1Start,length-p0Len-3);
    683                          destLen += (length-p0Len-3);
    684                          dest[destLen] = 0; /* Null terminate */
    685                          upos += 3;
    686                      } else { /* Something from the pattern not {0} or {1} */
    687                          u_strncat(dest,upos,1);
    688                          upos++;
    689                          destLen++;
    690                          dest[destLen] = 0; /* Null terminate */
    691                      }
    692                   }
    693                   length = destLen;
    694                   uprv_free(result);
    695               }
    696            }
    697         }
    698     }
    699     if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
    700         /* keep preflighting */
    701         *pErrorCode=U_ZERO_ERROR;
    702     }
    703 
    704     return u_terminateUChars(dest, destCapacity, length, pErrorCode);
    705 }
    706 
    707 U_CAPI int32_t U_EXPORT2
    708 uloc_getDisplayKeyword(const char* keyword,
    709                        const char* displayLocale,
    710                        UChar* dest,
    711                        int32_t destCapacity,
    712                        UErrorCode* status){
    713 
    714     /* argument checking */
    715     if(status==NULL || U_FAILURE(*status)) {
    716         return 0;
    717     }
    718 
    719     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
    720         *status=U_ILLEGAL_ARGUMENT_ERROR;
    721         return 0;
    722     }
    723 
    724 
    725     /* pass itemKey=NULL to look for a top-level item */
    726     return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
    727                                _kKeys, NULL,
    728                                keyword,
    729                                keyword,
    730                                dest, destCapacity,
    731                                status);
    732 
    733 }
    734 
    735 
    736 #define UCURRENCY_DISPLAY_NAME_INDEX 1
    737 
    738 U_CAPI int32_t U_EXPORT2
    739 uloc_getDisplayKeywordValue(   const char* locale,
    740                                const char* keyword,
    741                                const char* displayLocale,
    742                                UChar* dest,
    743                                int32_t destCapacity,
    744                                UErrorCode* status){
    745 
    746 
    747     char keywordValue[ULOC_FULLNAME_CAPACITY*4];
    748     int32_t capacity = ULOC_FULLNAME_CAPACITY*4;
    749     int32_t keywordValueLen =0;
    750 
    751     /* argument checking */
    752     if(status==NULL || U_FAILURE(*status)) {
    753         return 0;
    754     }
    755 
    756     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
    757         *status=U_ILLEGAL_ARGUMENT_ERROR;
    758         return 0;
    759     }
    760 
    761     /* get the keyword value */
    762     keywordValue[0]=0;
    763     keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status);
    764 
    765     /*
    766      * if the keyword is equal to currency .. then to get the display name
    767      * we need to do the fallback ourselves
    768      */
    769     if(uprv_stricmp(keyword, _kCurrency)==0){
    770 
    771         int32_t dispNameLen = 0;
    772         const UChar *dispName = NULL;
    773 
    774         UResourceBundle *bundle     = ures_open(U_ICUDATA_CURR, displayLocale, status);
    775         UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status);
    776         UResourceBundle *currency   = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status);
    777 
    778         dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
    779 
    780         /*close the bundles */
    781         ures_close(currency);
    782         ures_close(currencies);
    783         ures_close(bundle);
    784 
    785         if(U_FAILURE(*status)){
    786             if(*status == U_MISSING_RESOURCE_ERROR){
    787                 /* we just want to write the value over if nothing is available */
    788                 *status = U_USING_DEFAULT_WARNING;
    789             }else{
    790                 return 0;
    791             }
    792         }
    793 
    794         /* now copy the dispName over if not NULL */
    795         if(dispName != NULL){
    796             if(dispNameLen <= destCapacity){
    797                 uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR);
    798                 return u_terminateUChars(dest, destCapacity, dispNameLen, status);
    799             }else{
    800                 *status = U_BUFFER_OVERFLOW_ERROR;
    801                 return dispNameLen;
    802             }
    803         }else{
    804             /* we have not found the display name for the value .. just copy over */
    805             if(keywordValueLen <= destCapacity){
    806                 u_charsToUChars(keywordValue, dest, keywordValueLen);
    807                 return u_terminateUChars(dest, destCapacity, keywordValueLen, status);
    808             }else{
    809                  *status = U_BUFFER_OVERFLOW_ERROR;
    810                 return keywordValueLen;
    811             }
    812         }
    813 
    814 
    815     }else{
    816 
    817         return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
    818                                    _kTypes, keyword,
    819                                    keywordValue,
    820                                    keywordValue,
    821                                    dest, destCapacity,
    822                                    status);
    823     }
    824 }
    825