1/*
2*******************************************************************************
3*
4*   Copyright (C) 1997-2013, 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 _kScriptsStandAlone[] = "Scripts%stand-alone";
281static const char _kCountries[]       = "Countries";
282static const char _kVariants[]        = "Variants";
283static const char _kKeys[]            = "Keys";
284static const char _kTypes[]           = "Types";
285//static const char _kRootName[]        = "root";
286static const char _kCurrency[]        = "currency";
287static const char _kCurrencies[]      = "Currencies";
288static const char _kLocaleDisplayPattern[] = "localeDisplayPattern";
289static const char _kPattern[]         = "pattern";
290static const char _kSeparator[]       = "separator";
291
292/* ### Display name **************************************************/
293
294static int32_t
295_getStringOrCopyKey(const char *path, const char *locale,
296                    const char *tableKey,
297                    const char* subTableKey,
298                    const char *itemKey,
299                    const char *substitute,
300                    UChar *dest, int32_t destCapacity,
301                    UErrorCode *pErrorCode) {
302    const UChar *s = NULL;
303    int32_t length = 0;
304
305    if(itemKey==NULL) {
306        /* top-level item: normal resource bundle access */
307        UResourceBundle *rb;
308
309        rb=ures_open(path, locale, pErrorCode);
310
311        if(U_SUCCESS(*pErrorCode)) {
312            s=ures_getStringByKey(rb, tableKey, &length, pErrorCode);
313            /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
314            ures_close(rb);
315        }
316    } else {
317        /* Language code should not be a number. If it is, set the error code. */
318        if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) {
319            *pErrorCode = U_MISSING_RESOURCE_ERROR;
320        } else {
321            /* second-level item, use special fallback */
322            s=uloc_getTableStringWithFallback(path, locale,
323                                               tableKey,
324                                               subTableKey,
325                                               itemKey,
326                                               &length,
327                                               pErrorCode);
328        }
329    }
330
331    if(U_SUCCESS(*pErrorCode)) {
332        int32_t copyLength=uprv_min(length, destCapacity);
333        if(copyLength>0 && s != NULL) {
334            u_memcpy(dest, s, copyLength);
335        }
336    } else {
337        /* no string from a resource bundle: convert the substitute */
338        length=(int32_t)uprv_strlen(substitute);
339        u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
340        *pErrorCode=U_USING_DEFAULT_WARNING;
341    }
342
343    return u_terminateUChars(dest, destCapacity, length, pErrorCode);
344}
345
346typedef  int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *);
347
348static int32_t
349_getDisplayNameForComponent(const char *locale,
350                            const char *displayLocale,
351                            UChar *dest, int32_t destCapacity,
352                            UDisplayNameGetter *getter,
353                            const char *tag,
354                            UErrorCode *pErrorCode) {
355    char localeBuffer[ULOC_FULLNAME_CAPACITY*4];
356    int32_t length;
357    UErrorCode localStatus;
358    const char* root = NULL;
359
360    /* argument checking */
361    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
362        return 0;
363    }
364
365    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
366        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
367        return 0;
368    }
369
370    localStatus = U_ZERO_ERROR;
371    length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
372    if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
373        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
374        return 0;
375    }
376    if(length==0) {
377        return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
378    }
379
380    root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
381
382    return _getStringOrCopyKey(root, displayLocale,
383                               tag, NULL, localeBuffer,
384                               localeBuffer,
385                               dest, destCapacity,
386                               pErrorCode);
387}
388
389U_CAPI int32_t U_EXPORT2
390uloc_getDisplayLanguage(const char *locale,
391                        const char *displayLocale,
392                        UChar *dest, int32_t destCapacity,
393                        UErrorCode *pErrorCode) {
394    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
395                uloc_getLanguage, _kLanguages, pErrorCode);
396}
397
398U_CAPI int32_t U_EXPORT2
399uloc_getDisplayScript(const char* locale,
400                      const char* displayLocale,
401                      UChar *dest, int32_t destCapacity,
402                      UErrorCode *pErrorCode)
403{
404	UErrorCode err = U_ZERO_ERROR;
405	int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
406                uloc_getScript, _kScriptsStandAlone, &err);
407
408	if ( err == U_USING_DEFAULT_WARNING ) {
409        return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
410                    uloc_getScript, _kScripts, pErrorCode);
411	} else {
412		*pErrorCode = err;
413		return res;
414	}
415}
416
417U_INTERNAL int32_t U_EXPORT2
418uloc_getDisplayScriptInContext(const char* locale,
419                      const char* displayLocale,
420                      UChar *dest, int32_t destCapacity,
421                      UErrorCode *pErrorCode)
422{
423    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
424                    uloc_getScript, _kScripts, pErrorCode);
425}
426
427U_CAPI int32_t U_EXPORT2
428uloc_getDisplayCountry(const char *locale,
429                       const char *displayLocale,
430                       UChar *dest, int32_t destCapacity,
431                       UErrorCode *pErrorCode) {
432    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
433                uloc_getCountry, _kCountries, pErrorCode);
434}
435
436/*
437 * TODO separate variant1_variant2_variant3...
438 * by getting each tag's display string and concatenating them with ", "
439 * in between - similar to uloc_getDisplayName()
440 */
441U_CAPI int32_t U_EXPORT2
442uloc_getDisplayVariant(const char *locale,
443                       const char *displayLocale,
444                       UChar *dest, int32_t destCapacity,
445                       UErrorCode *pErrorCode) {
446    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
447                uloc_getVariant, _kVariants, pErrorCode);
448}
449
450/* Instead of having a separate pass for 'special' patterns, reintegrate the two
451 * so we don't get bitten by preflight bugs again.  We can be reasonably efficient
452 * without two separate code paths, this code isn't that performance-critical.
453 *
454 * This code is general enough to deal with patterns that have a prefix or swap the
455 * language and remainder components, since we gave developers enough rope to do such
456 * things if they futz with the pattern data.  But since we don't give them a way to
457 * specify a pattern for arbitrary combinations of components, there's not much use in
458 * that.  I don't think our data includes such patterns, the only variable I know if is
459 * whether there is a space before the open paren, or not.  Oh, and zh uses different
460 * chars than the standard open/close paren (which ja and ko use, btw).
461 */
462U_CAPI int32_t U_EXPORT2
463uloc_getDisplayName(const char *locale,
464                    const char *displayLocale,
465                    UChar *dest, int32_t destCapacity,
466                    UErrorCode *pErrorCode)
467{
468    static const UChar defaultSeparator[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */
469    static const UChar sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
470    static const UChar sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
471    static const int32_t subLen = 3;
472    static const UChar defaultPattern[10] = {
473        0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000
474    }; /* {0} ({1}) */
475    static const int32_t defaultPatLen = 9;
476    static const int32_t defaultSub0Pos = 0;
477    static const int32_t defaultSub1Pos = 5;
478
479    int32_t length; /* of formatted result */
480
481    const UChar *separator;
482    int32_t sepLen = 0;
483    const UChar *pattern;
484    int32_t patLen = 0;
485    int32_t sub0Pos, sub1Pos;
486
487    UChar formatOpenParen         = 0x0028; // (
488    UChar formatReplaceOpenParen  = 0x005B; // [
489    UChar formatCloseParen        = 0x0029; // )
490    UChar formatReplaceCloseParen = 0x005D; // ]
491
492    UBool haveLang = TRUE; /* assume true, set false if we find we don't have
493                              a lang component in the locale */
494    UBool haveRest = TRUE; /* assume true, set false if we find we don't have
495                              any other component in the locale */
496    UBool retry = FALSE; /* set true if we need to retry, see below */
497
498    int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */
499
500    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
501        return 0;
502    }
503
504    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
505        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
506        return 0;
507    }
508
509    {
510        UErrorCode status = U_ZERO_ERROR;
511        UResourceBundle* locbundle=ures_open(U_ICUDATA_LANG, displayLocale, &status);
512        UResourceBundle* dspbundle=ures_getByKeyWithFallback(locbundle, _kLocaleDisplayPattern,
513                                                             NULL, &status);
514
515        separator=ures_getStringByKeyWithFallback(dspbundle, _kSeparator, &sepLen, &status);
516        pattern=ures_getStringByKeyWithFallback(dspbundle, _kPattern, &patLen, &status);
517
518        ures_close(dspbundle);
519        ures_close(locbundle);
520    }
521
522    /* If we couldn't find any data, then use the defaults */
523    if(sepLen == 0) {
524       separator = defaultSeparator;
525    }
526    /* #10244: Even though separator is now a pattern, it is awkward to handle it as such
527     * here since we are trying to build the display string in place in the dest buffer,
528     * and to handle it as a pattern would entail having separate storage for the
529     * substrings that need to be combined (the first of which may be the result of
530     * previous such combinations). So for now we continue to treat the portion between
531     * {0} and {1} as a string to be appended when joining substrings, ignoring anything
532     * that is before {0} or after {1} (no existing separator pattern has any such thing).
533     * This is similar to how pattern is handled below.
534     */
535    {
536        UChar *p0=u_strstr(separator, sub0);
537        UChar *p1=u_strstr(separator, sub1);
538        if (p0==NULL || p1==NULL || p1<p0) {
539            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
540            return 0;
541        }
542        separator = (const UChar *)p0 + subLen;
543        sepLen = p1 - separator;
544    }
545
546    if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) {
547        pattern=defaultPattern;
548        patLen=defaultPatLen;
549        sub0Pos=defaultSub0Pos;
550        sub1Pos=defaultSub1Pos;
551        // use default formatOpenParen etc. set above
552    } else { /* non-default pattern */
553        UChar *p0=u_strstr(pattern, sub0);
554        UChar *p1=u_strstr(pattern, sub1);
555        if (p0==NULL || p1==NULL) {
556            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
557            return 0;
558        }
559        sub0Pos=p0-pattern;
560        sub1Pos=p1-pattern;
561        if (sub1Pos < sub0Pos) { /* a very odd pattern */
562            int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t;
563            langi=1;
564        }
565        if (u_strchr(pattern, 0xFF08) != NULL) {
566            formatOpenParen         = 0xFF08; // fullwidth (
567            formatReplaceOpenParen  = 0xFF3B; // fullwidth [
568            formatCloseParen        = 0xFF09; // fullwidth )
569            formatReplaceCloseParen = 0xFF3D; // fullwidth ]
570        }
571    }
572
573    /* We loop here because there is one case in which after the first pass we could need to
574     * reextract the data.  If there's initial padding before the first element, we put in
575     * the padding and then write that element.  If it turns out there's no second element,
576     * we didn't need the padding.  If we do need the data (no preflight), and the first element
577     * would have fit but for the padding, we need to reextract.  In this case (only) we
578     * adjust the parameters so padding is not added, and repeat.
579     */
580    do {
581        UChar* p=dest;
582        int32_t patPos=0; /* position in the pattern, used for non-substitution portions */
583        int32_t langLen=0; /* length of language substitution */
584        int32_t langPos=0; /* position in output of language substitution */
585        int32_t restLen=0; /* length of 'everything else' substitution */
586        int32_t restPos=0; /* position in output of 'everything else' substitution */
587        UEnumeration* kenum = NULL; /* keyword enumeration */
588
589        /* prefix of pattern, extremely likely to be empty */
590        if(sub0Pos) {
591            if(destCapacity >= sub0Pos) {
592                while (patPos < sub0Pos) {
593                    *p++ = pattern[patPos++];
594                }
595            } else {
596                patPos=sub0Pos;
597            }
598            length=sub0Pos;
599        } else {
600            length=0;
601        }
602
603        for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/
604            UBool subdone = FALSE; /* set true when ready to move to next substitution */
605
606            /* prep p and cap for calls to get display components, pin cap to 0 since
607               they complain if cap is negative */
608            int32_t cap=destCapacity-length;
609            if (cap <= 0) {
610                cap=0;
611            } else {
612                p=dest+length;
613            }
614
615            if (subi == langi) { /* {0}*/
616                if(haveLang) {
617                    langPos=length;
618                    langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode);
619                    length+=langLen;
620                    haveLang=langLen>0;
621                }
622                subdone=TRUE;
623            } else { /* {1} */
624                if(!haveRest) {
625                    subdone=TRUE;
626                } else {
627                    int32_t len; /* length of component (plus other stuff) we just fetched */
628                    switch(resti++) {
629                        case 0:
630                            restPos=length;
631                            len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode);
632                            break;
633                        case 1:
634                            len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode);
635                            break;
636                        case 2:
637                            len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode);
638                            break;
639                        case 3:
640                            kenum = uloc_openKeywords(locale, pErrorCode);
641                            /* fall through */
642                        default: {
643                            const char* kw=uenum_next(kenum, &len, pErrorCode);
644                            if (kw == NULL) {
645                                uenum_close(kenum);
646                                len=0; /* mark that we didn't add a component */
647                                subdone=TRUE;
648                            } else {
649                                /* incorporating this behavior into the loop made it even more complex,
650                                   so just special case it here */
651                                len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode);
652                                if(len) {
653                                    if(len < cap) {
654                                        p[len]=0x3d; /* '=', assume we'll need it */
655                                    }
656                                    len+=1;
657
658                                    /* adjust for call to get keyword */
659                                    cap-=len;
660                                    if(cap <= 0) {
661                                        cap=0;
662                                    } else {
663                                        p+=len;
664                                    }
665                                }
666                                /* reset for call below */
667                                if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
668                                    *pErrorCode=U_ZERO_ERROR;
669                                }
670                                int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale,
671                                                                           p, cap, pErrorCode);
672                                if(len) {
673                                    if(vlen==0) {
674                                        --len; /* remove unneeded '=' */
675                                    }
676                                    /* restore cap and p to what they were at start */
677                                    cap=destCapacity-length;
678                                    if(cap <= 0) {
679                                        cap=0;
680                                    } else {
681                                        p=dest+length;
682                                    }
683                                }
684                                len+=vlen; /* total we added for key + '=' + value */
685                            }
686                        } break;
687                    } /* end switch */
688
689                    if (len>0) {
690                        /* we addeed a component, so add separator and write it if there's room. */
691                        if(len+sepLen<=cap) {
692                            const UChar * plimit = p + len;
693                            for (; p < plimit; p++) {
694                                if (*p == formatOpenParen) {
695                                    *p = formatReplaceOpenParen;
696                                } else if (*p == formatCloseParen) {
697                                    *p = formatReplaceCloseParen;
698                                }
699                            }
700                            for(int32_t i=0;i<sepLen;++i) {
701                                *p++=separator[i];
702                            }
703                        }
704                        length+=len+sepLen;
705                    } else if(subdone) {
706                        /* remove separator if we added it */
707                        if (length!=restPos) {
708                            length-=sepLen;
709                        }
710                        restLen=length-restPos;
711                        haveRest=restLen>0;
712                    }
713                }
714            }
715
716            if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
717                *pErrorCode=U_ZERO_ERROR;
718            }
719
720            if(subdone) {
721                if(haveLang && haveRest) {
722                    /* append internal portion of pattern, the first time,
723                       or last portion of pattern the second time */
724                    int32_t padLen;
725                    patPos+=subLen;
726                    padLen=(subi==0 ? sub1Pos : patLen)-patPos;
727                    if(length+padLen < destCapacity) {
728                        p=dest+length;
729                        for(int32_t i=0;i<padLen;++i) {
730                            *p++=pattern[patPos++];
731                        }
732                    } else {
733                        patPos+=padLen;
734                    }
735                    length+=padLen;
736                } else if(subi==0) {
737                    /* don't have first component, reset for second component */
738                    sub0Pos=0;
739                    length=0;
740                } else if(length>0) {
741                    /* true length is the length of just the component we got. */
742                    length=haveLang?langLen:restLen;
743                    if(dest && sub0Pos!=0) {
744                        if (sub0Pos+length<=destCapacity) {
745                            /* first component not at start of result,
746                               but we have full component in buffer. */
747                            u_memmove(dest, dest+(haveLang?langPos:restPos), length);
748                        } else {
749                            /* would have fit, but didn't because of pattern prefix. */
750                            sub0Pos=0; /* stops initial padding (and a second retry,
751                                          so we won't end up here again) */
752                            retry=TRUE;
753                        }
754                    }
755                }
756
757                ++subi; /* move on to next substitution */
758            }
759        }
760    } while(retry);
761
762    return u_terminateUChars(dest, destCapacity, length, pErrorCode);
763}
764
765U_CAPI int32_t U_EXPORT2
766uloc_getDisplayKeyword(const char* keyword,
767                       const char* displayLocale,
768                       UChar* dest,
769                       int32_t destCapacity,
770                       UErrorCode* status){
771
772    /* argument checking */
773    if(status==NULL || U_FAILURE(*status)) {
774        return 0;
775    }
776
777    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
778        *status=U_ILLEGAL_ARGUMENT_ERROR;
779        return 0;
780    }
781
782
783    /* pass itemKey=NULL to look for a top-level item */
784    return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
785                               _kKeys, NULL,
786                               keyword,
787                               keyword,
788                               dest, destCapacity,
789                               status);
790
791}
792
793
794#define UCURRENCY_DISPLAY_NAME_INDEX 1
795
796U_CAPI int32_t U_EXPORT2
797uloc_getDisplayKeywordValue(   const char* locale,
798                               const char* keyword,
799                               const char* displayLocale,
800                               UChar* dest,
801                               int32_t destCapacity,
802                               UErrorCode* status){
803
804
805    char keywordValue[ULOC_FULLNAME_CAPACITY*4];
806    int32_t capacity = ULOC_FULLNAME_CAPACITY*4;
807    int32_t keywordValueLen =0;
808
809    /* argument checking */
810    if(status==NULL || U_FAILURE(*status)) {
811        return 0;
812    }
813
814    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
815        *status=U_ILLEGAL_ARGUMENT_ERROR;
816        return 0;
817    }
818
819    /* get the keyword value */
820    keywordValue[0]=0;
821    keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status);
822
823    /*
824     * if the keyword is equal to currency .. then to get the display name
825     * we need to do the fallback ourselves
826     */
827    if(uprv_stricmp(keyword, _kCurrency)==0){
828
829        int32_t dispNameLen = 0;
830        const UChar *dispName = NULL;
831
832        UResourceBundle *bundle     = ures_open(U_ICUDATA_CURR, displayLocale, status);
833        UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status);
834        UResourceBundle *currency   = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status);
835
836        dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
837
838        /*close the bundles */
839        ures_close(currency);
840        ures_close(currencies);
841        ures_close(bundle);
842
843        if(U_FAILURE(*status)){
844            if(*status == U_MISSING_RESOURCE_ERROR){
845                /* we just want to write the value over if nothing is available */
846                *status = U_USING_DEFAULT_WARNING;
847            }else{
848                return 0;
849            }
850        }
851
852        /* now copy the dispName over if not NULL */
853        if(dispName != NULL){
854            if(dispNameLen <= destCapacity){
855                uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR);
856                return u_terminateUChars(dest, destCapacity, dispNameLen, status);
857            }else{
858                *status = U_BUFFER_OVERFLOW_ERROR;
859                return dispNameLen;
860            }
861        }else{
862            /* we have not found the display name for the value .. just copy over */
863            if(keywordValueLen <= destCapacity){
864                u_charsToUChars(keywordValue, dest, keywordValueLen);
865                return u_terminateUChars(dest, destCapacity, keywordValueLen, status);
866            }else{
867                 *status = U_BUFFER_OVERFLOW_ERROR;
868                return keywordValueLen;
869            }
870        }
871
872
873    }else{
874
875        return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
876                                   _kTypes, keyword,
877                                   keywordValue,
878                                   keywordValue,
879                                   dest, destCapacity,
880                                   status);
881    }
882}
883