123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900 |
- // © 2016 and later: Unicode, Inc. and others.
- // License & terms of use: http://www.unicode.org/copyright.html
- /*
- *******************************************************************************
- *
- * Copyright (C) 1997-2016, International Business Machines
- * Corporation and others. All Rights Reserved.
- *
- *******************************************************************************
- * file name: locdispnames.cpp
- * encoding: UTF-8
- * tab size: 8 (not used)
- * indentation:4
- *
- * created on: 2010feb25
- * created by: Markus W. Scherer
- *
- * Code for locale display names, separated out from other .cpp files
- * that then do not depend on resource bundle code and display name data.
- */
- #include "unicode/utypes.h"
- #include "unicode/brkiter.h"
- #include "unicode/locid.h"
- #include "unicode/uenum.h"
- #include "unicode/uloc.h"
- #include "unicode/ures.h"
- #include "unicode/ustring.h"
- #include "charstr.h"
- #include "cmemory.h"
- #include "cstring.h"
- #include "putilimp.h"
- #include "ulocimp.h"
- #include "uresimp.h"
- #include "ureslocs.h"
- #include "ustr_imp.h"
- // C++ API ----------------------------------------------------------------- ***
- U_NAMESPACE_BEGIN
- UnicodeString&
- Locale::getDisplayLanguage(UnicodeString& dispLang) const
- {
- return this->getDisplayLanguage(getDefault(), dispLang);
- }
- /*We cannot make any assumptions on the size of the output display strings
- * Yet, since we are calling through to a C API, we need to set limits on
- * buffer size. For all the following getDisplay functions we first attempt
- * to fill up a stack allocated buffer. If it is to small we heap allocated
- * the exact buffer we need copy it to the UnicodeString and delete it*/
- UnicodeString&
- Locale::getDisplayLanguage(const Locale &displayLocale,
- UnicodeString &result) const {
- char16_t *buffer;
- UErrorCode errorCode=U_ZERO_ERROR;
- int32_t length;
- buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
- if (buffer == nullptr) {
- result.truncate(0);
- return result;
- }
- length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
- buffer, result.getCapacity(),
- &errorCode);
- result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
- if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
- buffer=result.getBuffer(length);
- if (buffer == nullptr) {
- result.truncate(0);
- return result;
- }
- errorCode=U_ZERO_ERROR;
- length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
- buffer, result.getCapacity(),
- &errorCode);
- result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
- }
- return result;
- }
- UnicodeString&
- Locale::getDisplayScript(UnicodeString& dispScript) const
- {
- return this->getDisplayScript(getDefault(), dispScript);
- }
- UnicodeString&
- Locale::getDisplayScript(const Locale &displayLocale,
- UnicodeString &result) const {
- char16_t *buffer;
- UErrorCode errorCode=U_ZERO_ERROR;
- int32_t length;
- buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
- if (buffer == nullptr) {
- result.truncate(0);
- return result;
- }
- length=uloc_getDisplayScript(fullName, displayLocale.fullName,
- buffer, result.getCapacity(),
- &errorCode);
- result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
- if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
- buffer=result.getBuffer(length);
- if (buffer == nullptr) {
- result.truncate(0);
- return result;
- }
- errorCode=U_ZERO_ERROR;
- length=uloc_getDisplayScript(fullName, displayLocale.fullName,
- buffer, result.getCapacity(),
- &errorCode);
- result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
- }
- return result;
- }
- UnicodeString&
- Locale::getDisplayCountry(UnicodeString& dispCntry) const
- {
- return this->getDisplayCountry(getDefault(), dispCntry);
- }
- UnicodeString&
- Locale::getDisplayCountry(const Locale &displayLocale,
- UnicodeString &result) const {
- char16_t *buffer;
- UErrorCode errorCode=U_ZERO_ERROR;
- int32_t length;
- buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
- if (buffer == nullptr) {
- result.truncate(0);
- return result;
- }
- length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
- buffer, result.getCapacity(),
- &errorCode);
- result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
- if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
- buffer=result.getBuffer(length);
- if (buffer == nullptr) {
- result.truncate(0);
- return result;
- }
- errorCode=U_ZERO_ERROR;
- length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
- buffer, result.getCapacity(),
- &errorCode);
- result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
- }
- return result;
- }
- UnicodeString&
- Locale::getDisplayVariant(UnicodeString& dispVar) const
- {
- return this->getDisplayVariant(getDefault(), dispVar);
- }
- UnicodeString&
- Locale::getDisplayVariant(const Locale &displayLocale,
- UnicodeString &result) const {
- char16_t *buffer;
- UErrorCode errorCode=U_ZERO_ERROR;
- int32_t length;
- buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
- if (buffer == nullptr) {
- result.truncate(0);
- return result;
- }
- length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
- buffer, result.getCapacity(),
- &errorCode);
- result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
- if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
- buffer=result.getBuffer(length);
- if (buffer == nullptr) {
- result.truncate(0);
- return result;
- }
- errorCode=U_ZERO_ERROR;
- length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
- buffer, result.getCapacity(),
- &errorCode);
- result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
- }
- return result;
- }
- UnicodeString&
- Locale::getDisplayName( UnicodeString& name ) const
- {
- return this->getDisplayName(getDefault(), name);
- }
- UnicodeString&
- Locale::getDisplayName(const Locale &displayLocale,
- UnicodeString &result) const {
- char16_t *buffer;
- UErrorCode errorCode=U_ZERO_ERROR;
- int32_t length;
- buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
- if (buffer == nullptr) {
- result.truncate(0);
- return result;
- }
- length=uloc_getDisplayName(fullName, displayLocale.fullName,
- buffer, result.getCapacity(),
- &errorCode);
- result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
- if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
- buffer=result.getBuffer(length);
- if (buffer == nullptr) {
- result.truncate(0);
- return result;
- }
- errorCode=U_ZERO_ERROR;
- length=uloc_getDisplayName(fullName, displayLocale.fullName,
- buffer, result.getCapacity(),
- &errorCode);
- result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
- }
- return result;
- }
- #if !UCONFIG_NO_BREAK_ITERATION
- // -------------------------------------
- // Gets the objectLocale display name in the default locale language.
- UnicodeString& U_EXPORT2
- BreakIterator::getDisplayName(const Locale& objectLocale,
- UnicodeString& name)
- {
- return objectLocale.getDisplayName(name);
- }
- // -------------------------------------
- // Gets the objectLocale display name in the displayLocale language.
- UnicodeString& U_EXPORT2
- BreakIterator::getDisplayName(const Locale& objectLocale,
- const Locale& displayLocale,
- UnicodeString& name)
- {
- return objectLocale.getDisplayName(displayLocale, name);
- }
- #endif
- U_NAMESPACE_END
- // C API ------------------------------------------------------------------- ***
- U_NAMESPACE_USE
- namespace {
- /* ### Constants **************************************************/
- /* These strings describe the resources we attempt to load from
- the locale ResourceBundle data file.*/
- constexpr char _kLanguages[] = "Languages";
- constexpr char _kScripts[] = "Scripts";
- constexpr char _kScriptsStandAlone[] = "Scripts%stand-alone";
- constexpr char _kCountries[] = "Countries";
- constexpr char _kVariants[] = "Variants";
- constexpr char _kKeys[] = "Keys";
- constexpr char _kTypes[] = "Types";
- //constexpr char _kRootName[] = "root";
- constexpr char _kCurrency[] = "currency";
- constexpr char _kCurrencies[] = "Currencies";
- constexpr char _kLocaleDisplayPattern[] = "localeDisplayPattern";
- constexpr char _kPattern[] = "pattern";
- constexpr char _kSeparator[] = "separator";
- /* ### Display name **************************************************/
- int32_t
- _getStringOrCopyKey(const char *path, const char *locale,
- const char *tableKey,
- const char* subTableKey,
- const char *itemKey,
- const char *substitute,
- char16_t *dest, int32_t destCapacity,
- UErrorCode &errorCode) {
- if (U_FAILURE(errorCode)) { return 0; }
- const char16_t *s = nullptr;
- int32_t length = 0;
- if(itemKey==nullptr) {
- /* top-level item: normal resource bundle access */
- icu::LocalUResourceBundlePointer rb(ures_open(path, locale, &errorCode));
- if(U_SUCCESS(errorCode)) {
- s=ures_getStringByKey(rb.getAlias(), tableKey, &length, &errorCode);
- /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
- }
- } else {
- bool isLanguageCode = (uprv_strncmp(tableKey, _kLanguages, 9) == 0);
- /* Language code should not be a number. If it is, set the error code. */
- if (isLanguageCode && uprv_strtol(itemKey, nullptr, 10)) {
- errorCode = U_MISSING_RESOURCE_ERROR;
- } else {
- /* second-level item, use special fallback */
- s=uloc_getTableStringWithFallback(path, locale,
- tableKey,
- subTableKey,
- itemKey,
- &length,
- &errorCode);
- if (U_FAILURE(errorCode) && isLanguageCode && itemKey != nullptr) {
- // convert itemKey locale code to canonical form and try again, ICU-20870
- errorCode = U_ZERO_ERROR;
- Locale canonKey = Locale::createCanonical(itemKey);
- s=uloc_getTableStringWithFallback(path, locale,
- tableKey,
- subTableKey,
- canonKey.getName(),
- &length,
- &errorCode);
- }
- }
- }
- if(U_SUCCESS(errorCode)) {
- int32_t copyLength=uprv_min(length, destCapacity);
- if(copyLength>0 && s != nullptr) {
- u_memcpy(dest, s, copyLength);
- }
- } else {
- /* no string from a resource bundle: convert the substitute */
- length = static_cast<int32_t>(uprv_strlen(substitute));
- u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
- errorCode = U_USING_DEFAULT_WARNING;
- }
- return u_terminateUChars(dest, destCapacity, length, &errorCode);
- }
- using UDisplayNameGetter = icu::CharString(const char*, UErrorCode&);
- int32_t
- _getDisplayNameForComponent(const char *locale,
- const char *displayLocale,
- char16_t *dest, int32_t destCapacity,
- UDisplayNameGetter *getter,
- const char *tag,
- UErrorCode &errorCode) {
- if (U_FAILURE(errorCode)) { return 0; }
- UErrorCode localStatus;
- const char* root = nullptr;
- if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
- errorCode = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- localStatus = U_ZERO_ERROR;
- icu::CharString localeBuffer = (*getter)(locale, localStatus);
- if (U_FAILURE(localStatus)) {
- errorCode = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- if (localeBuffer.isEmpty()) {
- // For the display name, we treat this as unknown language (ICU-20273).
- if (getter == ulocimp_getLanguage) {
- localeBuffer.append("und", errorCode);
- } else {
- return u_terminateUChars(dest, destCapacity, 0, &errorCode);
- }
- }
- root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
- return _getStringOrCopyKey(root, displayLocale,
- tag, nullptr, localeBuffer.data(),
- localeBuffer.data(),
- dest, destCapacity,
- errorCode);
- }
- } // namespace
- U_CAPI int32_t U_EXPORT2
- uloc_getDisplayLanguage(const char *locale,
- const char *displayLocale,
- char16_t *dest, int32_t destCapacity,
- UErrorCode *pErrorCode) {
- return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
- ulocimp_getLanguage, _kLanguages, *pErrorCode);
- }
- U_CAPI int32_t U_EXPORT2
- uloc_getDisplayScript(const char* locale,
- const char* displayLocale,
- char16_t *dest, int32_t destCapacity,
- UErrorCode *pErrorCode)
- {
- if (U_FAILURE(*pErrorCode)) { return 0; }
- UErrorCode err = U_ZERO_ERROR;
- int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
- ulocimp_getScript, _kScriptsStandAlone, err);
- if (destCapacity == 0 && err == U_BUFFER_OVERFLOW_ERROR) {
- // For preflight, return the max of the value and the fallback.
- int32_t fallback_res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
- ulocimp_getScript, _kScripts, *pErrorCode);
- return (fallback_res > res) ? fallback_res : res;
- }
- if ( err == U_USING_DEFAULT_WARNING ) {
- return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
- ulocimp_getScript, _kScripts, *pErrorCode);
- } else {
- *pErrorCode = err;
- return res;
- }
- }
- static int32_t
- uloc_getDisplayScriptInContext(const char* locale,
- const char* displayLocale,
- char16_t *dest, int32_t destCapacity,
- UErrorCode *pErrorCode)
- {
- return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
- ulocimp_getScript, _kScripts, *pErrorCode);
- }
- U_CAPI int32_t U_EXPORT2
- uloc_getDisplayCountry(const char *locale,
- const char *displayLocale,
- char16_t *dest, int32_t destCapacity,
- UErrorCode *pErrorCode) {
- return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
- ulocimp_getRegion, _kCountries, *pErrorCode);
- }
- /*
- * TODO separate variant1_variant2_variant3...
- * by getting each tag's display string and concatenating them with ", "
- * in between - similar to uloc_getDisplayName()
- */
- U_CAPI int32_t U_EXPORT2
- uloc_getDisplayVariant(const char *locale,
- const char *displayLocale,
- char16_t *dest, int32_t destCapacity,
- UErrorCode *pErrorCode) {
- return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
- ulocimp_getVariant, _kVariants, *pErrorCode);
- }
- /* Instead of having a separate pass for 'special' patterns, reintegrate the two
- * so we don't get bitten by preflight bugs again. We can be reasonably efficient
- * without two separate code paths, this code isn't that performance-critical.
- *
- * This code is general enough to deal with patterns that have a prefix or swap the
- * language and remainder components, since we gave developers enough rope to do such
- * things if they futz with the pattern data. But since we don't give them a way to
- * specify a pattern for arbitrary combinations of components, there's not much use in
- * that. I don't think our data includes such patterns, the only variable I know if is
- * whether there is a space before the open paren, or not. Oh, and zh uses different
- * chars than the standard open/close paren (which ja and ko use, btw).
- */
- U_CAPI int32_t U_EXPORT2
- uloc_getDisplayName(const char *locale,
- const char *displayLocale,
- char16_t *dest, int32_t destCapacity,
- UErrorCode *pErrorCode)
- {
- static const char16_t defaultSeparator[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */
- static const char16_t sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
- static const char16_t sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
- static const int32_t subLen = 3;
- static const char16_t defaultPattern[10] = {
- 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000
- }; /* {0} ({1}) */
- static const int32_t defaultPatLen = 9;
- static const int32_t defaultSub0Pos = 0;
- static const int32_t defaultSub1Pos = 5;
- int32_t length; /* of formatted result */
- const char16_t *separator;
- int32_t sepLen = 0;
- const char16_t *pattern;
- int32_t patLen = 0;
- int32_t sub0Pos, sub1Pos;
-
- char16_t formatOpenParen = 0x0028; // (
- char16_t formatReplaceOpenParen = 0x005B; // [
- char16_t formatCloseParen = 0x0029; // )
- char16_t formatReplaceCloseParen = 0x005D; // ]
- UBool haveLang = true; /* assume true, set false if we find we don't have
- a lang component in the locale */
- UBool haveRest = true; /* assume true, set false if we find we don't have
- any other component in the locale */
- UBool retry = false; /* set true if we need to retry, see below */
- int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */
- if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
- return 0;
- }
- if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
- *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- {
- UErrorCode status = U_ZERO_ERROR;
- icu::LocalUResourceBundlePointer locbundle(
- ures_open(U_ICUDATA_LANG, displayLocale, &status));
- icu::LocalUResourceBundlePointer dspbundle(
- ures_getByKeyWithFallback(locbundle.getAlias(), _kLocaleDisplayPattern, nullptr, &status));
- separator=ures_getStringByKeyWithFallback(dspbundle.getAlias(), _kSeparator, &sepLen, &status);
- pattern=ures_getStringByKeyWithFallback(dspbundle.getAlias(), _kPattern, &patLen, &status);
- }
- /* If we couldn't find any data, then use the defaults */
- if(sepLen == 0) {
- separator = defaultSeparator;
- }
- /* #10244: Even though separator is now a pattern, it is awkward to handle it as such
- * here since we are trying to build the display string in place in the dest buffer,
- * and to handle it as a pattern would entail having separate storage for the
- * substrings that need to be combined (the first of which may be the result of
- * previous such combinations). So for now we continue to treat the portion between
- * {0} and {1} as a string to be appended when joining substrings, ignoring anything
- * that is before {0} or after {1} (no existing separator pattern has any such thing).
- * This is similar to how pattern is handled below.
- */
- {
- char16_t *p0=u_strstr(separator, sub0);
- char16_t *p1=u_strstr(separator, sub1);
- if (p0==nullptr || p1==nullptr || p1<p0) {
- *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- separator = (const char16_t *)p0 + subLen;
- sepLen = static_cast<int32_t>(p1 - separator);
- }
- if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) {
- pattern=defaultPattern;
- patLen=defaultPatLen;
- sub0Pos=defaultSub0Pos;
- sub1Pos=defaultSub1Pos;
- // use default formatOpenParen etc. set above
- } else { /* non-default pattern */
- char16_t *p0=u_strstr(pattern, sub0);
- char16_t *p1=u_strstr(pattern, sub1);
- if (p0==nullptr || p1==nullptr) {
- *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- sub0Pos = static_cast<int32_t>(p0-pattern);
- sub1Pos = static_cast<int32_t>(p1-pattern);
- if (sub1Pos < sub0Pos) { /* a very odd pattern */
- int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t;
- langi=1;
- }
- if (u_strchr(pattern, 0xFF08) != nullptr) {
- formatOpenParen = 0xFF08; // fullwidth (
- formatReplaceOpenParen = 0xFF3B; // fullwidth [
- formatCloseParen = 0xFF09; // fullwidth )
- formatReplaceCloseParen = 0xFF3D; // fullwidth ]
- }
- }
- /* We loop here because there is one case in which after the first pass we could need to
- * reextract the data. If there's initial padding before the first element, we put in
- * the padding and then write that element. If it turns out there's no second element,
- * we didn't need the padding. If we do need the data (no preflight), and the first element
- * would have fit but for the padding, we need to reextract. In this case (only) we
- * adjust the parameters so padding is not added, and repeat.
- */
- do {
- char16_t* p=dest;
- int32_t patPos=0; /* position in the pattern, used for non-substitution portions */
- int32_t langLen=0; /* length of language substitution */
- int32_t langPos=0; /* position in output of language substitution */
- int32_t restLen=0; /* length of 'everything else' substitution */
- int32_t restPos=0; /* position in output of 'everything else' substitution */
- icu::LocalUEnumerationPointer kenum; /* keyword enumeration */
- /* prefix of pattern, extremely likely to be empty */
- if(sub0Pos) {
- if(destCapacity >= sub0Pos) {
- while (patPos < sub0Pos) {
- *p++ = pattern[patPos++];
- }
- } else {
- patPos=sub0Pos;
- }
- length=sub0Pos;
- } else {
- length=0;
- }
- for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/
- UBool subdone = false; /* set true when ready to move to next substitution */
- /* prep p and cap for calls to get display components, pin cap to 0 since
- they complain if cap is negative */
- int32_t cap=destCapacity-length;
- if (cap <= 0) {
- cap=0;
- } else {
- p=dest+length;
- }
- if (subi == langi) { /* {0}*/
- if(haveLang) {
- langPos=length;
- langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode);
- length+=langLen;
- haveLang=langLen>0;
- }
- subdone=true;
- } else { /* {1} */
- if(!haveRest) {
- subdone=true;
- } else {
- int32_t len; /* length of component (plus other stuff) we just fetched */
- switch(resti++) {
- case 0:
- restPos=length;
- len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode);
- break;
- case 1:
- len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode);
- break;
- case 2:
- len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode);
- break;
- case 3:
- kenum.adoptInstead(uloc_openKeywords(locale, pErrorCode));
- U_FALLTHROUGH;
- default: {
- const char* kw=uenum_next(kenum.getAlias(), &len, pErrorCode);
- if (kw == nullptr) {
- len=0; /* mark that we didn't add a component */
- subdone=true;
- } else {
- /* incorporating this behavior into the loop made it even more complex,
- so just special case it here */
- len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode);
- if(len) {
- if(len < cap) {
- p[len]=0x3d; /* '=', assume we'll need it */
- }
- len+=1;
- /* adjust for call to get keyword */
- cap-=len;
- if(cap <= 0) {
- cap=0;
- } else {
- p+=len;
- }
- }
- /* reset for call below */
- if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
- *pErrorCode=U_ZERO_ERROR;
- }
- int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale,
- p, cap, pErrorCode);
- if(len) {
- if(vlen==0) {
- --len; /* remove unneeded '=' */
- }
- /* restore cap and p to what they were at start */
- cap=destCapacity-length;
- if(cap <= 0) {
- cap=0;
- } else {
- p=dest+length;
- }
- }
- len+=vlen; /* total we added for key + '=' + value */
- }
- } break;
- } /* end switch */
- if (len>0) {
- /* we added a component, so add separator and write it if there's room. */
- if(len+sepLen<=cap) {
- const char16_t * plimit = p + len;
- for (; p < plimit; p++) {
- if (*p == formatOpenParen) {
- *p = formatReplaceOpenParen;
- } else if (*p == formatCloseParen) {
- *p = formatReplaceCloseParen;
- }
- }
- for(int32_t i=0;i<sepLen;++i) {
- *p++=separator[i];
- }
- }
- length+=len+sepLen;
- } else if(subdone) {
- /* remove separator if we added it */
- if (length!=restPos) {
- length-=sepLen;
- }
- restLen=length-restPos;
- haveRest=restLen>0;
- }
- }
- }
- if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
- *pErrorCode=U_ZERO_ERROR;
- }
- if(subdone) {
- if(haveLang && haveRest) {
- /* append internal portion of pattern, the first time,
- or last portion of pattern the second time */
- int32_t padLen;
- patPos+=subLen;
- padLen=(subi==0 ? sub1Pos : patLen)-patPos;
- if(length+padLen <= destCapacity) {
- p=dest+length;
- for(int32_t i=0;i<padLen;++i) {
- *p++=pattern[patPos++];
- }
- } else {
- patPos+=padLen;
- }
- length+=padLen;
- } else if(subi==0) {
- /* don't have first component, reset for second component */
- sub0Pos=0;
- length=0;
- } else if(length>0) {
- /* true length is the length of just the component we got. */
- length=haveLang?langLen:restLen;
- if(dest && sub0Pos!=0) {
- if (sub0Pos+length<=destCapacity) {
- /* first component not at start of result,
- but we have full component in buffer. */
- u_memmove(dest, dest+(haveLang?langPos:restPos), length);
- } else {
- /* would have fit, but didn't because of pattern prefix. */
- sub0Pos=0; /* stops initial padding (and a second retry,
- so we won't end up here again) */
- retry=true;
- }
- }
- }
- ++subi; /* move on to next substitution */
- }
- }
- } while(retry);
- return u_terminateUChars(dest, destCapacity, length, pErrorCode);
- }
- U_CAPI int32_t U_EXPORT2
- uloc_getDisplayKeyword(const char* keyword,
- const char* displayLocale,
- char16_t* dest,
- int32_t destCapacity,
- UErrorCode* status){
- /* argument checking */
- if(status==nullptr || U_FAILURE(*status)) {
- return 0;
- }
- if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
- *status=U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- /* pass itemKey=nullptr to look for a top-level item */
- return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
- _kKeys, nullptr,
- keyword,
- keyword,
- dest, destCapacity,
- *status);
- }
- #define UCURRENCY_DISPLAY_NAME_INDEX 1
- U_CAPI int32_t U_EXPORT2
- uloc_getDisplayKeywordValue( const char* locale,
- const char* keyword,
- const char* displayLocale,
- char16_t* dest,
- int32_t destCapacity,
- UErrorCode* status){
- /* argument checking */
- if(status==nullptr || U_FAILURE(*status)) {
- return 0;
- }
- if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
- *status=U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- /* get the keyword value */
- CharString keywordValue;
- if (keyword != nullptr && *keyword != '\0') {
- keywordValue = ulocimp_getKeywordValue(locale, keyword, *status);
- }
- /*
- * if the keyword is equal to currency .. then to get the display name
- * we need to do the fallback ourselves
- */
- if(uprv_stricmp(keyword, _kCurrency)==0){
- int32_t dispNameLen = 0;
- const char16_t *dispName = nullptr;
- icu::LocalUResourceBundlePointer bundle(
- ures_open(U_ICUDATA_CURR, displayLocale, status));
- icu::LocalUResourceBundlePointer currencies(
- ures_getByKey(bundle.getAlias(), _kCurrencies, nullptr, status));
- icu::LocalUResourceBundlePointer currency(
- ures_getByKeyWithFallback(currencies.getAlias(), keywordValue.data(), nullptr, status));
- dispName = ures_getStringByIndex(currency.getAlias(), UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
- if(U_FAILURE(*status)){
- if(*status == U_MISSING_RESOURCE_ERROR){
- /* we just want to write the value over if nothing is available */
- *status = U_USING_DEFAULT_WARNING;
- }else{
- return 0;
- }
- }
- /* now copy the dispName over if not nullptr */
- if(dispName != nullptr){
- if(dispNameLen <= destCapacity){
- u_memcpy(dest, dispName, dispNameLen);
- return u_terminateUChars(dest, destCapacity, dispNameLen, status);
- }else{
- *status = U_BUFFER_OVERFLOW_ERROR;
- return dispNameLen;
- }
- }else{
- /* we have not found the display name for the value .. just copy over */
- if(keywordValue.length() <= destCapacity){
- u_charsToUChars(keywordValue.data(), dest, keywordValue.length());
- return u_terminateUChars(dest, destCapacity, keywordValue.length(), status);
- }else{
- *status = U_BUFFER_OVERFLOW_ERROR;
- return keywordValue.length();
- }
- }
-
- }else{
- return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
- _kTypes, keyword,
- keywordValue.data(),
- keywordValue.data(),
- dest, destCapacity,
- *status);
- }
- }
|