11cb0ef41Sopenharmony_ci// © 2016 and later: Unicode, Inc. and others.
21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
31cb0ef41Sopenharmony_ci/*
41cb0ef41Sopenharmony_ci*******************************************************************************
51cb0ef41Sopenharmony_ci*
61cb0ef41Sopenharmony_ci*   Copyright (C) 1997-2016, International Business Machines
71cb0ef41Sopenharmony_ci*   Corporation and others.  All Rights Reserved.
81cb0ef41Sopenharmony_ci*
91cb0ef41Sopenharmony_ci*******************************************************************************
101cb0ef41Sopenharmony_ci*   file name:  locdispnames.cpp
111cb0ef41Sopenharmony_ci*   encoding:   UTF-8
121cb0ef41Sopenharmony_ci*   tab size:   8 (not used)
131cb0ef41Sopenharmony_ci*   indentation:4
141cb0ef41Sopenharmony_ci*
151cb0ef41Sopenharmony_ci*   created on: 2010feb25
161cb0ef41Sopenharmony_ci*   created by: Markus W. Scherer
171cb0ef41Sopenharmony_ci*
181cb0ef41Sopenharmony_ci*   Code for locale display names, separated out from other .cpp files
191cb0ef41Sopenharmony_ci*   that then do not depend on resource bundle code and display name data.
201cb0ef41Sopenharmony_ci*/
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci#include "unicode/utypes.h"
231cb0ef41Sopenharmony_ci#include "unicode/brkiter.h"
241cb0ef41Sopenharmony_ci#include "unicode/locid.h"
251cb0ef41Sopenharmony_ci#include "unicode/uenum.h"
261cb0ef41Sopenharmony_ci#include "unicode/uloc.h"
271cb0ef41Sopenharmony_ci#include "unicode/ures.h"
281cb0ef41Sopenharmony_ci#include "unicode/ustring.h"
291cb0ef41Sopenharmony_ci#include "bytesinkutil.h"
301cb0ef41Sopenharmony_ci#include "charstr.h"
311cb0ef41Sopenharmony_ci#include "cmemory.h"
321cb0ef41Sopenharmony_ci#include "cstring.h"
331cb0ef41Sopenharmony_ci#include "putilimp.h"
341cb0ef41Sopenharmony_ci#include "ulocimp.h"
351cb0ef41Sopenharmony_ci#include "uresimp.h"
361cb0ef41Sopenharmony_ci#include "ureslocs.h"
371cb0ef41Sopenharmony_ci#include "ustr_imp.h"
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci// C++ API ----------------------------------------------------------------- ***
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ciU_NAMESPACE_BEGIN
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ciUnicodeString&
441cb0ef41Sopenharmony_ciLocale::getDisplayLanguage(UnicodeString& dispLang) const
451cb0ef41Sopenharmony_ci{
461cb0ef41Sopenharmony_ci    return this->getDisplayLanguage(getDefault(), dispLang);
471cb0ef41Sopenharmony_ci}
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci/*We cannot make any assumptions on the size of the output display strings
501cb0ef41Sopenharmony_ci* Yet, since we are calling through to a C API, we need to set limits on
511cb0ef41Sopenharmony_ci* buffer size. For all the following getDisplay functions we first attempt
521cb0ef41Sopenharmony_ci* to fill up a stack allocated buffer. If it is to small we heap allocated
531cb0ef41Sopenharmony_ci* the exact buffer we need copy it to the UnicodeString and delete it*/
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ciUnicodeString&
561cb0ef41Sopenharmony_ciLocale::getDisplayLanguage(const Locale &displayLocale,
571cb0ef41Sopenharmony_ci                           UnicodeString &result) const {
581cb0ef41Sopenharmony_ci    char16_t *buffer;
591cb0ef41Sopenharmony_ci    UErrorCode errorCode=U_ZERO_ERROR;
601cb0ef41Sopenharmony_ci    int32_t length;
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
631cb0ef41Sopenharmony_ci    if(buffer==0) {
641cb0ef41Sopenharmony_ci        result.truncate(0);
651cb0ef41Sopenharmony_ci        return result;
661cb0ef41Sopenharmony_ci    }
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci    length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
691cb0ef41Sopenharmony_ci                                   buffer, result.getCapacity(),
701cb0ef41Sopenharmony_ci                                   &errorCode);
711cb0ef41Sopenharmony_ci    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
741cb0ef41Sopenharmony_ci        buffer=result.getBuffer(length);
751cb0ef41Sopenharmony_ci        if(buffer==0) {
761cb0ef41Sopenharmony_ci            result.truncate(0);
771cb0ef41Sopenharmony_ci            return result;
781cb0ef41Sopenharmony_ci        }
791cb0ef41Sopenharmony_ci        errorCode=U_ZERO_ERROR;
801cb0ef41Sopenharmony_ci        length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
811cb0ef41Sopenharmony_ci                                       buffer, result.getCapacity(),
821cb0ef41Sopenharmony_ci                                       &errorCode);
831cb0ef41Sopenharmony_ci        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
841cb0ef41Sopenharmony_ci    }
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci    return result;
871cb0ef41Sopenharmony_ci}
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ciUnicodeString&
901cb0ef41Sopenharmony_ciLocale::getDisplayScript(UnicodeString& dispScript) const
911cb0ef41Sopenharmony_ci{
921cb0ef41Sopenharmony_ci    return this->getDisplayScript(getDefault(), dispScript);
931cb0ef41Sopenharmony_ci}
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ciUnicodeString&
961cb0ef41Sopenharmony_ciLocale::getDisplayScript(const Locale &displayLocale,
971cb0ef41Sopenharmony_ci                          UnicodeString &result) const {
981cb0ef41Sopenharmony_ci    char16_t *buffer;
991cb0ef41Sopenharmony_ci    UErrorCode errorCode=U_ZERO_ERROR;
1001cb0ef41Sopenharmony_ci    int32_t length;
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
1031cb0ef41Sopenharmony_ci    if(buffer==0) {
1041cb0ef41Sopenharmony_ci        result.truncate(0);
1051cb0ef41Sopenharmony_ci        return result;
1061cb0ef41Sopenharmony_ci    }
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci    length=uloc_getDisplayScript(fullName, displayLocale.fullName,
1091cb0ef41Sopenharmony_ci                                  buffer, result.getCapacity(),
1101cb0ef41Sopenharmony_ci                                  &errorCode);
1111cb0ef41Sopenharmony_ci    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
1141cb0ef41Sopenharmony_ci        buffer=result.getBuffer(length);
1151cb0ef41Sopenharmony_ci        if(buffer==0) {
1161cb0ef41Sopenharmony_ci            result.truncate(0);
1171cb0ef41Sopenharmony_ci            return result;
1181cb0ef41Sopenharmony_ci        }
1191cb0ef41Sopenharmony_ci        errorCode=U_ZERO_ERROR;
1201cb0ef41Sopenharmony_ci        length=uloc_getDisplayScript(fullName, displayLocale.fullName,
1211cb0ef41Sopenharmony_ci                                      buffer, result.getCapacity(),
1221cb0ef41Sopenharmony_ci                                      &errorCode);
1231cb0ef41Sopenharmony_ci        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
1241cb0ef41Sopenharmony_ci    }
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci    return result;
1271cb0ef41Sopenharmony_ci}
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ciUnicodeString&
1301cb0ef41Sopenharmony_ciLocale::getDisplayCountry(UnicodeString& dispCntry) const
1311cb0ef41Sopenharmony_ci{
1321cb0ef41Sopenharmony_ci    return this->getDisplayCountry(getDefault(), dispCntry);
1331cb0ef41Sopenharmony_ci}
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ciUnicodeString&
1361cb0ef41Sopenharmony_ciLocale::getDisplayCountry(const Locale &displayLocale,
1371cb0ef41Sopenharmony_ci                          UnicodeString &result) const {
1381cb0ef41Sopenharmony_ci    char16_t *buffer;
1391cb0ef41Sopenharmony_ci    UErrorCode errorCode=U_ZERO_ERROR;
1401cb0ef41Sopenharmony_ci    int32_t length;
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
1431cb0ef41Sopenharmony_ci    if(buffer==0) {
1441cb0ef41Sopenharmony_ci        result.truncate(0);
1451cb0ef41Sopenharmony_ci        return result;
1461cb0ef41Sopenharmony_ci    }
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci    length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
1491cb0ef41Sopenharmony_ci                                  buffer, result.getCapacity(),
1501cb0ef41Sopenharmony_ci                                  &errorCode);
1511cb0ef41Sopenharmony_ci    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
1541cb0ef41Sopenharmony_ci        buffer=result.getBuffer(length);
1551cb0ef41Sopenharmony_ci        if(buffer==0) {
1561cb0ef41Sopenharmony_ci            result.truncate(0);
1571cb0ef41Sopenharmony_ci            return result;
1581cb0ef41Sopenharmony_ci        }
1591cb0ef41Sopenharmony_ci        errorCode=U_ZERO_ERROR;
1601cb0ef41Sopenharmony_ci        length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
1611cb0ef41Sopenharmony_ci                                      buffer, result.getCapacity(),
1621cb0ef41Sopenharmony_ci                                      &errorCode);
1631cb0ef41Sopenharmony_ci        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
1641cb0ef41Sopenharmony_ci    }
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci    return result;
1671cb0ef41Sopenharmony_ci}
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ciUnicodeString&
1701cb0ef41Sopenharmony_ciLocale::getDisplayVariant(UnicodeString& dispVar) const
1711cb0ef41Sopenharmony_ci{
1721cb0ef41Sopenharmony_ci    return this->getDisplayVariant(getDefault(), dispVar);
1731cb0ef41Sopenharmony_ci}
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ciUnicodeString&
1761cb0ef41Sopenharmony_ciLocale::getDisplayVariant(const Locale &displayLocale,
1771cb0ef41Sopenharmony_ci                          UnicodeString &result) const {
1781cb0ef41Sopenharmony_ci    char16_t *buffer;
1791cb0ef41Sopenharmony_ci    UErrorCode errorCode=U_ZERO_ERROR;
1801cb0ef41Sopenharmony_ci    int32_t length;
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
1831cb0ef41Sopenharmony_ci    if(buffer==0) {
1841cb0ef41Sopenharmony_ci        result.truncate(0);
1851cb0ef41Sopenharmony_ci        return result;
1861cb0ef41Sopenharmony_ci    }
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci    length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
1891cb0ef41Sopenharmony_ci                                  buffer, result.getCapacity(),
1901cb0ef41Sopenharmony_ci                                  &errorCode);
1911cb0ef41Sopenharmony_ci    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
1941cb0ef41Sopenharmony_ci        buffer=result.getBuffer(length);
1951cb0ef41Sopenharmony_ci        if(buffer==0) {
1961cb0ef41Sopenharmony_ci            result.truncate(0);
1971cb0ef41Sopenharmony_ci            return result;
1981cb0ef41Sopenharmony_ci        }
1991cb0ef41Sopenharmony_ci        errorCode=U_ZERO_ERROR;
2001cb0ef41Sopenharmony_ci        length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
2011cb0ef41Sopenharmony_ci                                      buffer, result.getCapacity(),
2021cb0ef41Sopenharmony_ci                                      &errorCode);
2031cb0ef41Sopenharmony_ci        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
2041cb0ef41Sopenharmony_ci    }
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci    return result;
2071cb0ef41Sopenharmony_ci}
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ciUnicodeString&
2101cb0ef41Sopenharmony_ciLocale::getDisplayName( UnicodeString& name ) const
2111cb0ef41Sopenharmony_ci{
2121cb0ef41Sopenharmony_ci    return this->getDisplayName(getDefault(), name);
2131cb0ef41Sopenharmony_ci}
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ciUnicodeString&
2161cb0ef41Sopenharmony_ciLocale::getDisplayName(const Locale &displayLocale,
2171cb0ef41Sopenharmony_ci                       UnicodeString &result) const {
2181cb0ef41Sopenharmony_ci    char16_t *buffer;
2191cb0ef41Sopenharmony_ci    UErrorCode errorCode=U_ZERO_ERROR;
2201cb0ef41Sopenharmony_ci    int32_t length;
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
2231cb0ef41Sopenharmony_ci    if(buffer==0) {
2241cb0ef41Sopenharmony_ci        result.truncate(0);
2251cb0ef41Sopenharmony_ci        return result;
2261cb0ef41Sopenharmony_ci    }
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_ci    length=uloc_getDisplayName(fullName, displayLocale.fullName,
2291cb0ef41Sopenharmony_ci                               buffer, result.getCapacity(),
2301cb0ef41Sopenharmony_ci                               &errorCode);
2311cb0ef41Sopenharmony_ci    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
2341cb0ef41Sopenharmony_ci        buffer=result.getBuffer(length);
2351cb0ef41Sopenharmony_ci        if(buffer==0) {
2361cb0ef41Sopenharmony_ci            result.truncate(0);
2371cb0ef41Sopenharmony_ci            return result;
2381cb0ef41Sopenharmony_ci        }
2391cb0ef41Sopenharmony_ci        errorCode=U_ZERO_ERROR;
2401cb0ef41Sopenharmony_ci        length=uloc_getDisplayName(fullName, displayLocale.fullName,
2411cb0ef41Sopenharmony_ci                                   buffer, result.getCapacity(),
2421cb0ef41Sopenharmony_ci                                   &errorCode);
2431cb0ef41Sopenharmony_ci        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
2441cb0ef41Sopenharmony_ci    }
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_ci    return result;
2471cb0ef41Sopenharmony_ci}
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_ci#if ! UCONFIG_NO_BREAK_ITERATION
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci// -------------------------------------
2521cb0ef41Sopenharmony_ci// Gets the objectLocale display name in the default locale language.
2531cb0ef41Sopenharmony_ciUnicodeString& U_EXPORT2
2541cb0ef41Sopenharmony_ciBreakIterator::getDisplayName(const Locale& objectLocale,
2551cb0ef41Sopenharmony_ci                             UnicodeString& name)
2561cb0ef41Sopenharmony_ci{
2571cb0ef41Sopenharmony_ci    return objectLocale.getDisplayName(name);
2581cb0ef41Sopenharmony_ci}
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ci// -------------------------------------
2611cb0ef41Sopenharmony_ci// Gets the objectLocale display name in the displayLocale language.
2621cb0ef41Sopenharmony_ciUnicodeString& U_EXPORT2
2631cb0ef41Sopenharmony_ciBreakIterator::getDisplayName(const Locale& objectLocale,
2641cb0ef41Sopenharmony_ci                             const Locale& displayLocale,
2651cb0ef41Sopenharmony_ci                             UnicodeString& name)
2661cb0ef41Sopenharmony_ci{
2671cb0ef41Sopenharmony_ci    return objectLocale.getDisplayName(displayLocale, name);
2681cb0ef41Sopenharmony_ci}
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci#endif
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ciU_NAMESPACE_END
2741cb0ef41Sopenharmony_ci
2751cb0ef41Sopenharmony_ci// C API ------------------------------------------------------------------- ***
2761cb0ef41Sopenharmony_ci
2771cb0ef41Sopenharmony_ciU_NAMESPACE_USE
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ci/* ### Constants **************************************************/
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci/* These strings describe the resources we attempt to load from
2821cb0ef41Sopenharmony_ci the locale ResourceBundle data file.*/
2831cb0ef41Sopenharmony_cistatic const char _kLanguages[]       = "Languages";
2841cb0ef41Sopenharmony_cistatic const char _kScripts[]         = "Scripts";
2851cb0ef41Sopenharmony_cistatic const char _kScriptsStandAlone[] = "Scripts%stand-alone";
2861cb0ef41Sopenharmony_cistatic const char _kCountries[]       = "Countries";
2871cb0ef41Sopenharmony_cistatic const char _kVariants[]        = "Variants";
2881cb0ef41Sopenharmony_cistatic const char _kKeys[]            = "Keys";
2891cb0ef41Sopenharmony_cistatic const char _kTypes[]           = "Types";
2901cb0ef41Sopenharmony_ci//static const char _kRootName[]        = "root";
2911cb0ef41Sopenharmony_cistatic const char _kCurrency[]        = "currency";
2921cb0ef41Sopenharmony_cistatic const char _kCurrencies[]      = "Currencies";
2931cb0ef41Sopenharmony_cistatic const char _kLocaleDisplayPattern[] = "localeDisplayPattern";
2941cb0ef41Sopenharmony_cistatic const char _kPattern[]         = "pattern";
2951cb0ef41Sopenharmony_cistatic const char _kSeparator[]       = "separator";
2961cb0ef41Sopenharmony_ci
2971cb0ef41Sopenharmony_ci/* ### Display name **************************************************/
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_cistatic int32_t
3001cb0ef41Sopenharmony_ci_getStringOrCopyKey(const char *path, const char *locale,
3011cb0ef41Sopenharmony_ci                    const char *tableKey,
3021cb0ef41Sopenharmony_ci                    const char* subTableKey,
3031cb0ef41Sopenharmony_ci                    const char *itemKey,
3041cb0ef41Sopenharmony_ci                    const char *substitute,
3051cb0ef41Sopenharmony_ci                    char16_t *dest, int32_t destCapacity,
3061cb0ef41Sopenharmony_ci                    UErrorCode *pErrorCode) {
3071cb0ef41Sopenharmony_ci    const char16_t *s = nullptr;
3081cb0ef41Sopenharmony_ci    int32_t length = 0;
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ci    if(itemKey==nullptr) {
3111cb0ef41Sopenharmony_ci        /* top-level item: normal resource bundle access */
3121cb0ef41Sopenharmony_ci        icu::LocalUResourceBundlePointer rb(ures_open(path, locale, pErrorCode));
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ci        if(U_SUCCESS(*pErrorCode)) {
3151cb0ef41Sopenharmony_ci            s=ures_getStringByKey(rb.getAlias(), tableKey, &length, pErrorCode);
3161cb0ef41Sopenharmony_ci            /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
3171cb0ef41Sopenharmony_ci        }
3181cb0ef41Sopenharmony_ci    } else {
3191cb0ef41Sopenharmony_ci        bool isLanguageCode = (uprv_strncmp(tableKey, _kLanguages, 9) == 0);
3201cb0ef41Sopenharmony_ci        /* Language code should not be a number. If it is, set the error code. */
3211cb0ef41Sopenharmony_ci        if (isLanguageCode && uprv_strtol(itemKey, nullptr, 10)) {
3221cb0ef41Sopenharmony_ci            *pErrorCode = U_MISSING_RESOURCE_ERROR;
3231cb0ef41Sopenharmony_ci        } else {
3241cb0ef41Sopenharmony_ci            /* second-level item, use special fallback */
3251cb0ef41Sopenharmony_ci            s=uloc_getTableStringWithFallback(path, locale,
3261cb0ef41Sopenharmony_ci                                               tableKey,
3271cb0ef41Sopenharmony_ci                                               subTableKey,
3281cb0ef41Sopenharmony_ci                                               itemKey,
3291cb0ef41Sopenharmony_ci                                               &length,
3301cb0ef41Sopenharmony_ci                                               pErrorCode);
3311cb0ef41Sopenharmony_ci            if (U_FAILURE(*pErrorCode) && isLanguageCode && itemKey != nullptr) {
3321cb0ef41Sopenharmony_ci                // convert itemKey locale code to canonical form and try again, ICU-20870
3331cb0ef41Sopenharmony_ci                *pErrorCode = U_ZERO_ERROR;
3341cb0ef41Sopenharmony_ci                Locale canonKey = Locale::createCanonical(itemKey);
3351cb0ef41Sopenharmony_ci                s=uloc_getTableStringWithFallback(path, locale,
3361cb0ef41Sopenharmony_ci                                                    tableKey,
3371cb0ef41Sopenharmony_ci                                                    subTableKey,
3381cb0ef41Sopenharmony_ci                                                    canonKey.getName(),
3391cb0ef41Sopenharmony_ci                                                    &length,
3401cb0ef41Sopenharmony_ci                                                    pErrorCode);
3411cb0ef41Sopenharmony_ci            }
3421cb0ef41Sopenharmony_ci        }
3431cb0ef41Sopenharmony_ci    }
3441cb0ef41Sopenharmony_ci
3451cb0ef41Sopenharmony_ci    if(U_SUCCESS(*pErrorCode)) {
3461cb0ef41Sopenharmony_ci        int32_t copyLength=uprv_min(length, destCapacity);
3471cb0ef41Sopenharmony_ci        if(copyLength>0 && s != nullptr) {
3481cb0ef41Sopenharmony_ci            u_memcpy(dest, s, copyLength);
3491cb0ef41Sopenharmony_ci        }
3501cb0ef41Sopenharmony_ci    } else {
3511cb0ef41Sopenharmony_ci        /* no string from a resource bundle: convert the substitute */
3521cb0ef41Sopenharmony_ci        length=(int32_t)uprv_strlen(substitute);
3531cb0ef41Sopenharmony_ci        u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
3541cb0ef41Sopenharmony_ci        *pErrorCode=U_USING_DEFAULT_WARNING;
3551cb0ef41Sopenharmony_ci    }
3561cb0ef41Sopenharmony_ci
3571cb0ef41Sopenharmony_ci    return u_terminateUChars(dest, destCapacity, length, pErrorCode);
3581cb0ef41Sopenharmony_ci}
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_citypedef  int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *);
3611cb0ef41Sopenharmony_ci
3621cb0ef41Sopenharmony_cistatic int32_t
3631cb0ef41Sopenharmony_ci_getDisplayNameForComponent(const char *locale,
3641cb0ef41Sopenharmony_ci                            const char *displayLocale,
3651cb0ef41Sopenharmony_ci                            char16_t *dest, int32_t destCapacity,
3661cb0ef41Sopenharmony_ci                            UDisplayNameGetter *getter,
3671cb0ef41Sopenharmony_ci                            const char *tag,
3681cb0ef41Sopenharmony_ci                            UErrorCode *pErrorCode) {
3691cb0ef41Sopenharmony_ci    char localeBuffer[ULOC_FULLNAME_CAPACITY*4];
3701cb0ef41Sopenharmony_ci    int32_t length;
3711cb0ef41Sopenharmony_ci    UErrorCode localStatus;
3721cb0ef41Sopenharmony_ci    const char* root = nullptr;
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci    /* argument checking */
3751cb0ef41Sopenharmony_ci    if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
3761cb0ef41Sopenharmony_ci        return 0;
3771cb0ef41Sopenharmony_ci    }
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ci    if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
3801cb0ef41Sopenharmony_ci        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
3811cb0ef41Sopenharmony_ci        return 0;
3821cb0ef41Sopenharmony_ci    }
3831cb0ef41Sopenharmony_ci
3841cb0ef41Sopenharmony_ci    localStatus = U_ZERO_ERROR;
3851cb0ef41Sopenharmony_ci    length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
3861cb0ef41Sopenharmony_ci    if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
3871cb0ef41Sopenharmony_ci        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
3881cb0ef41Sopenharmony_ci        return 0;
3891cb0ef41Sopenharmony_ci    }
3901cb0ef41Sopenharmony_ci    if(length==0) {
3911cb0ef41Sopenharmony_ci        // For the display name, we treat this as unknown language (ICU-20273).
3921cb0ef41Sopenharmony_ci        if (getter == uloc_getLanguage) {
3931cb0ef41Sopenharmony_ci            uprv_strcpy(localeBuffer, "und");
3941cb0ef41Sopenharmony_ci        } else {
3951cb0ef41Sopenharmony_ci            return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
3961cb0ef41Sopenharmony_ci        }
3971cb0ef41Sopenharmony_ci    }
3981cb0ef41Sopenharmony_ci
3991cb0ef41Sopenharmony_ci    root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
4001cb0ef41Sopenharmony_ci
4011cb0ef41Sopenharmony_ci    return _getStringOrCopyKey(root, displayLocale,
4021cb0ef41Sopenharmony_ci                               tag, nullptr, localeBuffer,
4031cb0ef41Sopenharmony_ci                               localeBuffer,
4041cb0ef41Sopenharmony_ci                               dest, destCapacity,
4051cb0ef41Sopenharmony_ci                               pErrorCode);
4061cb0ef41Sopenharmony_ci}
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2
4091cb0ef41Sopenharmony_ciuloc_getDisplayLanguage(const char *locale,
4101cb0ef41Sopenharmony_ci                        const char *displayLocale,
4111cb0ef41Sopenharmony_ci                        char16_t *dest, int32_t destCapacity,
4121cb0ef41Sopenharmony_ci                        UErrorCode *pErrorCode) {
4131cb0ef41Sopenharmony_ci    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
4141cb0ef41Sopenharmony_ci                uloc_getLanguage, _kLanguages, pErrorCode);
4151cb0ef41Sopenharmony_ci}
4161cb0ef41Sopenharmony_ci
4171cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2
4181cb0ef41Sopenharmony_ciuloc_getDisplayScript(const char* locale,
4191cb0ef41Sopenharmony_ci                      const char* displayLocale,
4201cb0ef41Sopenharmony_ci                      char16_t *dest, int32_t destCapacity,
4211cb0ef41Sopenharmony_ci                      UErrorCode *pErrorCode)
4221cb0ef41Sopenharmony_ci{
4231cb0ef41Sopenharmony_ci    UErrorCode err = U_ZERO_ERROR;
4241cb0ef41Sopenharmony_ci    int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
4251cb0ef41Sopenharmony_ci                uloc_getScript, _kScriptsStandAlone, &err);
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_ci    if (destCapacity == 0 && err == U_BUFFER_OVERFLOW_ERROR) {
4281cb0ef41Sopenharmony_ci        // For preflight, return the max of the value and the fallback.
4291cb0ef41Sopenharmony_ci        int32_t fallback_res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
4301cb0ef41Sopenharmony_ci                                                           uloc_getScript, _kScripts, pErrorCode);
4311cb0ef41Sopenharmony_ci        return (fallback_res > res) ? fallback_res : res;
4321cb0ef41Sopenharmony_ci    }
4331cb0ef41Sopenharmony_ci    if ( err == U_USING_DEFAULT_WARNING ) {
4341cb0ef41Sopenharmony_ci        return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
4351cb0ef41Sopenharmony_ci                                           uloc_getScript, _kScripts, pErrorCode);
4361cb0ef41Sopenharmony_ci    } else {
4371cb0ef41Sopenharmony_ci        *pErrorCode = err;
4381cb0ef41Sopenharmony_ci        return res;
4391cb0ef41Sopenharmony_ci    }
4401cb0ef41Sopenharmony_ci}
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_cistatic int32_t
4431cb0ef41Sopenharmony_ciuloc_getDisplayScriptInContext(const char* locale,
4441cb0ef41Sopenharmony_ci                      const char* displayLocale,
4451cb0ef41Sopenharmony_ci                      char16_t *dest, int32_t destCapacity,
4461cb0ef41Sopenharmony_ci                      UErrorCode *pErrorCode)
4471cb0ef41Sopenharmony_ci{
4481cb0ef41Sopenharmony_ci    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
4491cb0ef41Sopenharmony_ci                    uloc_getScript, _kScripts, pErrorCode);
4501cb0ef41Sopenharmony_ci}
4511cb0ef41Sopenharmony_ci
4521cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2
4531cb0ef41Sopenharmony_ciuloc_getDisplayCountry(const char *locale,
4541cb0ef41Sopenharmony_ci                       const char *displayLocale,
4551cb0ef41Sopenharmony_ci                       char16_t *dest, int32_t destCapacity,
4561cb0ef41Sopenharmony_ci                       UErrorCode *pErrorCode) {
4571cb0ef41Sopenharmony_ci    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
4581cb0ef41Sopenharmony_ci                uloc_getCountry, _kCountries, pErrorCode);
4591cb0ef41Sopenharmony_ci}
4601cb0ef41Sopenharmony_ci
4611cb0ef41Sopenharmony_ci/*
4621cb0ef41Sopenharmony_ci * TODO separate variant1_variant2_variant3...
4631cb0ef41Sopenharmony_ci * by getting each tag's display string and concatenating them with ", "
4641cb0ef41Sopenharmony_ci * in between - similar to uloc_getDisplayName()
4651cb0ef41Sopenharmony_ci */
4661cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2
4671cb0ef41Sopenharmony_ciuloc_getDisplayVariant(const char *locale,
4681cb0ef41Sopenharmony_ci                       const char *displayLocale,
4691cb0ef41Sopenharmony_ci                       char16_t *dest, int32_t destCapacity,
4701cb0ef41Sopenharmony_ci                       UErrorCode *pErrorCode) {
4711cb0ef41Sopenharmony_ci    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
4721cb0ef41Sopenharmony_ci                uloc_getVariant, _kVariants, pErrorCode);
4731cb0ef41Sopenharmony_ci}
4741cb0ef41Sopenharmony_ci
4751cb0ef41Sopenharmony_ci/* Instead of having a separate pass for 'special' patterns, reintegrate the two
4761cb0ef41Sopenharmony_ci * so we don't get bitten by preflight bugs again.  We can be reasonably efficient
4771cb0ef41Sopenharmony_ci * without two separate code paths, this code isn't that performance-critical.
4781cb0ef41Sopenharmony_ci *
4791cb0ef41Sopenharmony_ci * This code is general enough to deal with patterns that have a prefix or swap the
4801cb0ef41Sopenharmony_ci * language and remainder components, since we gave developers enough rope to do such
4811cb0ef41Sopenharmony_ci * things if they futz with the pattern data.  But since we don't give them a way to
4821cb0ef41Sopenharmony_ci * specify a pattern for arbitrary combinations of components, there's not much use in
4831cb0ef41Sopenharmony_ci * that.  I don't think our data includes such patterns, the only variable I know if is
4841cb0ef41Sopenharmony_ci * whether there is a space before the open paren, or not.  Oh, and zh uses different
4851cb0ef41Sopenharmony_ci * chars than the standard open/close paren (which ja and ko use, btw).
4861cb0ef41Sopenharmony_ci */
4871cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2
4881cb0ef41Sopenharmony_ciuloc_getDisplayName(const char *locale,
4891cb0ef41Sopenharmony_ci                    const char *displayLocale,
4901cb0ef41Sopenharmony_ci                    char16_t *dest, int32_t destCapacity,
4911cb0ef41Sopenharmony_ci                    UErrorCode *pErrorCode)
4921cb0ef41Sopenharmony_ci{
4931cb0ef41Sopenharmony_ci    static const char16_t defaultSeparator[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */
4941cb0ef41Sopenharmony_ci    static const char16_t sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
4951cb0ef41Sopenharmony_ci    static const char16_t sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
4961cb0ef41Sopenharmony_ci    static const int32_t subLen = 3;
4971cb0ef41Sopenharmony_ci    static const char16_t defaultPattern[10] = {
4981cb0ef41Sopenharmony_ci        0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000
4991cb0ef41Sopenharmony_ci    }; /* {0} ({1}) */
5001cb0ef41Sopenharmony_ci    static const int32_t defaultPatLen = 9;
5011cb0ef41Sopenharmony_ci    static const int32_t defaultSub0Pos = 0;
5021cb0ef41Sopenharmony_ci    static const int32_t defaultSub1Pos = 5;
5031cb0ef41Sopenharmony_ci
5041cb0ef41Sopenharmony_ci    int32_t length; /* of formatted result */
5051cb0ef41Sopenharmony_ci
5061cb0ef41Sopenharmony_ci    const char16_t *separator;
5071cb0ef41Sopenharmony_ci    int32_t sepLen = 0;
5081cb0ef41Sopenharmony_ci    const char16_t *pattern;
5091cb0ef41Sopenharmony_ci    int32_t patLen = 0;
5101cb0ef41Sopenharmony_ci    int32_t sub0Pos, sub1Pos;
5111cb0ef41Sopenharmony_ci
5121cb0ef41Sopenharmony_ci    char16_t formatOpenParen         = 0x0028; // (
5131cb0ef41Sopenharmony_ci    char16_t formatReplaceOpenParen  = 0x005B; // [
5141cb0ef41Sopenharmony_ci    char16_t formatCloseParen        = 0x0029; // )
5151cb0ef41Sopenharmony_ci    char16_t formatReplaceCloseParen = 0x005D; // ]
5161cb0ef41Sopenharmony_ci
5171cb0ef41Sopenharmony_ci    UBool haveLang = true; /* assume true, set false if we find we don't have
5181cb0ef41Sopenharmony_ci                              a lang component in the locale */
5191cb0ef41Sopenharmony_ci    UBool haveRest = true; /* assume true, set false if we find we don't have
5201cb0ef41Sopenharmony_ci                              any other component in the locale */
5211cb0ef41Sopenharmony_ci    UBool retry = false; /* set true if we need to retry, see below */
5221cb0ef41Sopenharmony_ci
5231cb0ef41Sopenharmony_ci    int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */
5241cb0ef41Sopenharmony_ci
5251cb0ef41Sopenharmony_ci    if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
5261cb0ef41Sopenharmony_ci        return 0;
5271cb0ef41Sopenharmony_ci    }
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_ci    if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
5301cb0ef41Sopenharmony_ci        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
5311cb0ef41Sopenharmony_ci        return 0;
5321cb0ef41Sopenharmony_ci    }
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_ci    {
5351cb0ef41Sopenharmony_ci        UErrorCode status = U_ZERO_ERROR;
5361cb0ef41Sopenharmony_ci
5371cb0ef41Sopenharmony_ci        icu::LocalUResourceBundlePointer locbundle(
5381cb0ef41Sopenharmony_ci                ures_open(U_ICUDATA_LANG, displayLocale, &status));
5391cb0ef41Sopenharmony_ci        icu::LocalUResourceBundlePointer dspbundle(
5401cb0ef41Sopenharmony_ci                ures_getByKeyWithFallback(locbundle.getAlias(), _kLocaleDisplayPattern, nullptr, &status));
5411cb0ef41Sopenharmony_ci
5421cb0ef41Sopenharmony_ci        separator=ures_getStringByKeyWithFallback(dspbundle.getAlias(), _kSeparator, &sepLen, &status);
5431cb0ef41Sopenharmony_ci        pattern=ures_getStringByKeyWithFallback(dspbundle.getAlias(), _kPattern, &patLen, &status);
5441cb0ef41Sopenharmony_ci    }
5451cb0ef41Sopenharmony_ci
5461cb0ef41Sopenharmony_ci    /* If we couldn't find any data, then use the defaults */
5471cb0ef41Sopenharmony_ci    if(sepLen == 0) {
5481cb0ef41Sopenharmony_ci       separator = defaultSeparator;
5491cb0ef41Sopenharmony_ci    }
5501cb0ef41Sopenharmony_ci    /* #10244: Even though separator is now a pattern, it is awkward to handle it as such
5511cb0ef41Sopenharmony_ci     * here since we are trying to build the display string in place in the dest buffer,
5521cb0ef41Sopenharmony_ci     * and to handle it as a pattern would entail having separate storage for the
5531cb0ef41Sopenharmony_ci     * substrings that need to be combined (the first of which may be the result of
5541cb0ef41Sopenharmony_ci     * previous such combinations). So for now we continue to treat the portion between
5551cb0ef41Sopenharmony_ci     * {0} and {1} as a string to be appended when joining substrings, ignoring anything
5561cb0ef41Sopenharmony_ci     * that is before {0} or after {1} (no existing separator pattern has any such thing).
5571cb0ef41Sopenharmony_ci     * This is similar to how pattern is handled below.
5581cb0ef41Sopenharmony_ci     */
5591cb0ef41Sopenharmony_ci    {
5601cb0ef41Sopenharmony_ci        char16_t *p0=u_strstr(separator, sub0);
5611cb0ef41Sopenharmony_ci        char16_t *p1=u_strstr(separator, sub1);
5621cb0ef41Sopenharmony_ci        if (p0==nullptr || p1==nullptr || p1<p0) {
5631cb0ef41Sopenharmony_ci            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
5641cb0ef41Sopenharmony_ci            return 0;
5651cb0ef41Sopenharmony_ci        }
5661cb0ef41Sopenharmony_ci        separator = (const char16_t *)p0 + subLen;
5671cb0ef41Sopenharmony_ci        sepLen = static_cast<int32_t>(p1 - separator);
5681cb0ef41Sopenharmony_ci    }
5691cb0ef41Sopenharmony_ci
5701cb0ef41Sopenharmony_ci    if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) {
5711cb0ef41Sopenharmony_ci        pattern=defaultPattern;
5721cb0ef41Sopenharmony_ci        patLen=defaultPatLen;
5731cb0ef41Sopenharmony_ci        sub0Pos=defaultSub0Pos;
5741cb0ef41Sopenharmony_ci        sub1Pos=defaultSub1Pos;
5751cb0ef41Sopenharmony_ci        // use default formatOpenParen etc. set above
5761cb0ef41Sopenharmony_ci    } else { /* non-default pattern */
5771cb0ef41Sopenharmony_ci        char16_t *p0=u_strstr(pattern, sub0);
5781cb0ef41Sopenharmony_ci        char16_t *p1=u_strstr(pattern, sub1);
5791cb0ef41Sopenharmony_ci        if (p0==nullptr || p1==nullptr) {
5801cb0ef41Sopenharmony_ci            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
5811cb0ef41Sopenharmony_ci            return 0;
5821cb0ef41Sopenharmony_ci        }
5831cb0ef41Sopenharmony_ci        sub0Pos = static_cast<int32_t>(p0-pattern);
5841cb0ef41Sopenharmony_ci        sub1Pos = static_cast<int32_t>(p1-pattern);
5851cb0ef41Sopenharmony_ci        if (sub1Pos < sub0Pos) { /* a very odd pattern */
5861cb0ef41Sopenharmony_ci            int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t;
5871cb0ef41Sopenharmony_ci            langi=1;
5881cb0ef41Sopenharmony_ci        }
5891cb0ef41Sopenharmony_ci        if (u_strchr(pattern, 0xFF08) != nullptr) {
5901cb0ef41Sopenharmony_ci            formatOpenParen         = 0xFF08; // fullwidth (
5911cb0ef41Sopenharmony_ci            formatReplaceOpenParen  = 0xFF3B; // fullwidth [
5921cb0ef41Sopenharmony_ci            formatCloseParen        = 0xFF09; // fullwidth )
5931cb0ef41Sopenharmony_ci            formatReplaceCloseParen = 0xFF3D; // fullwidth ]
5941cb0ef41Sopenharmony_ci        }
5951cb0ef41Sopenharmony_ci    }
5961cb0ef41Sopenharmony_ci
5971cb0ef41Sopenharmony_ci    /* We loop here because there is one case in which after the first pass we could need to
5981cb0ef41Sopenharmony_ci     * reextract the data.  If there's initial padding before the first element, we put in
5991cb0ef41Sopenharmony_ci     * the padding and then write that element.  If it turns out there's no second element,
6001cb0ef41Sopenharmony_ci     * we didn't need the padding.  If we do need the data (no preflight), and the first element
6011cb0ef41Sopenharmony_ci     * would have fit but for the padding, we need to reextract.  In this case (only) we
6021cb0ef41Sopenharmony_ci     * adjust the parameters so padding is not added, and repeat.
6031cb0ef41Sopenharmony_ci     */
6041cb0ef41Sopenharmony_ci    do {
6051cb0ef41Sopenharmony_ci        char16_t* p=dest;
6061cb0ef41Sopenharmony_ci        int32_t patPos=0; /* position in the pattern, used for non-substitution portions */
6071cb0ef41Sopenharmony_ci        int32_t langLen=0; /* length of language substitution */
6081cb0ef41Sopenharmony_ci        int32_t langPos=0; /* position in output of language substitution */
6091cb0ef41Sopenharmony_ci        int32_t restLen=0; /* length of 'everything else' substitution */
6101cb0ef41Sopenharmony_ci        int32_t restPos=0; /* position in output of 'everything else' substitution */
6111cb0ef41Sopenharmony_ci        icu::LocalUEnumerationPointer kenum; /* keyword enumeration */
6121cb0ef41Sopenharmony_ci
6131cb0ef41Sopenharmony_ci        /* prefix of pattern, extremely likely to be empty */
6141cb0ef41Sopenharmony_ci        if(sub0Pos) {
6151cb0ef41Sopenharmony_ci            if(destCapacity >= sub0Pos) {
6161cb0ef41Sopenharmony_ci                while (patPos < sub0Pos) {
6171cb0ef41Sopenharmony_ci                    *p++ = pattern[patPos++];
6181cb0ef41Sopenharmony_ci                }
6191cb0ef41Sopenharmony_ci            } else {
6201cb0ef41Sopenharmony_ci                patPos=sub0Pos;
6211cb0ef41Sopenharmony_ci            }
6221cb0ef41Sopenharmony_ci            length=sub0Pos;
6231cb0ef41Sopenharmony_ci        } else {
6241cb0ef41Sopenharmony_ci            length=0;
6251cb0ef41Sopenharmony_ci        }
6261cb0ef41Sopenharmony_ci
6271cb0ef41Sopenharmony_ci        for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/
6281cb0ef41Sopenharmony_ci            UBool subdone = false; /* set true when ready to move to next substitution */
6291cb0ef41Sopenharmony_ci
6301cb0ef41Sopenharmony_ci            /* prep p and cap for calls to get display components, pin cap to 0 since
6311cb0ef41Sopenharmony_ci               they complain if cap is negative */
6321cb0ef41Sopenharmony_ci            int32_t cap=destCapacity-length;
6331cb0ef41Sopenharmony_ci            if (cap <= 0) {
6341cb0ef41Sopenharmony_ci                cap=0;
6351cb0ef41Sopenharmony_ci            } else {
6361cb0ef41Sopenharmony_ci                p=dest+length;
6371cb0ef41Sopenharmony_ci            }
6381cb0ef41Sopenharmony_ci
6391cb0ef41Sopenharmony_ci            if (subi == langi) { /* {0}*/
6401cb0ef41Sopenharmony_ci                if(haveLang) {
6411cb0ef41Sopenharmony_ci                    langPos=length;
6421cb0ef41Sopenharmony_ci                    langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode);
6431cb0ef41Sopenharmony_ci                    length+=langLen;
6441cb0ef41Sopenharmony_ci                    haveLang=langLen>0;
6451cb0ef41Sopenharmony_ci                }
6461cb0ef41Sopenharmony_ci                subdone=true;
6471cb0ef41Sopenharmony_ci            } else { /* {1} */
6481cb0ef41Sopenharmony_ci                if(!haveRest) {
6491cb0ef41Sopenharmony_ci                    subdone=true;
6501cb0ef41Sopenharmony_ci                } else {
6511cb0ef41Sopenharmony_ci                    int32_t len; /* length of component (plus other stuff) we just fetched */
6521cb0ef41Sopenharmony_ci                    switch(resti++) {
6531cb0ef41Sopenharmony_ci                        case 0:
6541cb0ef41Sopenharmony_ci                            restPos=length;
6551cb0ef41Sopenharmony_ci                            len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode);
6561cb0ef41Sopenharmony_ci                            break;
6571cb0ef41Sopenharmony_ci                        case 1:
6581cb0ef41Sopenharmony_ci                            len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode);
6591cb0ef41Sopenharmony_ci                            break;
6601cb0ef41Sopenharmony_ci                        case 2:
6611cb0ef41Sopenharmony_ci                            len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode);
6621cb0ef41Sopenharmony_ci                            break;
6631cb0ef41Sopenharmony_ci                        case 3:
6641cb0ef41Sopenharmony_ci                            kenum.adoptInstead(uloc_openKeywords(locale, pErrorCode));
6651cb0ef41Sopenharmony_ci                            U_FALLTHROUGH;
6661cb0ef41Sopenharmony_ci                        default: {
6671cb0ef41Sopenharmony_ci                            const char* kw=uenum_next(kenum.getAlias(), &len, pErrorCode);
6681cb0ef41Sopenharmony_ci                            if (kw == nullptr) {
6691cb0ef41Sopenharmony_ci                                len=0; /* mark that we didn't add a component */
6701cb0ef41Sopenharmony_ci                                subdone=true;
6711cb0ef41Sopenharmony_ci                            } else {
6721cb0ef41Sopenharmony_ci                                /* incorporating this behavior into the loop made it even more complex,
6731cb0ef41Sopenharmony_ci                                   so just special case it here */
6741cb0ef41Sopenharmony_ci                                len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode);
6751cb0ef41Sopenharmony_ci                                if(len) {
6761cb0ef41Sopenharmony_ci                                    if(len < cap) {
6771cb0ef41Sopenharmony_ci                                        p[len]=0x3d; /* '=', assume we'll need it */
6781cb0ef41Sopenharmony_ci                                    }
6791cb0ef41Sopenharmony_ci                                    len+=1;
6801cb0ef41Sopenharmony_ci
6811cb0ef41Sopenharmony_ci                                    /* adjust for call to get keyword */
6821cb0ef41Sopenharmony_ci                                    cap-=len;
6831cb0ef41Sopenharmony_ci                                    if(cap <= 0) {
6841cb0ef41Sopenharmony_ci                                        cap=0;
6851cb0ef41Sopenharmony_ci                                    } else {
6861cb0ef41Sopenharmony_ci                                        p+=len;
6871cb0ef41Sopenharmony_ci                                    }
6881cb0ef41Sopenharmony_ci                                }
6891cb0ef41Sopenharmony_ci                                /* reset for call below */
6901cb0ef41Sopenharmony_ci                                if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
6911cb0ef41Sopenharmony_ci                                    *pErrorCode=U_ZERO_ERROR;
6921cb0ef41Sopenharmony_ci                                }
6931cb0ef41Sopenharmony_ci                                int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale,
6941cb0ef41Sopenharmony_ci                                                                           p, cap, pErrorCode);
6951cb0ef41Sopenharmony_ci                                if(len) {
6961cb0ef41Sopenharmony_ci                                    if(vlen==0) {
6971cb0ef41Sopenharmony_ci                                        --len; /* remove unneeded '=' */
6981cb0ef41Sopenharmony_ci                                    }
6991cb0ef41Sopenharmony_ci                                    /* restore cap and p to what they were at start */
7001cb0ef41Sopenharmony_ci                                    cap=destCapacity-length;
7011cb0ef41Sopenharmony_ci                                    if(cap <= 0) {
7021cb0ef41Sopenharmony_ci                                        cap=0;
7031cb0ef41Sopenharmony_ci                                    } else {
7041cb0ef41Sopenharmony_ci                                        p=dest+length;
7051cb0ef41Sopenharmony_ci                                    }
7061cb0ef41Sopenharmony_ci                                }
7071cb0ef41Sopenharmony_ci                                len+=vlen; /* total we added for key + '=' + value */
7081cb0ef41Sopenharmony_ci                            }
7091cb0ef41Sopenharmony_ci                        } break;
7101cb0ef41Sopenharmony_ci                    } /* end switch */
7111cb0ef41Sopenharmony_ci
7121cb0ef41Sopenharmony_ci                    if (len>0) {
7131cb0ef41Sopenharmony_ci                        /* we added a component, so add separator and write it if there's room. */
7141cb0ef41Sopenharmony_ci                        if(len+sepLen<=cap) {
7151cb0ef41Sopenharmony_ci                            const char16_t * plimit = p + len;
7161cb0ef41Sopenharmony_ci                            for (; p < plimit; p++) {
7171cb0ef41Sopenharmony_ci                                if (*p == formatOpenParen) {
7181cb0ef41Sopenharmony_ci                                    *p = formatReplaceOpenParen;
7191cb0ef41Sopenharmony_ci                                } else if (*p == formatCloseParen) {
7201cb0ef41Sopenharmony_ci                                    *p = formatReplaceCloseParen;
7211cb0ef41Sopenharmony_ci                                }
7221cb0ef41Sopenharmony_ci                            }
7231cb0ef41Sopenharmony_ci                            for(int32_t i=0;i<sepLen;++i) {
7241cb0ef41Sopenharmony_ci                                *p++=separator[i];
7251cb0ef41Sopenharmony_ci                            }
7261cb0ef41Sopenharmony_ci                        }
7271cb0ef41Sopenharmony_ci                        length+=len+sepLen;
7281cb0ef41Sopenharmony_ci                    } else if(subdone) {
7291cb0ef41Sopenharmony_ci                        /* remove separator if we added it */
7301cb0ef41Sopenharmony_ci                        if (length!=restPos) {
7311cb0ef41Sopenharmony_ci                            length-=sepLen;
7321cb0ef41Sopenharmony_ci                        }
7331cb0ef41Sopenharmony_ci                        restLen=length-restPos;
7341cb0ef41Sopenharmony_ci                        haveRest=restLen>0;
7351cb0ef41Sopenharmony_ci                    }
7361cb0ef41Sopenharmony_ci                }
7371cb0ef41Sopenharmony_ci            }
7381cb0ef41Sopenharmony_ci
7391cb0ef41Sopenharmony_ci            if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
7401cb0ef41Sopenharmony_ci                *pErrorCode=U_ZERO_ERROR;
7411cb0ef41Sopenharmony_ci            }
7421cb0ef41Sopenharmony_ci
7431cb0ef41Sopenharmony_ci            if(subdone) {
7441cb0ef41Sopenharmony_ci                if(haveLang && haveRest) {
7451cb0ef41Sopenharmony_ci                    /* append internal portion of pattern, the first time,
7461cb0ef41Sopenharmony_ci                       or last portion of pattern the second time */
7471cb0ef41Sopenharmony_ci                    int32_t padLen;
7481cb0ef41Sopenharmony_ci                    patPos+=subLen;
7491cb0ef41Sopenharmony_ci                    padLen=(subi==0 ? sub1Pos : patLen)-patPos;
7501cb0ef41Sopenharmony_ci                    if(length+padLen <= destCapacity) {
7511cb0ef41Sopenharmony_ci                        p=dest+length;
7521cb0ef41Sopenharmony_ci                        for(int32_t i=0;i<padLen;++i) {
7531cb0ef41Sopenharmony_ci                            *p++=pattern[patPos++];
7541cb0ef41Sopenharmony_ci                        }
7551cb0ef41Sopenharmony_ci                    } else {
7561cb0ef41Sopenharmony_ci                        patPos+=padLen;
7571cb0ef41Sopenharmony_ci                    }
7581cb0ef41Sopenharmony_ci                    length+=padLen;
7591cb0ef41Sopenharmony_ci                } else if(subi==0) {
7601cb0ef41Sopenharmony_ci                    /* don't have first component, reset for second component */
7611cb0ef41Sopenharmony_ci                    sub0Pos=0;
7621cb0ef41Sopenharmony_ci                    length=0;
7631cb0ef41Sopenharmony_ci                } else if(length>0) {
7641cb0ef41Sopenharmony_ci                    /* true length is the length of just the component we got. */
7651cb0ef41Sopenharmony_ci                    length=haveLang?langLen:restLen;
7661cb0ef41Sopenharmony_ci                    if(dest && sub0Pos!=0) {
7671cb0ef41Sopenharmony_ci                        if (sub0Pos+length<=destCapacity) {
7681cb0ef41Sopenharmony_ci                            /* first component not at start of result,
7691cb0ef41Sopenharmony_ci                               but we have full component in buffer. */
7701cb0ef41Sopenharmony_ci                            u_memmove(dest, dest+(haveLang?langPos:restPos), length);
7711cb0ef41Sopenharmony_ci                        } else {
7721cb0ef41Sopenharmony_ci                            /* would have fit, but didn't because of pattern prefix. */
7731cb0ef41Sopenharmony_ci                            sub0Pos=0; /* stops initial padding (and a second retry,
7741cb0ef41Sopenharmony_ci                                          so we won't end up here again) */
7751cb0ef41Sopenharmony_ci                            retry=true;
7761cb0ef41Sopenharmony_ci                        }
7771cb0ef41Sopenharmony_ci                    }
7781cb0ef41Sopenharmony_ci                }
7791cb0ef41Sopenharmony_ci
7801cb0ef41Sopenharmony_ci                ++subi; /* move on to next substitution */
7811cb0ef41Sopenharmony_ci            }
7821cb0ef41Sopenharmony_ci        }
7831cb0ef41Sopenharmony_ci    } while(retry);
7841cb0ef41Sopenharmony_ci
7851cb0ef41Sopenharmony_ci    return u_terminateUChars(dest, destCapacity, length, pErrorCode);
7861cb0ef41Sopenharmony_ci}
7871cb0ef41Sopenharmony_ci
7881cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2
7891cb0ef41Sopenharmony_ciuloc_getDisplayKeyword(const char* keyword,
7901cb0ef41Sopenharmony_ci                       const char* displayLocale,
7911cb0ef41Sopenharmony_ci                       char16_t* dest,
7921cb0ef41Sopenharmony_ci                       int32_t destCapacity,
7931cb0ef41Sopenharmony_ci                       UErrorCode* status){
7941cb0ef41Sopenharmony_ci
7951cb0ef41Sopenharmony_ci    /* argument checking */
7961cb0ef41Sopenharmony_ci    if(status==nullptr || U_FAILURE(*status)) {
7971cb0ef41Sopenharmony_ci        return 0;
7981cb0ef41Sopenharmony_ci    }
7991cb0ef41Sopenharmony_ci
8001cb0ef41Sopenharmony_ci    if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
8011cb0ef41Sopenharmony_ci        *status=U_ILLEGAL_ARGUMENT_ERROR;
8021cb0ef41Sopenharmony_ci        return 0;
8031cb0ef41Sopenharmony_ci    }
8041cb0ef41Sopenharmony_ci
8051cb0ef41Sopenharmony_ci
8061cb0ef41Sopenharmony_ci    /* pass itemKey=nullptr to look for a top-level item */
8071cb0ef41Sopenharmony_ci    return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
8081cb0ef41Sopenharmony_ci                               _kKeys, nullptr,
8091cb0ef41Sopenharmony_ci                               keyword,
8101cb0ef41Sopenharmony_ci                               keyword,
8111cb0ef41Sopenharmony_ci                               dest, destCapacity,
8121cb0ef41Sopenharmony_ci                               status);
8131cb0ef41Sopenharmony_ci
8141cb0ef41Sopenharmony_ci}
8151cb0ef41Sopenharmony_ci
8161cb0ef41Sopenharmony_ci
8171cb0ef41Sopenharmony_ci#define UCURRENCY_DISPLAY_NAME_INDEX 1
8181cb0ef41Sopenharmony_ci
8191cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2
8201cb0ef41Sopenharmony_ciuloc_getDisplayKeywordValue(   const char* locale,
8211cb0ef41Sopenharmony_ci                               const char* keyword,
8221cb0ef41Sopenharmony_ci                               const char* displayLocale,
8231cb0ef41Sopenharmony_ci                               char16_t* dest,
8241cb0ef41Sopenharmony_ci                               int32_t destCapacity,
8251cb0ef41Sopenharmony_ci                               UErrorCode* status){
8261cb0ef41Sopenharmony_ci
8271cb0ef41Sopenharmony_ci
8281cb0ef41Sopenharmony_ci    /* argument checking */
8291cb0ef41Sopenharmony_ci    if(status==nullptr || U_FAILURE(*status)) {
8301cb0ef41Sopenharmony_ci        return 0;
8311cb0ef41Sopenharmony_ci    }
8321cb0ef41Sopenharmony_ci
8331cb0ef41Sopenharmony_ci    if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
8341cb0ef41Sopenharmony_ci        *status=U_ILLEGAL_ARGUMENT_ERROR;
8351cb0ef41Sopenharmony_ci        return 0;
8361cb0ef41Sopenharmony_ci    }
8371cb0ef41Sopenharmony_ci
8381cb0ef41Sopenharmony_ci    /* get the keyword value */
8391cb0ef41Sopenharmony_ci    CharString keywordValue;
8401cb0ef41Sopenharmony_ci    {
8411cb0ef41Sopenharmony_ci        CharStringByteSink sink(&keywordValue);
8421cb0ef41Sopenharmony_ci        ulocimp_getKeywordValue(locale, keyword, sink, status);
8431cb0ef41Sopenharmony_ci    }
8441cb0ef41Sopenharmony_ci
8451cb0ef41Sopenharmony_ci    /*
8461cb0ef41Sopenharmony_ci     * if the keyword is equal to currency .. then to get the display name
8471cb0ef41Sopenharmony_ci     * we need to do the fallback ourselves
8481cb0ef41Sopenharmony_ci     */
8491cb0ef41Sopenharmony_ci    if(uprv_stricmp(keyword, _kCurrency)==0){
8501cb0ef41Sopenharmony_ci
8511cb0ef41Sopenharmony_ci        int32_t dispNameLen = 0;
8521cb0ef41Sopenharmony_ci        const char16_t *dispName = nullptr;
8531cb0ef41Sopenharmony_ci
8541cb0ef41Sopenharmony_ci        icu::LocalUResourceBundlePointer bundle(
8551cb0ef41Sopenharmony_ci                ures_open(U_ICUDATA_CURR, displayLocale, status));
8561cb0ef41Sopenharmony_ci        icu::LocalUResourceBundlePointer currencies(
8571cb0ef41Sopenharmony_ci                ures_getByKey(bundle.getAlias(), _kCurrencies, nullptr, status));
8581cb0ef41Sopenharmony_ci        icu::LocalUResourceBundlePointer currency(
8591cb0ef41Sopenharmony_ci                ures_getByKeyWithFallback(currencies.getAlias(), keywordValue.data(), nullptr, status));
8601cb0ef41Sopenharmony_ci
8611cb0ef41Sopenharmony_ci        dispName = ures_getStringByIndex(currency.getAlias(), UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
8621cb0ef41Sopenharmony_ci
8631cb0ef41Sopenharmony_ci        if(U_FAILURE(*status)){
8641cb0ef41Sopenharmony_ci            if(*status == U_MISSING_RESOURCE_ERROR){
8651cb0ef41Sopenharmony_ci                /* we just want to write the value over if nothing is available */
8661cb0ef41Sopenharmony_ci                *status = U_USING_DEFAULT_WARNING;
8671cb0ef41Sopenharmony_ci            }else{
8681cb0ef41Sopenharmony_ci                return 0;
8691cb0ef41Sopenharmony_ci            }
8701cb0ef41Sopenharmony_ci        }
8711cb0ef41Sopenharmony_ci
8721cb0ef41Sopenharmony_ci        /* now copy the dispName over if not nullptr */
8731cb0ef41Sopenharmony_ci        if(dispName != nullptr){
8741cb0ef41Sopenharmony_ci            if(dispNameLen <= destCapacity){
8751cb0ef41Sopenharmony_ci                u_memcpy(dest, dispName, dispNameLen);
8761cb0ef41Sopenharmony_ci                return u_terminateUChars(dest, destCapacity, dispNameLen, status);
8771cb0ef41Sopenharmony_ci            }else{
8781cb0ef41Sopenharmony_ci                *status = U_BUFFER_OVERFLOW_ERROR;
8791cb0ef41Sopenharmony_ci                return dispNameLen;
8801cb0ef41Sopenharmony_ci            }
8811cb0ef41Sopenharmony_ci        }else{
8821cb0ef41Sopenharmony_ci            /* we have not found the display name for the value .. just copy over */
8831cb0ef41Sopenharmony_ci            if(keywordValue.length() <= destCapacity){
8841cb0ef41Sopenharmony_ci                u_charsToUChars(keywordValue.data(), dest, keywordValue.length());
8851cb0ef41Sopenharmony_ci                return u_terminateUChars(dest, destCapacity, keywordValue.length(), status);
8861cb0ef41Sopenharmony_ci            }else{
8871cb0ef41Sopenharmony_ci                 *status = U_BUFFER_OVERFLOW_ERROR;
8881cb0ef41Sopenharmony_ci                return keywordValue.length();
8891cb0ef41Sopenharmony_ci            }
8901cb0ef41Sopenharmony_ci        }
8911cb0ef41Sopenharmony_ci
8921cb0ef41Sopenharmony_ci
8931cb0ef41Sopenharmony_ci    }else{
8941cb0ef41Sopenharmony_ci
8951cb0ef41Sopenharmony_ci        return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
8961cb0ef41Sopenharmony_ci                                   _kTypes, keyword,
8971cb0ef41Sopenharmony_ci                                   keywordValue.data(),
8981cb0ef41Sopenharmony_ci                                   keywordValue.data(),
8991cb0ef41Sopenharmony_ci                                   dest, destCapacity,
9001cb0ef41Sopenharmony_ci                                   status);
9011cb0ef41Sopenharmony_ci    }
9021cb0ef41Sopenharmony_ci}
903