locdispnames.cpp 34 KB

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