• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 _kScriptsStandAlone[] = "Scripts%stand-alone";
281 static const char _kCountries[]       = "Countries";
282 static const char _kVariants[]        = "Variants";
283 static const char _kKeys[]            = "Keys";
284 static const char _kTypes[]           = "Types";
285 //static const char _kRootName[]        = "root";
286 static const char _kCurrency[]        = "currency";
287 static const char _kCurrencies[]      = "Currencies";
288 static const char _kLocaleDisplayPattern[] = "localeDisplayPattern";
289 static const char _kPattern[]         = "pattern";
290 static const char _kSeparator[]       = "separator";
291 
292 /* ### Display name **************************************************/
293 
294 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)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 
346 typedef  int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *);
347 
348 static int32_t
_getDisplayNameForComponent(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UDisplayNameGetter * getter,const char * tag,UErrorCode * pErrorCode)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 
389 U_CAPI int32_t U_EXPORT2
uloc_getDisplayLanguage(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)390 uloc_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 
398 U_CAPI int32_t U_EXPORT2
uloc_getDisplayScript(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)399 uloc_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 
417 U_INTERNAL int32_t U_EXPORT2
uloc_getDisplayScriptInContext(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)418 uloc_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 
427 U_CAPI int32_t U_EXPORT2
uloc_getDisplayCountry(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)428 uloc_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  */
441 U_CAPI int32_t U_EXPORT2
uloc_getDisplayVariant(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)442 uloc_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  */
462 U_CAPI int32_t U_EXPORT2
uloc_getDisplayName(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)463 uloc_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 
765 U_CAPI int32_t U_EXPORT2
uloc_getDisplayKeyword(const char * keyword,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * status)766 uloc_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 
796 U_CAPI int32_t U_EXPORT2
uloc_getDisplayKeywordValue(const char * locale,const char * keyword,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * status)797 uloc_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