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
36U_NAMESPACE_BEGIN
37
38UnicodeString&
39Locale::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
50UnicodeString&
51Locale::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
84UnicodeString&
85Locale::getDisplayScript(UnicodeString& dispScript) const
86{
87    return this->getDisplayScript(getDefault(), dispScript);
88}
89
90UnicodeString&
91Locale::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
124UnicodeString&
125Locale::getDisplayCountry(UnicodeString& dispCntry) const
126{
127    return this->getDisplayCountry(getDefault(), dispCntry);
128}
129
130UnicodeString&
131Locale::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
164UnicodeString&
165Locale::getDisplayVariant(UnicodeString& dispVar) const
166{
167    return this->getDisplayVariant(getDefault(), dispVar);
168}
169
170UnicodeString&
171Locale::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
204UnicodeString&
205Locale::getDisplayName( UnicodeString& name ) const
206{
207    return this->getDisplayName(getDefault(), name);
208}
209
210UnicodeString&
211Locale::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.
248UnicodeString& U_EXPORT2
249BreakIterator::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.
257UnicodeString& U_EXPORT2
258BreakIterator::getDisplayName(const Locale& objectLocale,
259                             const Locale& displayLocale,
260                             UnicodeString& name)
261{
262    return objectLocale.getDisplayName(displayLocale, name);
263}
264
265#endif
266
267
268U_NAMESPACE_END
269
270// C API ------------------------------------------------------------------- ***
271
272U_NAMESPACE_USE
273
274/* ### Constants **************************************************/
275
276/* These strings describe the resources we attempt to load from
277 the locale ResourceBundle data file.*/
278static const char _kLanguages[]       = "Languages";
279static const char _kScripts[]         = "Scripts";
280static const char _kCountries[]       = "Countries";
281static const char _kVariants[]        = "Variants";
282static const char _kKeys[]            = "Keys";
283static const char _kTypes[]           = "Types";
284static const char _kRootName[]        = "root";
285static const char _kCurrency[]        = "currency";
286static const char _kCurrencies[]      = "Currencies";
287static const char _kLocaleDisplayPattern[] = "localeDisplayPattern";
288static const char _kPattern[]         = "pattern";
289static const char _kSeparator[]       = "separator";
290
291/* ### Display name **************************************************/
292
293static int32_t
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
345typedef  int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *);
346
347static int32_t
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
388U_CAPI int32_t U_EXPORT2
389uloc_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
397U_CAPI int32_t U_EXPORT2
398uloc_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
407U_CAPI int32_t U_EXPORT2
408uloc_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 */
421U_CAPI int32_t U_EXPORT2
422uloc_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
430U_CAPI int32_t U_EXPORT2
431uloc_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
707U_CAPI int32_t U_EXPORT2
708uloc_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
738U_CAPI int32_t U_EXPORT2
739uloc_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