1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 1997-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
10 * file name: locdispnames.cpp
12 * tab size: 8 (not used)
15 * created on: 2010feb25
16 * created by: Markus W. Scherer
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.
22 #include "unicode/utypes.h"
23 #include "unicode/brkiter.h"
24 #include "unicode/locid.h"
25 #include "unicode/uloc.h"
26 #include "unicode/ures.h"
27 #include "unicode/ustring.h"
36 // C++ API ----------------------------------------------------------------- ***
41 Locale::getDisplayLanguage(UnicodeString
& dispLang
) const
43 return this->getDisplayLanguage(getDefault(), dispLang
);
46 /*We cannot make any assumptions on the size of the output display strings
47 * Yet, since we are calling through to a C API, we need to set limits on
48 * buffer size. For all the following getDisplay functions we first attempt
49 * to fill up a stack allocated buffer. If it is to small we heap allocated
50 * the exact buffer we need copy it to the UnicodeString and delete it*/
53 Locale::getDisplayLanguage(const Locale
&displayLocale
,
54 UnicodeString
&result
) const {
56 UErrorCode errorCode
=U_ZERO_ERROR
;
59 buffer
=result
.getBuffer(ULOC_FULLNAME_CAPACITY
);
65 length
=uloc_getDisplayLanguage(fullName
, displayLocale
.fullName
,
66 buffer
, result
.getCapacity(),
68 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
70 if(errorCode
==U_BUFFER_OVERFLOW_ERROR
) {
71 buffer
=result
.getBuffer(length
);
76 errorCode
=U_ZERO_ERROR
;
77 length
=uloc_getDisplayLanguage(fullName
, displayLocale
.fullName
,
78 buffer
, result
.getCapacity(),
80 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
87 Locale::getDisplayScript(UnicodeString
& dispScript
) const
89 return this->getDisplayScript(getDefault(), dispScript
);
93 Locale::getDisplayScript(const Locale
&displayLocale
,
94 UnicodeString
&result
) const {
96 UErrorCode errorCode
=U_ZERO_ERROR
;
99 buffer
=result
.getBuffer(ULOC_FULLNAME_CAPACITY
);
105 length
=uloc_getDisplayScript(fullName
, displayLocale
.fullName
,
106 buffer
, result
.getCapacity(),
108 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
110 if(errorCode
==U_BUFFER_OVERFLOW_ERROR
) {
111 buffer
=result
.getBuffer(length
);
116 errorCode
=U_ZERO_ERROR
;
117 length
=uloc_getDisplayScript(fullName
, displayLocale
.fullName
,
118 buffer
, result
.getCapacity(),
120 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
127 Locale::getDisplayCountry(UnicodeString
& dispCntry
) const
129 return this->getDisplayCountry(getDefault(), dispCntry
);
133 Locale::getDisplayCountry(const Locale
&displayLocale
,
134 UnicodeString
&result
) const {
136 UErrorCode errorCode
=U_ZERO_ERROR
;
139 buffer
=result
.getBuffer(ULOC_FULLNAME_CAPACITY
);
145 length
=uloc_getDisplayCountry(fullName
, displayLocale
.fullName
,
146 buffer
, result
.getCapacity(),
148 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
150 if(errorCode
==U_BUFFER_OVERFLOW_ERROR
) {
151 buffer
=result
.getBuffer(length
);
156 errorCode
=U_ZERO_ERROR
;
157 length
=uloc_getDisplayCountry(fullName
, displayLocale
.fullName
,
158 buffer
, result
.getCapacity(),
160 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
167 Locale::getDisplayVariant(UnicodeString
& dispVar
) const
169 return this->getDisplayVariant(getDefault(), dispVar
);
173 Locale::getDisplayVariant(const Locale
&displayLocale
,
174 UnicodeString
&result
) const {
176 UErrorCode errorCode
=U_ZERO_ERROR
;
179 buffer
=result
.getBuffer(ULOC_FULLNAME_CAPACITY
);
185 length
=uloc_getDisplayVariant(fullName
, displayLocale
.fullName
,
186 buffer
, result
.getCapacity(),
188 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
190 if(errorCode
==U_BUFFER_OVERFLOW_ERROR
) {
191 buffer
=result
.getBuffer(length
);
196 errorCode
=U_ZERO_ERROR
;
197 length
=uloc_getDisplayVariant(fullName
, displayLocale
.fullName
,
198 buffer
, result
.getCapacity(),
200 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
207 Locale::getDisplayName( UnicodeString
& name
) const
209 return this->getDisplayName(getDefault(), name
);
213 Locale::getDisplayName(const Locale
&displayLocale
,
214 UnicodeString
&result
) const {
216 UErrorCode errorCode
=U_ZERO_ERROR
;
219 buffer
=result
.getBuffer(ULOC_FULLNAME_CAPACITY
);
225 length
=uloc_getDisplayName(fullName
, displayLocale
.fullName
,
226 buffer
, result
.getCapacity(),
228 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
230 if(errorCode
==U_BUFFER_OVERFLOW_ERROR
) {
231 buffer
=result
.getBuffer(length
);
236 errorCode
=U_ZERO_ERROR
;
237 length
=uloc_getDisplayName(fullName
, displayLocale
.fullName
,
238 buffer
, result
.getCapacity(),
240 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
246 #if ! UCONFIG_NO_BREAK_ITERATION
248 // -------------------------------------
249 // Gets the objectLocale display name in the default locale language.
250 UnicodeString
& U_EXPORT2
251 BreakIterator::getDisplayName(const Locale
& objectLocale
,
254 return objectLocale
.getDisplayName(name
);
257 // -------------------------------------
258 // Gets the objectLocale display name in the displayLocale language.
259 UnicodeString
& U_EXPORT2
260 BreakIterator::getDisplayName(const Locale
& objectLocale
,
261 const Locale
& displayLocale
,
264 return objectLocale
.getDisplayName(displayLocale
, name
);
272 // C API ------------------------------------------------------------------- ***
276 /* ### Constants **************************************************/
278 /* These strings describe the resources we attempt to load from
279 the locale ResourceBundle data file.*/
280 static const char _kLanguages
[] = "Languages";
281 static const char _kScripts
[] = "Scripts";
282 static const char _kScriptsStandAlone
[] = "Scripts%stand-alone";
283 static const char _kCountries
[] = "Countries";
284 static const char _kVariants
[] = "Variants";
285 static const char _kKeys
[] = "Keys";
286 static const char _kTypes
[] = "Types";
287 //static const char _kRootName[] = "root";
288 static const char _kCurrency
[] = "currency";
289 static const char _kCurrencies
[] = "Currencies";
290 static const char _kLocaleDisplayPattern
[] = "localeDisplayPattern";
291 static const char _kPattern
[] = "pattern";
292 static const char _kSeparator
[] = "separator";
294 /* ### Display name **************************************************/
297 _getStringOrCopyKey(const char *path
, const char *locale
,
298 const char *tableKey
,
299 const char* subTableKey
,
301 const char *substitute
,
302 UChar
*dest
, int32_t destCapacity
,
303 UErrorCode
*pErrorCode
) {
304 const UChar
*s
= NULL
;
308 /* top-level item: normal resource bundle access */
311 rb
=ures_open(path
, locale
, pErrorCode
);
313 if(U_SUCCESS(*pErrorCode
)) {
314 s
=ures_getStringByKey(rb
, tableKey
, &length
, pErrorCode
);
315 /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
319 /* Language code should not be a number. If it is, set the error code. */
320 if (!uprv_strncmp(tableKey
, "Languages", 9) && uprv_strtol(itemKey
, NULL
, 10)) {
321 *pErrorCode
= U_MISSING_RESOURCE_ERROR
;
323 /* second-level item, use special fallback */
324 s
=uloc_getTableStringWithFallback(path
, locale
,
333 if(U_SUCCESS(*pErrorCode
)) {
334 int32_t copyLength
=uprv_min(length
, destCapacity
);
335 if(copyLength
>0 && s
!= NULL
) {
336 u_memcpy(dest
, s
, copyLength
);
339 /* no string from a resource bundle: convert the substitute */
340 length
=(int32_t)uprv_strlen(substitute
);
341 u_charsToUChars(substitute
, dest
, uprv_min(length
, destCapacity
));
342 *pErrorCode
=U_USING_DEFAULT_WARNING
;
345 return u_terminateUChars(dest
, destCapacity
, length
, pErrorCode
);
348 typedef int32_t U_CALLCONV
UDisplayNameGetter(const char *, char *, int32_t, UErrorCode
*);
351 _getDisplayNameForComponent(const char *locale
,
352 const char *displayLocale
,
353 UChar
*dest
, int32_t destCapacity
,
354 UDisplayNameGetter
*getter
,
356 UErrorCode
*pErrorCode
) {
357 char localeBuffer
[ULOC_FULLNAME_CAPACITY
*4];
359 UErrorCode localStatus
;
360 const char* root
= NULL
;
362 /* argument checking */
363 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
367 if(destCapacity
<0 || (destCapacity
>0 && dest
==NULL
)) {
368 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
372 localStatus
= U_ZERO_ERROR
;
373 length
=(*getter
)(locale
, localeBuffer
, sizeof(localeBuffer
), &localStatus
);
374 if(U_FAILURE(localStatus
) || localStatus
==U_STRING_NOT_TERMINATED_WARNING
) {
375 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
379 return u_terminateUChars(dest
, destCapacity
, 0, pErrorCode
);
382 root
= tag
== _kCountries
? U_ICUDATA_REGION
: U_ICUDATA_LANG
;
384 return _getStringOrCopyKey(root
, displayLocale
,
385 tag
, NULL
, localeBuffer
,
391 U_CAPI
int32_t U_EXPORT2
392 uloc_getDisplayLanguage(const char *locale
,
393 const char *displayLocale
,
394 UChar
*dest
, int32_t destCapacity
,
395 UErrorCode
*pErrorCode
) {
396 return _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
397 uloc_getLanguage
, _kLanguages
, pErrorCode
);
400 U_CAPI
int32_t U_EXPORT2
401 uloc_getDisplayScript(const char* locale
,
402 const char* displayLocale
,
403 UChar
*dest
, int32_t destCapacity
,
404 UErrorCode
*pErrorCode
)
406 UErrorCode err
= U_ZERO_ERROR
;
407 int32_t res
= _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
408 uloc_getScript
, _kScriptsStandAlone
, &err
);
410 if ( err
== U_USING_DEFAULT_WARNING
) {
411 return _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
412 uloc_getScript
, _kScripts
, pErrorCode
);
419 U_INTERNAL
int32_t U_EXPORT2
420 uloc_getDisplayScriptInContext(const char* locale
,
421 const char* displayLocale
,
422 UChar
*dest
, int32_t destCapacity
,
423 UErrorCode
*pErrorCode
)
425 return _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
426 uloc_getScript
, _kScripts
, pErrorCode
);
429 U_CAPI
int32_t U_EXPORT2
430 uloc_getDisplayCountry(const char *locale
,
431 const char *displayLocale
,
432 UChar
*dest
, int32_t destCapacity
,
433 UErrorCode
*pErrorCode
) {
434 return _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
435 uloc_getCountry
, _kCountries
, pErrorCode
);
439 * TODO separate variant1_variant2_variant3...
440 * by getting each tag's display string and concatenating them with ", "
441 * in between - similar to uloc_getDisplayName()
443 U_CAPI
int32_t U_EXPORT2
444 uloc_getDisplayVariant(const char *locale
,
445 const char *displayLocale
,
446 UChar
*dest
, int32_t destCapacity
,
447 UErrorCode
*pErrorCode
) {
448 return _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
449 uloc_getVariant
, _kVariants
, pErrorCode
);
452 /* Instead of having a separate pass for 'special' patterns, reintegrate the two
453 * so we don't get bitten by preflight bugs again. We can be reasonably efficient
454 * without two separate code paths, this code isn't that performance-critical.
456 * This code is general enough to deal with patterns that have a prefix or swap the
457 * language and remainder components, since we gave developers enough rope to do such
458 * things if they futz with the pattern data. But since we don't give them a way to
459 * specify a pattern for arbitrary combinations of components, there's not much use in
460 * that. I don't think our data includes such patterns, the only variable I know if is
461 * whether there is a space before the open paren, or not. Oh, and zh uses different
462 * chars than the standard open/close paren (which ja and ko use, btw).
464 U_CAPI
int32_t U_EXPORT2
465 uloc_getDisplayName(const char *locale
,
466 const char *displayLocale
,
467 UChar
*dest
, int32_t destCapacity
,
468 UErrorCode
*pErrorCode
)
470 static const UChar defaultSeparator
[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */
471 static const UChar sub0
[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
472 static const UChar sub1
[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
473 static const int32_t subLen
= 3;
474 static const UChar defaultPattern
[10] = {
475 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000
477 static const int32_t defaultPatLen
= 9;
478 static const int32_t defaultSub0Pos
= 0;
479 static const int32_t defaultSub1Pos
= 5;
481 int32_t length
; /* of formatted result */
483 const UChar
*separator
;
485 const UChar
*pattern
;
487 int32_t sub0Pos
, sub1Pos
;
489 UChar formatOpenParen
= 0x0028; // (
490 UChar formatReplaceOpenParen
= 0x005B; // [
491 UChar formatCloseParen
= 0x0029; // )
492 UChar formatReplaceCloseParen
= 0x005D; // ]
494 UBool haveLang
= TRUE
; /* assume true, set false if we find we don't have
495 a lang component in the locale */
496 UBool haveRest
= TRUE
; /* assume true, set false if we find we don't have
497 any other component in the locale */
498 UBool retry
= FALSE
; /* set true if we need to retry, see below */
500 int32_t langi
= 0; /* index of the language substitution (0 or 1), virtually always 0 */
502 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
506 if(destCapacity
<0 || (destCapacity
>0 && dest
==NULL
)) {
507 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
512 UErrorCode status
= U_ZERO_ERROR
;
513 UResourceBundle
* locbundle
=ures_open(U_ICUDATA_LANG
, displayLocale
, &status
);
514 UResourceBundle
* dspbundle
=ures_getByKeyWithFallback(locbundle
, _kLocaleDisplayPattern
,
517 separator
=ures_getStringByKeyWithFallback(dspbundle
, _kSeparator
, &sepLen
, &status
);
518 pattern
=ures_getStringByKeyWithFallback(dspbundle
, _kPattern
, &patLen
, &status
);
520 ures_close(dspbundle
);
521 ures_close(locbundle
);
524 /* If we couldn't find any data, then use the defaults */
526 separator
= defaultSeparator
;
528 /* #10244: Even though separator is now a pattern, it is awkward to handle it as such
529 * here since we are trying to build the display string in place in the dest buffer,
530 * and to handle it as a pattern would entail having separate storage for the
531 * substrings that need to be combined (the first of which may be the result of
532 * previous such combinations). So for now we continue to treat the portion between
533 * {0} and {1} as a string to be appended when joining substrings, ignoring anything
534 * that is before {0} or after {1} (no existing separator pattern has any such thing).
535 * This is similar to how pattern is handled below.
538 UChar
*p0
=u_strstr(separator
, sub0
);
539 UChar
*p1
=u_strstr(separator
, sub1
);
540 if (p0
==NULL
|| p1
==NULL
|| p1
<p0
) {
541 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
544 separator
= (const UChar
*)p0
+ subLen
;
545 sepLen
= static_cast<int32_t>(p1
- separator
);
548 if(patLen
==0 || (patLen
==defaultPatLen
&& !u_strncmp(pattern
, defaultPattern
, patLen
))) {
549 pattern
=defaultPattern
;
550 patLen
=defaultPatLen
;
551 sub0Pos
=defaultSub0Pos
;
552 sub1Pos
=defaultSub1Pos
;
553 // use default formatOpenParen etc. set above
554 } else { /* non-default pattern */
555 UChar
*p0
=u_strstr(pattern
, sub0
);
556 UChar
*p1
=u_strstr(pattern
, sub1
);
557 if (p0
==NULL
|| p1
==NULL
) {
558 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
561 sub0Pos
= static_cast<int32_t>(p0
-pattern
);
562 sub1Pos
= static_cast<int32_t>(p1
-pattern
);
563 if (sub1Pos
< sub0Pos
) { /* a very odd pattern */
564 int32_t t
=sub0Pos
; sub0Pos
=sub1Pos
; sub1Pos
=t
;
567 if (u_strchr(pattern
, 0xFF08) != NULL
) {
568 formatOpenParen
= 0xFF08; // fullwidth (
569 formatReplaceOpenParen
= 0xFF3B; // fullwidth [
570 formatCloseParen
= 0xFF09; // fullwidth )
571 formatReplaceCloseParen
= 0xFF3D; // fullwidth ]
575 /* We loop here because there is one case in which after the first pass we could need to
576 * reextract the data. If there's initial padding before the first element, we put in
577 * the padding and then write that element. If it turns out there's no second element,
578 * we didn't need the padding. If we do need the data (no preflight), and the first element
579 * would have fit but for the padding, we need to reextract. In this case (only) we
580 * adjust the parameters so padding is not added, and repeat.
584 int32_t patPos
=0; /* position in the pattern, used for non-substitution portions */
585 int32_t langLen
=0; /* length of language substitution */
586 int32_t langPos
=0; /* position in output of language substitution */
587 int32_t restLen
=0; /* length of 'everything else' substitution */
588 int32_t restPos
=0; /* position in output of 'everything else' substitution */
589 UEnumeration
* kenum
= NULL
; /* keyword enumeration */
591 /* prefix of pattern, extremely likely to be empty */
593 if(destCapacity
>= sub0Pos
) {
594 while (patPos
< sub0Pos
) {
595 *p
++ = pattern
[patPos
++];
605 for(int32_t subi
=0,resti
=0;subi
<2;) { /* iterate through patterns 0 and 1*/
606 UBool subdone
= FALSE
; /* set true when ready to move to next substitution */
608 /* prep p and cap for calls to get display components, pin cap to 0 since
609 they complain if cap is negative */
610 int32_t cap
=destCapacity
-length
;
617 if (subi
== langi
) { /* {0}*/
620 langLen
=uloc_getDisplayLanguage(locale
, displayLocale
, p
, cap
, pErrorCode
);
629 int32_t len
; /* length of component (plus other stuff) we just fetched */
633 len
=uloc_getDisplayScriptInContext(locale
, displayLocale
, p
, cap
, pErrorCode
);
636 len
=uloc_getDisplayCountry(locale
, displayLocale
, p
, cap
, pErrorCode
);
639 len
=uloc_getDisplayVariant(locale
, displayLocale
, p
, cap
, pErrorCode
);
642 kenum
= uloc_openKeywords(locale
, pErrorCode
);
645 const char* kw
=uenum_next(kenum
, &len
, pErrorCode
);
648 len
=0; /* mark that we didn't add a component */
651 /* incorporating this behavior into the loop made it even more complex,
652 so just special case it here */
653 len
= uloc_getDisplayKeyword(kw
, displayLocale
, p
, cap
, pErrorCode
);
656 p
[len
]=0x3d; /* '=', assume we'll need it */
660 /* adjust for call to get keyword */
668 /* reset for call below */
669 if(*pErrorCode
== U_BUFFER_OVERFLOW_ERROR
) {
670 *pErrorCode
=U_ZERO_ERROR
;
672 int32_t vlen
= uloc_getDisplayKeywordValue(locale
, kw
, displayLocale
,
676 --len
; /* remove unneeded '=' */
678 /* restore cap and p to what they were at start */
679 cap
=destCapacity
-length
;
686 len
+=vlen
; /* total we added for key + '=' + value */
692 /* we addeed a component, so add separator and write it if there's room. */
693 if(len
+sepLen
<=cap
) {
694 const UChar
* plimit
= p
+ len
;
695 for (; p
< plimit
; p
++) {
696 if (*p
== formatOpenParen
) {
697 *p
= formatReplaceOpenParen
;
698 } else if (*p
== formatCloseParen
) {
699 *p
= formatReplaceCloseParen
;
702 for(int32_t i
=0;i
<sepLen
;++i
) {
708 /* remove separator if we added it */
709 if (length
!=restPos
) {
712 restLen
=length
-restPos
;
718 if(*pErrorCode
== U_BUFFER_OVERFLOW_ERROR
) {
719 *pErrorCode
=U_ZERO_ERROR
;
723 if(haveLang
&& haveRest
) {
724 /* append internal portion of pattern, the first time,
725 or last portion of pattern the second time */
728 padLen
=(subi
==0 ? sub1Pos
: patLen
)-patPos
;
729 if(length
+padLen
< destCapacity
) {
731 for(int32_t i
=0;i
<padLen
;++i
) {
732 *p
++=pattern
[patPos
++];
739 /* don't have first component, reset for second component */
742 } else if(length
>0) {
743 /* true length is the length of just the component we got. */
744 length
=haveLang
?langLen
:restLen
;
745 if(dest
&& sub0Pos
!=0) {
746 if (sub0Pos
+length
<=destCapacity
) {
747 /* first component not at start of result,
748 but we have full component in buffer. */
749 u_memmove(dest
, dest
+(haveLang
?langPos
:restPos
), length
);
751 /* would have fit, but didn't because of pattern prefix. */
752 sub0Pos
=0; /* stops initial padding (and a second retry,
753 so we won't end up here again) */
759 ++subi
; /* move on to next substitution */
764 return u_terminateUChars(dest
, destCapacity
, length
, pErrorCode
);
767 U_CAPI
int32_t U_EXPORT2
768 uloc_getDisplayKeyword(const char* keyword
,
769 const char* displayLocale
,
771 int32_t destCapacity
,
774 /* argument checking */
775 if(status
==NULL
|| U_FAILURE(*status
)) {
779 if(destCapacity
<0 || (destCapacity
>0 && dest
==NULL
)) {
780 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
785 /* pass itemKey=NULL to look for a top-level item */
786 return _getStringOrCopyKey(U_ICUDATA_LANG
, displayLocale
,
796 #define UCURRENCY_DISPLAY_NAME_INDEX 1
798 U_CAPI
int32_t U_EXPORT2
799 uloc_getDisplayKeywordValue( const char* locale
,
801 const char* displayLocale
,
803 int32_t destCapacity
,
807 char keywordValue
[ULOC_FULLNAME_CAPACITY
*4];
808 int32_t capacity
= ULOC_FULLNAME_CAPACITY
*4;
809 int32_t keywordValueLen
=0;
811 /* argument checking */
812 if(status
==NULL
|| U_FAILURE(*status
)) {
816 if(destCapacity
<0 || (destCapacity
>0 && dest
==NULL
)) {
817 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
821 /* get the keyword value */
823 keywordValueLen
= uloc_getKeywordValue(locale
, keyword
, keywordValue
, capacity
, status
);
824 if (*status
== U_STRING_NOT_TERMINATED_WARNING
)
825 *status
= U_BUFFER_OVERFLOW_ERROR
;
828 * if the keyword is equal to currency .. then to get the display name
829 * we need to do the fallback ourselves
831 if(uprv_stricmp(keyword
, _kCurrency
)==0){
833 int32_t dispNameLen
= 0;
834 const UChar
*dispName
= NULL
;
836 UResourceBundle
*bundle
= ures_open(U_ICUDATA_CURR
, displayLocale
, status
);
837 UResourceBundle
*currencies
= ures_getByKey(bundle
, _kCurrencies
, NULL
, status
);
838 UResourceBundle
*currency
= ures_getByKeyWithFallback(currencies
, keywordValue
, NULL
, status
);
840 dispName
= ures_getStringByIndex(currency
, UCURRENCY_DISPLAY_NAME_INDEX
, &dispNameLen
, status
);
842 /*close the bundles */
843 ures_close(currency
);
844 ures_close(currencies
);
847 if(U_FAILURE(*status
)){
848 if(*status
== U_MISSING_RESOURCE_ERROR
){
849 /* we just want to write the value over if nothing is available */
850 *status
= U_USING_DEFAULT_WARNING
;
856 /* now copy the dispName over if not NULL */
857 if(dispName
!= NULL
){
858 if(dispNameLen
<= destCapacity
){
859 u_memcpy(dest
, dispName
, dispNameLen
);
860 return u_terminateUChars(dest
, destCapacity
, dispNameLen
, status
);
862 *status
= U_BUFFER_OVERFLOW_ERROR
;
866 /* we have not found the display name for the value .. just copy over */
867 if(keywordValueLen
<= destCapacity
){
868 u_charsToUChars(keywordValue
, dest
, keywordValueLen
);
869 return u_terminateUChars(dest
, destCapacity
, keywordValueLen
, status
);
871 *status
= U_BUFFER_OVERFLOW_ERROR
;
872 return keywordValueLen
;
879 return _getStringOrCopyKey(U_ICUDATA_LANG
, displayLocale
,