1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 1997-2010, International Business Machines
5 * Corporation and others. All Rights Reserved.
6 *
7 *******************************************************************************
8 * file name: locdispnames.cpp
9 * encoding: US-ASCII
10 * tab size: 8 (not used)
11 * indentation:4
12 *
13 * created on: 2010feb25
14 * created by: Markus W. Scherer
15 *
16 * Code for locale display names, separated out from other .cpp files
17 * that then do not depend on resource bundle code and display name data.
18 */
19
20 #include "unicode/utypes.h"
21 #include "unicode/brkiter.h"
22 #include "unicode/locid.h"
23 #include "unicode/uloc.h"
24 #include "unicode/ures.h"
25 #include "unicode/ustring.h"
26 #include "cmemory.h"
27 #include "cstring.h"
28 #include "putilimp.h"
29 #include "ulocimp.h"
30 #include "uresimp.h"
31 #include "ureslocs.h"
32 #include "ustr_imp.h"
33
34 // C++ API ----------------------------------------------------------------- ***
35
36 U_NAMESPACE_BEGIN
37
38 UnicodeString&
getDisplayLanguage(UnicodeString & dispLang) const39 Locale::getDisplayLanguage(UnicodeString& dispLang) const
40 {
41 return this->getDisplayLanguage(getDefault(), dispLang);
42 }
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
50 UnicodeString&
getDisplayLanguage(const Locale & displayLocale,UnicodeString & result) const51 Locale::getDisplayLanguage(const Locale &displayLocale,
52 UnicodeString &result) const {
53 UChar *buffer;
54 UErrorCode errorCode=U_ZERO_ERROR;
55 int32_t length;
56
57 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
58 if(buffer==0) {
59 result.truncate(0);
60 return result;
61 }
62
63 length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
64 buffer, result.getCapacity(),
65 &errorCode);
66 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
67
68 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
69 buffer=result.getBuffer(length);
70 if(buffer==0) {
71 result.truncate(0);
72 return result;
73 }
74 errorCode=U_ZERO_ERROR;
75 length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
76 buffer, result.getCapacity(),
77 &errorCode);
78 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
79 }
80
81 return result;
82 }
83
84 UnicodeString&
getDisplayScript(UnicodeString & dispScript) const85 Locale::getDisplayScript(UnicodeString& dispScript) const
86 {
87 return this->getDisplayScript(getDefault(), dispScript);
88 }
89
90 UnicodeString&
getDisplayScript(const Locale & displayLocale,UnicodeString & result) const91 Locale::getDisplayScript(const Locale &displayLocale,
92 UnicodeString &result) const {
93 UChar *buffer;
94 UErrorCode errorCode=U_ZERO_ERROR;
95 int32_t length;
96
97 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
98 if(buffer==0) {
99 result.truncate(0);
100 return result;
101 }
102
103 length=uloc_getDisplayScript(fullName, displayLocale.fullName,
104 buffer, result.getCapacity(),
105 &errorCode);
106 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
107
108 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
109 buffer=result.getBuffer(length);
110 if(buffer==0) {
111 result.truncate(0);
112 return result;
113 }
114 errorCode=U_ZERO_ERROR;
115 length=uloc_getDisplayScript(fullName, displayLocale.fullName,
116 buffer, result.getCapacity(),
117 &errorCode);
118 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
119 }
120
121 return result;
122 }
123
124 UnicodeString&
getDisplayCountry(UnicodeString & dispCntry) const125 Locale::getDisplayCountry(UnicodeString& dispCntry) const
126 {
127 return this->getDisplayCountry(getDefault(), dispCntry);
128 }
129
130 UnicodeString&
getDisplayCountry(const Locale & displayLocale,UnicodeString & result) const131 Locale::getDisplayCountry(const Locale &displayLocale,
132 UnicodeString &result) const {
133 UChar *buffer;
134 UErrorCode errorCode=U_ZERO_ERROR;
135 int32_t length;
136
137 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
138 if(buffer==0) {
139 result.truncate(0);
140 return result;
141 }
142
143 length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
144 buffer, result.getCapacity(),
145 &errorCode);
146 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
147
148 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
149 buffer=result.getBuffer(length);
150 if(buffer==0) {
151 result.truncate(0);
152 return result;
153 }
154 errorCode=U_ZERO_ERROR;
155 length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
156 buffer, result.getCapacity(),
157 &errorCode);
158 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
159 }
160
161 return result;
162 }
163
164 UnicodeString&
getDisplayVariant(UnicodeString & dispVar) const165 Locale::getDisplayVariant(UnicodeString& dispVar) const
166 {
167 return this->getDisplayVariant(getDefault(), dispVar);
168 }
169
170 UnicodeString&
getDisplayVariant(const Locale & displayLocale,UnicodeString & result) const171 Locale::getDisplayVariant(const Locale &displayLocale,
172 UnicodeString &result) const {
173 UChar *buffer;
174 UErrorCode errorCode=U_ZERO_ERROR;
175 int32_t length;
176
177 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
178 if(buffer==0) {
179 result.truncate(0);
180 return result;
181 }
182
183 length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
184 buffer, result.getCapacity(),
185 &errorCode);
186 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
187
188 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
189 buffer=result.getBuffer(length);
190 if(buffer==0) {
191 result.truncate(0);
192 return result;
193 }
194 errorCode=U_ZERO_ERROR;
195 length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
196 buffer, result.getCapacity(),
197 &errorCode);
198 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
199 }
200
201 return result;
202 }
203
204 UnicodeString&
getDisplayName(UnicodeString & name) const205 Locale::getDisplayName( UnicodeString& name ) const
206 {
207 return this->getDisplayName(getDefault(), name);
208 }
209
210 UnicodeString&
getDisplayName(const Locale & displayLocale,UnicodeString & result) const211 Locale::getDisplayName(const Locale &displayLocale,
212 UnicodeString &result) const {
213 UChar *buffer;
214 UErrorCode errorCode=U_ZERO_ERROR;
215 int32_t length;
216
217 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
218 if(buffer==0) {
219 result.truncate(0);
220 return result;
221 }
222
223 length=uloc_getDisplayName(fullName, displayLocale.fullName,
224 buffer, result.getCapacity(),
225 &errorCode);
226 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
227
228 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
229 buffer=result.getBuffer(length);
230 if(buffer==0) {
231 result.truncate(0);
232 return result;
233 }
234 errorCode=U_ZERO_ERROR;
235 length=uloc_getDisplayName(fullName, displayLocale.fullName,
236 buffer, result.getCapacity(),
237 &errorCode);
238 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
239 }
240
241 return result;
242 }
243
244 #if ! UCONFIG_NO_BREAK_ITERATION
245
246 // -------------------------------------
247 // Gets the objectLocale display name in the default locale language.
248 UnicodeString& U_EXPORT2
getDisplayName(const Locale & objectLocale,UnicodeString & name)249 BreakIterator::getDisplayName(const Locale& objectLocale,
250 UnicodeString& name)
251 {
252 return objectLocale.getDisplayName(name);
253 }
254
255 // -------------------------------------
256 // Gets the objectLocale display name in the displayLocale language.
257 UnicodeString& U_EXPORT2
getDisplayName(const Locale & objectLocale,const Locale & displayLocale,UnicodeString & name)258 BreakIterator::getDisplayName(const Locale& objectLocale,
259 const Locale& displayLocale,
260 UnicodeString& name)
261 {
262 return objectLocale.getDisplayName(displayLocale, name);
263 }
264
265 #endif
266
267
268 U_NAMESPACE_END
269
270 // C API ------------------------------------------------------------------- ***
271
272 U_NAMESPACE_USE
273
274 /* ### Constants **************************************************/
275
276 /* These strings describe the resources we attempt to load from
277 the locale ResourceBundle data file.*/
278 static const char _kLanguages[] = "Languages";
279 static const char _kScripts[] = "Scripts";
280 static const char _kCountries[] = "Countries";
281 static const char _kVariants[] = "Variants";
282 static const char _kKeys[] = "Keys";
283 static const char _kTypes[] = "Types";
284 static const char _kRootName[] = "root";
285 static const char _kCurrency[] = "currency";
286 static const char _kCurrencies[] = "Currencies";
287 static const char _kLocaleDisplayPattern[] = "localeDisplayPattern";
288 static const char _kPattern[] = "pattern";
289 static const char _kSeparator[] = "separator";
290
291 /* ### Display name **************************************************/
292
293 static int32_t
_getStringOrCopyKey(const char * path,const char * locale,const char * tableKey,const char * subTableKey,const char * itemKey,const char * substitute,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)294 _getStringOrCopyKey(const char *path, const char *locale,
295 const char *tableKey,
296 const char* subTableKey,
297 const char *itemKey,
298 const char *substitute,
299 UChar *dest, int32_t destCapacity,
300 UErrorCode *pErrorCode) {
301 const UChar *s = NULL;
302 int32_t length = 0;
303
304 if(itemKey==NULL) {
305 /* top-level item: normal resource bundle access */
306 UResourceBundle *rb;
307
308 rb=ures_open(path, locale, pErrorCode);
309
310 if(U_SUCCESS(*pErrorCode)) {
311 s=ures_getStringByKey(rb, tableKey, &length, pErrorCode);
312 /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
313 ures_close(rb);
314 }
315 } else {
316 /* Language code should not be a number. If it is, set the error code. */
317 if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) {
318 *pErrorCode = U_MISSING_RESOURCE_ERROR;
319 } else {
320 /* second-level item, use special fallback */
321 s=uloc_getTableStringWithFallback(path, locale,
322 tableKey,
323 subTableKey,
324 itemKey,
325 &length,
326 pErrorCode);
327 }
328 }
329
330 if(U_SUCCESS(*pErrorCode)) {
331 int32_t copyLength=uprv_min(length, destCapacity);
332 if(copyLength>0 && s != NULL) {
333 u_memcpy(dest, s, copyLength);
334 }
335 } else {
336 /* no string from a resource bundle: convert the substitute */
337 length=(int32_t)uprv_strlen(substitute);
338 u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
339 *pErrorCode=U_USING_DEFAULT_WARNING;
340 }
341
342 return u_terminateUChars(dest, destCapacity, length, pErrorCode);
343 }
344
345 typedef int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *);
346
347 static int32_t
_getDisplayNameForComponent(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UDisplayNameGetter * getter,const char * tag,UErrorCode * pErrorCode)348 _getDisplayNameForComponent(const char *locale,
349 const char *displayLocale,
350 UChar *dest, int32_t destCapacity,
351 UDisplayNameGetter *getter,
352 const char *tag,
353 UErrorCode *pErrorCode) {
354 char localeBuffer[ULOC_FULLNAME_CAPACITY*4];
355 int32_t length;
356 UErrorCode localStatus;
357 const char* root = NULL;
358
359 /* argument checking */
360 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
361 return 0;
362 }
363
364 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
365 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
366 return 0;
367 }
368
369 localStatus = U_ZERO_ERROR;
370 length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
371 if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
372 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
373 return 0;
374 }
375 if(length==0) {
376 return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
377 }
378
379 root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
380
381 return _getStringOrCopyKey(root, displayLocale,
382 tag, NULL, localeBuffer,
383 localeBuffer,
384 dest, destCapacity,
385 pErrorCode);
386 }
387
388 U_CAPI int32_t U_EXPORT2
uloc_getDisplayLanguage(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)389 uloc_getDisplayLanguage(const char *locale,
390 const char *displayLocale,
391 UChar *dest, int32_t destCapacity,
392 UErrorCode *pErrorCode) {
393 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
394 uloc_getLanguage, _kLanguages, pErrorCode);
395 }
396
397 U_CAPI int32_t U_EXPORT2
uloc_getDisplayScript(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)398 uloc_getDisplayScript(const char* locale,
399 const char* displayLocale,
400 UChar *dest, int32_t destCapacity,
401 UErrorCode *pErrorCode)
402 {
403 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
404 uloc_getScript, _kScripts, pErrorCode);
405 }
406
407 U_CAPI int32_t U_EXPORT2
uloc_getDisplayCountry(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)408 uloc_getDisplayCountry(const char *locale,
409 const char *displayLocale,
410 UChar *dest, int32_t destCapacity,
411 UErrorCode *pErrorCode) {
412 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
413 uloc_getCountry, _kCountries, pErrorCode);
414 }
415
416 /*
417 * TODO separate variant1_variant2_variant3...
418 * by getting each tag's display string and concatenating them with ", "
419 * in between - similar to uloc_getDisplayName()
420 */
421 U_CAPI int32_t U_EXPORT2
uloc_getDisplayVariant(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)422 uloc_getDisplayVariant(const char *locale,
423 const char *displayLocale,
424 UChar *dest, int32_t destCapacity,
425 UErrorCode *pErrorCode) {
426 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
427 uloc_getVariant, _kVariants, pErrorCode);
428 }
429
430 U_CAPI int32_t U_EXPORT2
uloc_getDisplayName(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)431 uloc_getDisplayName(const char *locale,
432 const char *displayLocale,
433 UChar *dest, int32_t destCapacity,
434 UErrorCode *pErrorCode)
435 {
436 int32_t length, length2, length3 = 0;
437 UBool hasLanguage, hasScript, hasCountry, hasVariant, hasKeywords;
438 UEnumeration* keywordEnum = NULL;
439 int32_t keywordCount = 0;
440 const char *keyword = NULL;
441 int32_t keywordLen = 0;
442 char keywordValue[256];
443 int32_t keywordValueLen = 0;
444
445 int32_t locSepLen = 0;
446 int32_t locPatLen = 0;
447 int32_t p0Len = 0;
448 int32_t defaultPatternLen = 9;
449 const UChar *dispLocSeparator;
450 const UChar *dispLocPattern;
451 static const UChar defaultSeparator[3] = { 0x002c, 0x0020 , 0x0000 }; /* comma + space */
452 static const UChar defaultPattern[10] = { 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000 }; /* {0} ({1}) */
453 static const UChar pat0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
454 static const UChar pat1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
455
456 UResourceBundle *bundle = NULL;
457 UResourceBundle *locdsppat = NULL;
458
459 UErrorCode status = U_ZERO_ERROR;
460
461 /* argument checking */
462 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
463 return 0;
464 }
465
466 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
467 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
468 return 0;
469 }
470
471 bundle = ures_open(U_ICUDATA_LANG, displayLocale, &status);
472
473 locdsppat = ures_getByKeyWithFallback(bundle, _kLocaleDisplayPattern, NULL, &status);
474 dispLocSeparator = ures_getStringByKeyWithFallback(locdsppat, _kSeparator, &locSepLen, &status);
475 dispLocPattern = ures_getStringByKeyWithFallback(locdsppat, _kPattern, &locPatLen, &status);
476
477 /*close the bundles */
478 ures_close(locdsppat);
479 ures_close(bundle);
480
481 /* If we couldn't find any data, then use the defaults */
482 if ( locSepLen == 0) {
483 dispLocSeparator = defaultSeparator;
484 locSepLen = 2;
485 }
486
487 if ( locPatLen == 0) {
488 dispLocPattern = defaultPattern;
489 locPatLen = 9;
490 }
491
492 /*
493 * if there is a language, then write "language (country, variant)"
494 * otherwise write "country, variant"
495 */
496
497 /* write the language */
498 length=uloc_getDisplayLanguage(locale, displayLocale,
499 dest, destCapacity,
500 pErrorCode);
501 hasLanguage= length>0;
502
503 if(hasLanguage) {
504 p0Len = length;
505
506 /* append " (" */
507 if(length<destCapacity) {
508 dest[length]=0x20;
509 }
510 ++length;
511 if(length<destCapacity) {
512 dest[length]=0x28;
513 }
514 ++length;
515 }
516
517 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
518 /* keep preflighting */
519 *pErrorCode=U_ZERO_ERROR;
520 }
521
522 /* append the script */
523 if(length<destCapacity) {
524 length2=uloc_getDisplayScript(locale, displayLocale,
525 dest+length, destCapacity-length,
526 pErrorCode);
527 } else {
528 length2=uloc_getDisplayScript(locale, displayLocale,
529 NULL, 0,
530 pErrorCode);
531 }
532 hasScript= length2>0;
533 length+=length2;
534
535 if(hasScript) {
536 /* append separator */
537 if(length+locSepLen<=destCapacity) {
538 u_memcpy(dest+length,dispLocSeparator,locSepLen);
539 }
540 length+=locSepLen;
541 }
542
543 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
544 /* keep preflighting */
545 *pErrorCode=U_ZERO_ERROR;
546 }
547
548 /* append the country */
549 if(length<destCapacity) {
550 length2=uloc_getDisplayCountry(locale, displayLocale,
551 dest+length, destCapacity-length,
552 pErrorCode);
553 } else {
554 length2=uloc_getDisplayCountry(locale, displayLocale,
555 NULL, 0,
556 pErrorCode);
557 }
558 hasCountry= length2>0;
559 length+=length2;
560
561 if(hasCountry) {
562 /* append separator */
563 if(length+locSepLen<=destCapacity) {
564 u_memcpy(dest+length,dispLocSeparator,locSepLen);
565 }
566 length+=locSepLen;
567 }
568
569 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
570 /* keep preflighting */
571 *pErrorCode=U_ZERO_ERROR;
572 }
573
574 /* append the variant */
575 if(length<destCapacity) {
576 length2=uloc_getDisplayVariant(locale, displayLocale,
577 dest+length, destCapacity-length,
578 pErrorCode);
579 } else {
580 length2=uloc_getDisplayVariant(locale, displayLocale,
581 NULL, 0,
582 pErrorCode);
583 }
584 hasVariant= length2>0;
585 length+=length2;
586
587 if(hasVariant) {
588 /* append separator */
589 if(length+locSepLen<=destCapacity) {
590 u_memcpy(dest+length,dispLocSeparator,locSepLen);
591 }
592 length+=locSepLen;
593 }
594
595 keywordEnum = uloc_openKeywords(locale, pErrorCode);
596
597 for(keywordCount = uenum_count(keywordEnum, pErrorCode); keywordCount > 0 ; keywordCount--){
598 if(U_FAILURE(*pErrorCode)){
599 break;
600 }
601 /* the uenum_next returns NUL terminated string */
602 keyword = uenum_next(keywordEnum, &keywordLen, pErrorCode);
603 if(length + length3 < destCapacity) {
604 length3 += uloc_getDisplayKeyword(keyword, displayLocale, dest+length+length3, destCapacity-length-length3, pErrorCode);
605 } else {
606 length3 += uloc_getDisplayKeyword(keyword, displayLocale, NULL, 0, pErrorCode);
607 }
608 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
609 /* keep preflighting */
610 *pErrorCode=U_ZERO_ERROR;
611 }
612 keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, 256, pErrorCode);
613 if(keywordValueLen) {
614 if(length + length3 < destCapacity) {
615 dest[length + length3] = 0x3D;
616 }
617 length3++;
618 if(length + length3 < destCapacity) {
619 length3 += uloc_getDisplayKeywordValue(locale, keyword, displayLocale, dest+length+length3, destCapacity-length-length3, pErrorCode);
620 } else {
621 length3 += uloc_getDisplayKeywordValue(locale, keyword, displayLocale, NULL, 0, pErrorCode);
622 }
623 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
624 /* keep preflighting */
625 *pErrorCode=U_ZERO_ERROR;
626 }
627 }
628 if(keywordCount > 1) {
629 if(length + length3 + locSepLen <= destCapacity && keywordCount) {
630 u_memcpy(dest+length+length3,dispLocSeparator,locSepLen);
631 length3+=locSepLen;
632 }
633 }
634 }
635 uenum_close(keywordEnum);
636
637 hasKeywords = length3 > 0;
638 length += length3;
639
640
641 if ((hasScript && !hasCountry)
642 || ((hasScript || hasCountry) && !hasVariant && !hasKeywords)
643 || ((hasScript || hasCountry || hasVariant) && !hasKeywords)) {
644 /* Remove separator */
645 length -= locSepLen;
646 } else if (hasLanguage && !hasScript && !hasCountry && !hasVariant && !hasKeywords) {
647 /* Remove " (" */
648 length-=2;
649 }
650
651 if (hasLanguage && (hasScript || hasCountry || hasVariant || hasKeywords)) {
652 /* append ")" */
653 if(length<destCapacity) {
654 dest[length]=0x29;
655 }
656 ++length;
657
658 /* If the localized display pattern is something other than the default pattern of "{0} ({1})", then
659 * then we need to do the formatting here. It would be easier to use a messageFormat to do this, but we
660 * can't since we don't have the APIs in the i18n library available to us at this point.
661 */
662 if (locPatLen != defaultPatternLen || u_strcmp(dispLocPattern,defaultPattern)) { /* Something other than the default pattern */
663 UChar *p0 = u_strstr(dispLocPattern,pat0);
664 UChar *p1 = u_strstr(dispLocPattern,pat1);
665 u_terminateUChars(dest, destCapacity, length, pErrorCode);
666
667 if ( p0 != NULL && p1 != NULL ) { /* The pattern is well formed */
668 if ( dest ) {
669 int32_t destLen = 0;
670 UChar *result = (UChar *)uprv_malloc((length+1)*sizeof(UChar));
671 UChar *upos = (UChar *)dispLocPattern;
672 u_strcpy(result,dest);
673 dest[0] = 0;
674 while ( *upos ) {
675 if ( upos == p0 ) { /* Handle {0} substitution */
676 u_strncat(dest,result,p0Len);
677 destLen += p0Len;
678 dest[destLen] = 0; /* Null terminate */
679 upos += 3;
680 } else if ( upos == p1 ) { /* Handle {1} substitution */
681 UChar *p1Start = &result[p0Len+2];
682 u_strncat(dest,p1Start,length-p0Len-3);
683 destLen += (length-p0Len-3);
684 dest[destLen] = 0; /* Null terminate */
685 upos += 3;
686 } else { /* Something from the pattern not {0} or {1} */
687 u_strncat(dest,upos,1);
688 upos++;
689 destLen++;
690 dest[destLen] = 0; /* Null terminate */
691 }
692 }
693 length = destLen;
694 uprv_free(result);
695 }
696 }
697 }
698 }
699 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
700 /* keep preflighting */
701 *pErrorCode=U_ZERO_ERROR;
702 }
703
704 return u_terminateUChars(dest, destCapacity, length, pErrorCode);
705 }
706
707 U_CAPI int32_t U_EXPORT2
uloc_getDisplayKeyword(const char * keyword,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * status)708 uloc_getDisplayKeyword(const char* keyword,
709 const char* displayLocale,
710 UChar* dest,
711 int32_t destCapacity,
712 UErrorCode* status){
713
714 /* argument checking */
715 if(status==NULL || U_FAILURE(*status)) {
716 return 0;
717 }
718
719 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
720 *status=U_ILLEGAL_ARGUMENT_ERROR;
721 return 0;
722 }
723
724
725 /* pass itemKey=NULL to look for a top-level item */
726 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
727 _kKeys, NULL,
728 keyword,
729 keyword,
730 dest, destCapacity,
731 status);
732
733 }
734
735
736 #define UCURRENCY_DISPLAY_NAME_INDEX 1
737
738 U_CAPI int32_t U_EXPORT2
uloc_getDisplayKeywordValue(const char * locale,const char * keyword,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * status)739 uloc_getDisplayKeywordValue( const char* locale,
740 const char* keyword,
741 const char* displayLocale,
742 UChar* dest,
743 int32_t destCapacity,
744 UErrorCode* status){
745
746
747 char keywordValue[ULOC_FULLNAME_CAPACITY*4];
748 int32_t capacity = ULOC_FULLNAME_CAPACITY*4;
749 int32_t keywordValueLen =0;
750
751 /* argument checking */
752 if(status==NULL || U_FAILURE(*status)) {
753 return 0;
754 }
755
756 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
757 *status=U_ILLEGAL_ARGUMENT_ERROR;
758 return 0;
759 }
760
761 /* get the keyword value */
762 keywordValue[0]=0;
763 keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status);
764
765 /*
766 * if the keyword is equal to currency .. then to get the display name
767 * we need to do the fallback ourselves
768 */
769 if(uprv_stricmp(keyword, _kCurrency)==0){
770
771 int32_t dispNameLen = 0;
772 const UChar *dispName = NULL;
773
774 UResourceBundle *bundle = ures_open(U_ICUDATA_CURR, displayLocale, status);
775 UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status);
776 UResourceBundle *currency = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status);
777
778 dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
779
780 /*close the bundles */
781 ures_close(currency);
782 ures_close(currencies);
783 ures_close(bundle);
784
785 if(U_FAILURE(*status)){
786 if(*status == U_MISSING_RESOURCE_ERROR){
787 /* we just want to write the value over if nothing is available */
788 *status = U_USING_DEFAULT_WARNING;
789 }else{
790 return 0;
791 }
792 }
793
794 /* now copy the dispName over if not NULL */
795 if(dispName != NULL){
796 if(dispNameLen <= destCapacity){
797 uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR);
798 return u_terminateUChars(dest, destCapacity, dispNameLen, status);
799 }else{
800 *status = U_BUFFER_OVERFLOW_ERROR;
801 return dispNameLen;
802 }
803 }else{
804 /* we have not found the display name for the value .. just copy over */
805 if(keywordValueLen <= destCapacity){
806 u_charsToUChars(keywordValue, dest, keywordValueLen);
807 return u_terminateUChars(dest, destCapacity, keywordValueLen, status);
808 }else{
809 *status = U_BUFFER_OVERFLOW_ERROR;
810 return keywordValueLen;
811 }
812 }
813
814
815 }else{
816
817 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
818 _kTypes, keyword,
819 keywordValue,
820 keywordValue,
821 dest, destCapacity,
822 status);
823 }
824 }
825