LCOV - code coverage report
Current view: top level - intl/icu/source/common - locdispnames.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 356 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 : Locale::getDisplayLanguage(UnicodeString& dispLang) const
      42             : {
      43           0 :     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           0 : Locale::getDisplayLanguage(const Locale &displayLocale,
      54             :                            UnicodeString &result) const {
      55             :     UChar *buffer;
      56           0 :     UErrorCode errorCode=U_ZERO_ERROR;
      57             :     int32_t length;
      58             : 
      59           0 :     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
      60           0 :     if(buffer==0) {
      61           0 :         result.truncate(0);
      62           0 :         return result;
      63             :     }
      64             : 
      65           0 :     length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
      66             :                                    buffer, result.getCapacity(),
      67           0 :                                    &errorCode);
      68           0 :     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
      69             : 
      70           0 :     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
      71           0 :         buffer=result.getBuffer(length);
      72           0 :         if(buffer==0) {
      73           0 :             result.truncate(0);
      74           0 :             return result;
      75             :         }
      76           0 :         errorCode=U_ZERO_ERROR;
      77           0 :         length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
      78             :                                        buffer, result.getCapacity(),
      79           0 :                                        &errorCode);
      80           0 :         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
      81             :     }
      82             : 
      83           0 :     return result;
      84             : }
      85             : 
      86             : UnicodeString&
      87           0 : Locale::getDisplayScript(UnicodeString& dispScript) const
      88             : {
      89           0 :     return this->getDisplayScript(getDefault(), dispScript);
      90             : }
      91             : 
      92             : UnicodeString&
      93           0 : Locale::getDisplayScript(const Locale &displayLocale,
      94             :                           UnicodeString &result) const {
      95             :     UChar *buffer;
      96           0 :     UErrorCode errorCode=U_ZERO_ERROR;
      97             :     int32_t length;
      98             : 
      99           0 :     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
     100           0 :     if(buffer==0) {
     101           0 :         result.truncate(0);
     102           0 :         return result;
     103             :     }
     104             : 
     105           0 :     length=uloc_getDisplayScript(fullName, displayLocale.fullName,
     106             :                                   buffer, result.getCapacity(),
     107           0 :                                   &errorCode);
     108           0 :     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
     109             : 
     110           0 :     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
     111           0 :         buffer=result.getBuffer(length);
     112           0 :         if(buffer==0) {
     113           0 :             result.truncate(0);
     114           0 :             return result;
     115             :         }
     116           0 :         errorCode=U_ZERO_ERROR;
     117           0 :         length=uloc_getDisplayScript(fullName, displayLocale.fullName,
     118             :                                       buffer, result.getCapacity(),
     119           0 :                                       &errorCode);
     120           0 :         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
     121             :     }
     122             : 
     123           0 :     return result;
     124             : }
     125             : 
     126             : UnicodeString&
     127           0 : Locale::getDisplayCountry(UnicodeString& dispCntry) const
     128             : {
     129           0 :     return this->getDisplayCountry(getDefault(), dispCntry);
     130             : }
     131             : 
     132             : UnicodeString&
     133           0 : Locale::getDisplayCountry(const Locale &displayLocale,
     134             :                           UnicodeString &result) const {
     135             :     UChar *buffer;
     136           0 :     UErrorCode errorCode=U_ZERO_ERROR;
     137             :     int32_t length;
     138             : 
     139           0 :     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
     140           0 :     if(buffer==0) {
     141           0 :         result.truncate(0);
     142           0 :         return result;
     143             :     }
     144             : 
     145           0 :     length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
     146             :                                   buffer, result.getCapacity(),
     147           0 :                                   &errorCode);
     148           0 :     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
     149             : 
     150           0 :     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
     151           0 :         buffer=result.getBuffer(length);
     152           0 :         if(buffer==0) {
     153           0 :             result.truncate(0);
     154           0 :             return result;
     155             :         }
     156           0 :         errorCode=U_ZERO_ERROR;
     157           0 :         length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
     158             :                                       buffer, result.getCapacity(),
     159           0 :                                       &errorCode);
     160           0 :         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
     161             :     }
     162             : 
     163           0 :     return result;
     164             : }
     165             : 
     166             : UnicodeString&
     167           0 : Locale::getDisplayVariant(UnicodeString& dispVar) const
     168             : {
     169           0 :     return this->getDisplayVariant(getDefault(), dispVar);
     170             : }
     171             : 
     172             : UnicodeString&
     173           0 : Locale::getDisplayVariant(const Locale &displayLocale,
     174             :                           UnicodeString &result) const {
     175             :     UChar *buffer;
     176           0 :     UErrorCode errorCode=U_ZERO_ERROR;
     177             :     int32_t length;
     178             : 
     179           0 :     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
     180           0 :     if(buffer==0) {
     181           0 :         result.truncate(0);
     182           0 :         return result;
     183             :     }
     184             : 
     185           0 :     length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
     186             :                                   buffer, result.getCapacity(),
     187           0 :                                   &errorCode);
     188           0 :     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
     189             : 
     190           0 :     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
     191           0 :         buffer=result.getBuffer(length);
     192           0 :         if(buffer==0) {
     193           0 :             result.truncate(0);
     194           0 :             return result;
     195             :         }
     196           0 :         errorCode=U_ZERO_ERROR;
     197           0 :         length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
     198             :                                       buffer, result.getCapacity(),
     199           0 :                                       &errorCode);
     200           0 :         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
     201             :     }
     202             : 
     203           0 :     return result;
     204             : }
     205             : 
     206             : UnicodeString&
     207           0 : Locale::getDisplayName( UnicodeString& name ) const
     208             : {
     209           0 :     return this->getDisplayName(getDefault(), name);
     210             : }
     211             : 
     212             : UnicodeString&
     213           0 : Locale::getDisplayName(const Locale &displayLocale,
     214             :                        UnicodeString &result) const {
     215             :     UChar *buffer;
     216           0 :     UErrorCode errorCode=U_ZERO_ERROR;
     217             :     int32_t length;
     218             : 
     219           0 :     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
     220           0 :     if(buffer==0) {
     221           0 :         result.truncate(0);
     222           0 :         return result;
     223             :     }
     224             : 
     225           0 :     length=uloc_getDisplayName(fullName, displayLocale.fullName,
     226             :                                buffer, result.getCapacity(),
     227           0 :                                &errorCode);
     228           0 :     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
     229             : 
     230           0 :     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
     231           0 :         buffer=result.getBuffer(length);
     232           0 :         if(buffer==0) {
     233           0 :             result.truncate(0);
     234           0 :             return result;
     235             :         }
     236           0 :         errorCode=U_ZERO_ERROR;
     237           0 :         length=uloc_getDisplayName(fullName, displayLocale.fullName,
     238             :                                    buffer, result.getCapacity(),
     239           0 :                                    &errorCode);
     240           0 :         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
     241             :     }
     242             : 
     243           0 :     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           0 : _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           0 :     const UChar *s = NULL;
     305           0 :     int32_t length = 0;
     306             : 
     307           0 :     if(itemKey==NULL) {
     308             :         /* top-level item: normal resource bundle access */
     309             :         UResourceBundle *rb;
     310             : 
     311           0 :         rb=ures_open(path, locale, pErrorCode);
     312             : 
     313           0 :         if(U_SUCCESS(*pErrorCode)) {
     314           0 :             s=ures_getStringByKey(rb, tableKey, &length, pErrorCode);
     315             :             /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
     316           0 :             ures_close(rb);
     317             :         }
     318             :     } else {
     319             :         /* Language code should not be a number. If it is, set the error code. */
     320           0 :         if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) {
     321           0 :             *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           0 :                                                pErrorCode);
     330             :         }
     331             :     }
     332             : 
     333           0 :     if(U_SUCCESS(*pErrorCode)) {
     334           0 :         int32_t copyLength=uprv_min(length, destCapacity);
     335           0 :         if(copyLength>0 && s != NULL) {
     336           0 :             u_memcpy(dest, s, copyLength);
     337             :         }
     338             :     } else {
     339             :         /* no string from a resource bundle: convert the substitute */
     340           0 :         length=(int32_t)uprv_strlen(substitute);
     341           0 :         u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
     342           0 :         *pErrorCode=U_USING_DEFAULT_WARNING;
     343             :     }
     344             : 
     345           0 :     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           0 : _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           0 :     const char* root = NULL;
     361             : 
     362             :     /* argument checking */
     363           0 :     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
     364           0 :         return 0;
     365             :     }
     366             : 
     367           0 :     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
     368           0 :         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
     369           0 :         return 0;
     370             :     }
     371             : 
     372           0 :     localStatus = U_ZERO_ERROR;
     373           0 :     length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
     374           0 :     if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
     375           0 :         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
     376           0 :         return 0;
     377             :     }
     378           0 :     if(length==0) {
     379           0 :         return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
     380             :     }
     381             : 
     382           0 :     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           0 :                                pErrorCode);
     389             : }
     390             : 
     391             : U_CAPI int32_t U_EXPORT2
     392           0 : 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           0 :                 uloc_getLanguage, _kLanguages, pErrorCode);
     398             : }
     399             : 
     400             : U_CAPI int32_t U_EXPORT2
     401           0 : uloc_getDisplayScript(const char* locale,
     402             :                       const char* displayLocale,
     403             :                       UChar *dest, int32_t destCapacity,
     404             :                       UErrorCode *pErrorCode)
     405             : {
     406           0 :         UErrorCode err = U_ZERO_ERROR;
     407             :         int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
     408           0 :                 uloc_getScript, _kScriptsStandAlone, &err);
     409             :         
     410           0 :         if ( err == U_USING_DEFAULT_WARNING ) {
     411             :         return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
     412           0 :                     uloc_getScript, _kScripts, pErrorCode);
     413             :         } else {
     414           0 :                 *pErrorCode = err;
     415           0 :                 return res;
     416             :         }
     417             : }
     418             : 
     419             : U_INTERNAL int32_t U_EXPORT2
     420           0 : 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           0 :                     uloc_getScript, _kScripts, pErrorCode);
     427             : }
     428             : 
     429             : U_CAPI int32_t U_EXPORT2
     430           0 : 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           0 :                 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           0 : 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           0 :                 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           0 : 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           0 :     int32_t sepLen = 0;
     485             :     const UChar *pattern;
     486           0 :     int32_t patLen = 0;
     487             :     int32_t sub0Pos, sub1Pos;
     488             :     
     489           0 :     UChar formatOpenParen         = 0x0028; // (
     490           0 :     UChar formatReplaceOpenParen  = 0x005B; // [
     491           0 :     UChar formatCloseParen        = 0x0029; // )
     492           0 :     UChar formatReplaceCloseParen = 0x005D; // ]
     493             : 
     494           0 :     UBool haveLang = TRUE; /* assume true, set false if we find we don't have
     495             :                               a lang component in the locale */
     496           0 :     UBool haveRest = TRUE; /* assume true, set false if we find we don't have
     497             :                               any other component in the locale */
     498           0 :     UBool retry = FALSE; /* set true if we need to retry, see below */
     499             : 
     500           0 :     int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */
     501             : 
     502           0 :     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
     503           0 :         return 0;
     504             :     }
     505             : 
     506           0 :     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
     507           0 :         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
     508           0 :         return 0;
     509             :     }
     510             : 
     511             :     {
     512           0 :         UErrorCode status = U_ZERO_ERROR;
     513           0 :         UResourceBundle* locbundle=ures_open(U_ICUDATA_LANG, displayLocale, &status);
     514             :         UResourceBundle* dspbundle=ures_getByKeyWithFallback(locbundle, _kLocaleDisplayPattern,
     515           0 :                                                              NULL, &status);
     516             : 
     517           0 :         separator=ures_getStringByKeyWithFallback(dspbundle, _kSeparator, &sepLen, &status);
     518           0 :         pattern=ures_getStringByKeyWithFallback(dspbundle, _kPattern, &patLen, &status);
     519             : 
     520           0 :         ures_close(dspbundle);
     521           0 :         ures_close(locbundle);
     522             :     }
     523             : 
     524             :     /* If we couldn't find any data, then use the defaults */
     525           0 :     if(sepLen == 0) {
     526           0 :        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           0 :         UChar *p0=u_strstr(separator, sub0);
     539           0 :         UChar *p1=u_strstr(separator, sub1);
     540           0 :         if (p0==NULL || p1==NULL || p1<p0) {
     541           0 :             *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
     542           0 :             return 0;
     543             :         }
     544           0 :         separator = (const UChar *)p0 + subLen;
     545           0 :         sepLen = p1 - separator;
     546             :     }
     547             : 
     548           0 :     if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) {
     549           0 :         pattern=defaultPattern;
     550           0 :         patLen=defaultPatLen;
     551           0 :         sub0Pos=defaultSub0Pos;
     552           0 :         sub1Pos=defaultSub1Pos;
     553             :         // use default formatOpenParen etc. set above
     554             :     } else { /* non-default pattern */
     555           0 :         UChar *p0=u_strstr(pattern, sub0);
     556           0 :         UChar *p1=u_strstr(pattern, sub1);
     557           0 :         if (p0==NULL || p1==NULL) {
     558           0 :             *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
     559           0 :             return 0;
     560             :         }
     561           0 :         sub0Pos=p0-pattern;
     562           0 :         sub1Pos=p1-pattern;
     563           0 :         if (sub1Pos < sub0Pos) { /* a very odd pattern */
     564           0 :             int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t;
     565           0 :             langi=1;
     566             :         }
     567           0 :         if (u_strchr(pattern, 0xFF08) != NULL) {
     568           0 :             formatOpenParen         = 0xFF08; // fullwidth (
     569           0 :             formatReplaceOpenParen  = 0xFF3B; // fullwidth [
     570           0 :             formatCloseParen        = 0xFF09; // fullwidth )
     571           0 :             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           0 :     do {
     583           0 :         UChar* p=dest;
     584           0 :         int32_t patPos=0; /* position in the pattern, used for non-substitution portions */
     585           0 :         int32_t langLen=0; /* length of language substitution */
     586           0 :         int32_t langPos=0; /* position in output of language substitution */
     587           0 :         int32_t restLen=0; /* length of 'everything else' substitution */
     588           0 :         int32_t restPos=0; /* position in output of 'everything else' substitution */
     589           0 :         UEnumeration* kenum = NULL; /* keyword enumeration */
     590             : 
     591             :         /* prefix of pattern, extremely likely to be empty */
     592           0 :         if(sub0Pos) {
     593           0 :             if(destCapacity >= sub0Pos) {
     594           0 :                 while (patPos < sub0Pos) {
     595           0 :                     *p++ = pattern[patPos++];
     596             :                 }
     597             :             } else {
     598           0 :                 patPos=sub0Pos;
     599             :             }
     600           0 :             length=sub0Pos;
     601             :         } else {
     602           0 :             length=0;
     603             :         }
     604             : 
     605           0 :         for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/
     606           0 :             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           0 :             int32_t cap=destCapacity-length;
     611           0 :             if (cap <= 0) {
     612           0 :                 cap=0;
     613             :             } else {
     614           0 :                 p=dest+length;
     615             :             }
     616             : 
     617           0 :             if (subi == langi) { /* {0}*/
     618           0 :                 if(haveLang) {
     619           0 :                     langPos=length;
     620           0 :                     langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode);
     621           0 :                     length+=langLen;
     622           0 :                     haveLang=langLen>0;
     623             :                 }
     624           0 :                 subdone=TRUE;
     625             :             } else { /* {1} */
     626           0 :                 if(!haveRest) {
     627           0 :                     subdone=TRUE;
     628             :                 } else {
     629             :                     int32_t len; /* length of component (plus other stuff) we just fetched */
     630           0 :                     switch(resti++) {
     631             :                         case 0:
     632           0 :                             restPos=length;
     633           0 :                             len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode);
     634           0 :                             break;
     635             :                         case 1:
     636           0 :                             len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode);
     637           0 :                             break;
     638             :                         case 2:
     639           0 :                             len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode);
     640           0 :                             break;
     641             :                         case 3:
     642           0 :                             kenum = uloc_openKeywords(locale, pErrorCode);
     643             :                             U_FALLTHROUGH;
     644             :                         default: {
     645           0 :                             const char* kw=uenum_next(kenum, &len, pErrorCode);
     646           0 :                             if (kw == NULL) {
     647           0 :                                 uenum_close(kenum);
     648           0 :                                 len=0; /* mark that we didn't add a component */
     649           0 :                                 subdone=TRUE;
     650             :                             } else {
     651             :                                 /* incorporating this behavior into the loop made it even more complex,
     652             :                                    so just special case it here */
     653           0 :                                 len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode);
     654           0 :                                 if(len) {
     655           0 :                                     if(len < cap) {
     656           0 :                                         p[len]=0x3d; /* '=', assume we'll need it */
     657             :                                     }
     658           0 :                                     len+=1;
     659             : 
     660             :                                     /* adjust for call to get keyword */
     661           0 :                                     cap-=len;
     662           0 :                                     if(cap <= 0) {
     663           0 :                                         cap=0;
     664             :                                     } else {
     665           0 :                                         p+=len;
     666             :                                     }
     667             :                                 }
     668             :                                 /* reset for call below */
     669           0 :                                 if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
     670           0 :                                     *pErrorCode=U_ZERO_ERROR;
     671             :                                 }
     672             :                                 int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale,
     673           0 :                                                                            p, cap, pErrorCode);
     674           0 :                                 if(len) {
     675           0 :                                     if(vlen==0) {
     676           0 :                                         --len; /* remove unneeded '=' */
     677             :                                     }
     678             :                                     /* restore cap and p to what they were at start */
     679           0 :                                     cap=destCapacity-length;
     680           0 :                                     if(cap <= 0) {
     681           0 :                                         cap=0;
     682             :                                     } else {
     683           0 :                                         p=dest+length;
     684             :                                     }
     685             :                                 }
     686           0 :                                 len+=vlen; /* total we added for key + '=' + value */
     687             :                             }
     688           0 :                         } break;
     689             :                     } /* end switch */
     690             : 
     691           0 :                     if (len>0) {
     692             :                         /* we addeed a component, so add separator and write it if there's room. */
     693           0 :                         if(len+sepLen<=cap) {
     694           0 :                             const UChar * plimit = p + len;
     695           0 :                             for (; p < plimit; p++) {
     696           0 :                                 if (*p == formatOpenParen) {
     697           0 :                                     *p = formatReplaceOpenParen;
     698           0 :                                 } else if (*p == formatCloseParen) {
     699           0 :                                     *p = formatReplaceCloseParen;
     700             :                                 }
     701             :                             }
     702           0 :                             for(int32_t i=0;i<sepLen;++i) {
     703           0 :                                 *p++=separator[i];
     704             :                             }
     705             :                         }
     706           0 :                         length+=len+sepLen;
     707           0 :                     } else if(subdone) {
     708             :                         /* remove separator if we added it */
     709           0 :                         if (length!=restPos) {
     710           0 :                             length-=sepLen;
     711             :                         }
     712           0 :                         restLen=length-restPos;
     713           0 :                         haveRest=restLen>0;
     714             :                     }
     715             :                 }
     716             :             }
     717             : 
     718           0 :             if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
     719           0 :                 *pErrorCode=U_ZERO_ERROR;
     720             :             }
     721             : 
     722           0 :             if(subdone) {
     723           0 :                 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           0 :                     patPos+=subLen;
     728           0 :                     padLen=(subi==0 ? sub1Pos : patLen)-patPos;
     729           0 :                     if(length+padLen < destCapacity) {
     730           0 :                         p=dest+length;
     731           0 :                         for(int32_t i=0;i<padLen;++i) {
     732           0 :                             *p++=pattern[patPos++];
     733             :                         }
     734             :                     } else {
     735           0 :                         patPos+=padLen;
     736             :                     }
     737           0 :                     length+=padLen;
     738           0 :                 } else if(subi==0) {
     739             :                     /* don't have first component, reset for second component */
     740           0 :                     sub0Pos=0;
     741           0 :                     length=0;
     742           0 :                 } else if(length>0) {
     743             :                     /* true length is the length of just the component we got. */
     744           0 :                     length=haveLang?langLen:restLen;
     745           0 :                     if(dest && sub0Pos!=0) {
     746           0 :                         if (sub0Pos+length<=destCapacity) {
     747             :                             /* first component not at start of result,
     748             :                                but we have full component in buffer. */
     749           0 :                             u_memmove(dest, dest+(haveLang?langPos:restPos), length);
     750             :                         } else {
     751             :                             /* would have fit, but didn't because of pattern prefix. */
     752           0 :                             sub0Pos=0; /* stops initial padding (and a second retry,
     753             :                                           so we won't end up here again) */
     754           0 :                             retry=TRUE;
     755             :                         }
     756             :                     }
     757             :                 }
     758             : 
     759           0 :                 ++subi; /* move on to next substitution */
     760             :             }
     761             :         }
     762           0 :     } while(retry);
     763             : 
     764           0 :     return u_terminateUChars(dest, destCapacity, length, pErrorCode);
     765             : }
     766             : 
     767             : U_CAPI int32_t U_EXPORT2
     768           0 : uloc_getDisplayKeyword(const char* keyword,
     769             :                        const char* displayLocale,
     770             :                        UChar* dest,
     771             :                        int32_t destCapacity,
     772             :                        UErrorCode* status){
     773             : 
     774             :     /* argument checking */
     775           0 :     if(status==NULL || U_FAILURE(*status)) {
     776           0 :         return 0;
     777             :     }
     778             : 
     779           0 :     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
     780           0 :         *status=U_ILLEGAL_ARGUMENT_ERROR;
     781           0 :         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           0 :                                status);
     792             : 
     793             : }
     794             : 
     795             : 
     796             : #define UCURRENCY_DISPLAY_NAME_INDEX 1
     797             : 
     798             : U_CAPI int32_t U_EXPORT2
     799           0 : 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           0 :     int32_t capacity = ULOC_FULLNAME_CAPACITY*4;
     809           0 :     int32_t keywordValueLen =0;
     810             : 
     811             :     /* argument checking */
     812           0 :     if(status==NULL || U_FAILURE(*status)) {
     813           0 :         return 0;
     814             :     }
     815             : 
     816           0 :     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
     817           0 :         *status=U_ILLEGAL_ARGUMENT_ERROR;
     818           0 :         return 0;
     819             :     }
     820             : 
     821             :     /* get the keyword value */
     822           0 :     keywordValue[0]=0;
     823           0 :     keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status);
     824             : 
     825             :     /* 
     826             :      * if the keyword is equal to currency .. then to get the display name 
     827             :      * we need to do the fallback ourselves
     828             :      */
     829           0 :     if(uprv_stricmp(keyword, _kCurrency)==0){
     830             : 
     831           0 :         int32_t dispNameLen = 0;
     832           0 :         const UChar *dispName = NULL;
     833             :         
     834           0 :         UResourceBundle *bundle     = ures_open(U_ICUDATA_CURR, displayLocale, status);
     835           0 :         UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status);
     836           0 :         UResourceBundle *currency   = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status);
     837             :         
     838           0 :         dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
     839             :         
     840             :         /*close the bundles */
     841           0 :         ures_close(currency);
     842           0 :         ures_close(currencies);
     843           0 :         ures_close(bundle);
     844             :         
     845           0 :         if(U_FAILURE(*status)){
     846           0 :             if(*status == U_MISSING_RESOURCE_ERROR){
     847             :                 /* we just want to write the value over if nothing is available */
     848           0 :                 *status = U_USING_DEFAULT_WARNING;
     849             :             }else{
     850           0 :                 return 0;
     851             :             }
     852             :         }
     853             : 
     854             :         /* now copy the dispName over if not NULL */
     855           0 :         if(dispName != NULL){
     856           0 :             if(dispNameLen <= destCapacity){
     857           0 :                 u_memcpy(dest, dispName, dispNameLen);
     858           0 :                 return u_terminateUChars(dest, destCapacity, dispNameLen, status);
     859             :             }else{
     860           0 :                 *status = U_BUFFER_OVERFLOW_ERROR;
     861           0 :                 return dispNameLen;
     862             :             }
     863             :         }else{
     864             :             /* we have not found the display name for the value .. just copy over */
     865           0 :             if(keywordValueLen <= destCapacity){
     866           0 :                 u_charsToUChars(keywordValue, dest, keywordValueLen);
     867           0 :                 return u_terminateUChars(dest, destCapacity, keywordValueLen, status);
     868             :             }else{
     869           0 :                  *status = U_BUFFER_OVERFLOW_ERROR;
     870           0 :                 return keywordValueLen;
     871             :             }
     872             :         }
     873             : 
     874             :         
     875             :     }else{
     876             : 
     877             :         return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
     878             :                                    _kTypes, keyword, 
     879             :                                    keywordValue,
     880             :                                    keywordValue,
     881             :                                    dest, destCapacity,
     882           0 :                                    status);
     883             :     }
     884             : }

Generated by: LCOV version 1.13