• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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