1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 *
6 * Copyright (C) 1997-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
8 *
9 *******************************************************************************
10 * file name: locdispnames.cpp
11 * encoding: UTF-8
12 * tab size: 8 (not used)
13 * indentation:4
14 *
15 * created on: 2010feb25
16 * created by: Markus W. Scherer
17 *
18 * Code for locale display names, separated out from other .cpp files
19 * that then do not depend on resource bundle code and display name data.
20 */
21
22 #include "unicode/utypes.h"
23 #include "unicode/brkiter.h"
24 #include "unicode/locid.h"
25 #include "unicode/uloc.h"
26 #include "unicode/ures.h"
27 #include "unicode/ustring.h"
28 #include "cmemory.h"
29 #include "cstring.h"
30 #include "putilimp.h"
31 #include "ulocimp.h"
32 #include "uresimp.h"
33 #include "ureslocs.h"
34 #include "ustr_imp.h"
35
36 // C++ API ----------------------------------------------------------------- ***
37
38 U_NAMESPACE_BEGIN
39
40 UnicodeString&
getDisplayLanguage(UnicodeString & dispLang) const41 Locale::getDisplayLanguage(UnicodeString& dispLang) const
42 {
43 return this->getDisplayLanguage(getDefault(), dispLang);
44 }
45
46 /*We cannot make any assumptions on the size of the output display strings
47 * Yet, since we are calling through to a C API, we need to set limits on
48 * buffer size. For all the following getDisplay functions we first attempt
49 * to fill up a stack allocated buffer. If it is to small we heap allocated
50 * the exact buffer we need copy it to the UnicodeString and delete it*/
51
52 UnicodeString&
getDisplayLanguage(const Locale & displayLocale,UnicodeString & result) const53 Locale::getDisplayLanguage(const Locale &displayLocale,
54 UnicodeString &result) const {
55 UChar *buffer;
56 UErrorCode errorCode=U_ZERO_ERROR;
57 int32_t length;
58
59 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
60 if(buffer==0) {
61 result.truncate(0);
62 return result;
63 }
64
65 length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
66 buffer, result.getCapacity(),
67 &errorCode);
68 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
69
70 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
71 buffer=result.getBuffer(length);
72 if(buffer==0) {
73 result.truncate(0);
74 return result;
75 }
76 errorCode=U_ZERO_ERROR;
77 length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
78 buffer, result.getCapacity(),
79 &errorCode);
80 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
81 }
82
83 return result;
84 }
85
86 UnicodeString&
getDisplayScript(UnicodeString & dispScript) const87 Locale::getDisplayScript(UnicodeString& dispScript) const
88 {
89 return this->getDisplayScript(getDefault(), dispScript);
90 }
91
92 UnicodeString&
getDisplayScript(const Locale & displayLocale,UnicodeString & result) const93 Locale::getDisplayScript(const Locale &displayLocale,
94 UnicodeString &result) const {
95 UChar *buffer;
96 UErrorCode errorCode=U_ZERO_ERROR;
97 int32_t length;
98
99 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
100 if(buffer==0) {
101 result.truncate(0);
102 return result;
103 }
104
105 length=uloc_getDisplayScript(fullName, displayLocale.fullName,
106 buffer, result.getCapacity(),
107 &errorCode);
108 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
109
110 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
111 buffer=result.getBuffer(length);
112 if(buffer==0) {
113 result.truncate(0);
114 return result;
115 }
116 errorCode=U_ZERO_ERROR;
117 length=uloc_getDisplayScript(fullName, displayLocale.fullName,
118 buffer, result.getCapacity(),
119 &errorCode);
120 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
121 }
122
123 return result;
124 }
125
126 UnicodeString&
getDisplayCountry(UnicodeString & dispCntry) const127 Locale::getDisplayCountry(UnicodeString& dispCntry) const
128 {
129 return this->getDisplayCountry(getDefault(), dispCntry);
130 }
131
132 UnicodeString&
getDisplayCountry(const Locale & displayLocale,UnicodeString & result) const133 Locale::getDisplayCountry(const Locale &displayLocale,
134 UnicodeString &result) const {
135 UChar *buffer;
136 UErrorCode errorCode=U_ZERO_ERROR;
137 int32_t length;
138
139 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
140 if(buffer==0) {
141 result.truncate(0);
142 return result;
143 }
144
145 length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
146 buffer, result.getCapacity(),
147 &errorCode);
148 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
149
150 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
151 buffer=result.getBuffer(length);
152 if(buffer==0) {
153 result.truncate(0);
154 return result;
155 }
156 errorCode=U_ZERO_ERROR;
157 length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
158 buffer, result.getCapacity(),
159 &errorCode);
160 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
161 }
162
163 return result;
164 }
165
166 UnicodeString&
getDisplayVariant(UnicodeString & dispVar) const167 Locale::getDisplayVariant(UnicodeString& dispVar) const
168 {
169 return this->getDisplayVariant(getDefault(), dispVar);
170 }
171
172 UnicodeString&
getDisplayVariant(const Locale & displayLocale,UnicodeString & result) const173 Locale::getDisplayVariant(const Locale &displayLocale,
174 UnicodeString &result) const {
175 UChar *buffer;
176 UErrorCode errorCode=U_ZERO_ERROR;
177 int32_t length;
178
179 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
180 if(buffer==0) {
181 result.truncate(0);
182 return result;
183 }
184
185 length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
186 buffer, result.getCapacity(),
187 &errorCode);
188 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
189
190 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
191 buffer=result.getBuffer(length);
192 if(buffer==0) {
193 result.truncate(0);
194 return result;
195 }
196 errorCode=U_ZERO_ERROR;
197 length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
198 buffer, result.getCapacity(),
199 &errorCode);
200 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
201 }
202
203 return result;
204 }
205
206 UnicodeString&
getDisplayName(UnicodeString & name) const207 Locale::getDisplayName( UnicodeString& name ) const
208 {
209 return this->getDisplayName(getDefault(), name);
210 }
211
212 UnicodeString&
getDisplayName(const Locale & displayLocale,UnicodeString & result) const213 Locale::getDisplayName(const Locale &displayLocale,
214 UnicodeString &result) const {
215 UChar *buffer;
216 UErrorCode errorCode=U_ZERO_ERROR;
217 int32_t length;
218
219 buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
220 if(buffer==0) {
221 result.truncate(0);
222 return result;
223 }
224
225 length=uloc_getDisplayName(fullName, displayLocale.fullName,
226 buffer, result.getCapacity(),
227 &errorCode);
228 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
229
230 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
231 buffer=result.getBuffer(length);
232 if(buffer==0) {
233 result.truncate(0);
234 return result;
235 }
236 errorCode=U_ZERO_ERROR;
237 length=uloc_getDisplayName(fullName, displayLocale.fullName,
238 buffer, result.getCapacity(),
239 &errorCode);
240 result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
241 }
242
243 return result;
244 }
245
246 #if ! UCONFIG_NO_BREAK_ITERATION
247
248 // -------------------------------------
249 // Gets the objectLocale display name in the default locale language.
250 UnicodeString& U_EXPORT2
getDisplayName(const Locale & objectLocale,UnicodeString & name)251 BreakIterator::getDisplayName(const Locale& objectLocale,
252 UnicodeString& name)
253 {
254 return objectLocale.getDisplayName(name);
255 }
256
257 // -------------------------------------
258 // Gets the objectLocale display name in the displayLocale language.
259 UnicodeString& U_EXPORT2
getDisplayName(const Locale & objectLocale,const Locale & displayLocale,UnicodeString & name)260 BreakIterator::getDisplayName(const Locale& objectLocale,
261 const Locale& displayLocale,
262 UnicodeString& name)
263 {
264 return objectLocale.getDisplayName(displayLocale, name);
265 }
266
267 #endif
268
269
270 U_NAMESPACE_END
271
272 // C API ------------------------------------------------------------------- ***
273
274 U_NAMESPACE_USE
275
276 /* ### Constants **************************************************/
277
278 /* These strings describe the resources we attempt to load from
279 the locale ResourceBundle data file.*/
280 static const char _kLanguages[] = "Languages";
281 static const char _kScripts[] = "Scripts";
282 static const char _kScriptsStandAlone[] = "Scripts%stand-alone";
283 static const char _kCountries[] = "Countries";
284 static const char _kVariants[] = "Variants";
285 static const char _kKeys[] = "Keys";
286 static const char _kTypes[] = "Types";
287 //static const char _kRootName[] = "root";
288 static const char _kCurrency[] = "currency";
289 static const char _kCurrencies[] = "Currencies";
290 static const char _kLocaleDisplayPattern[] = "localeDisplayPattern";
291 static const char _kPattern[] = "pattern";
292 static const char _kSeparator[] = "separator";
293
294 /* ### Display name **************************************************/
295
296 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)297 _getStringOrCopyKey(const char *path, const char *locale,
298 const char *tableKey,
299 const char* subTableKey,
300 const char *itemKey,
301 const char *substitute,
302 UChar *dest, int32_t destCapacity,
303 UErrorCode *pErrorCode) {
304 const UChar *s = NULL;
305 int32_t length = 0;
306
307 if(itemKey==NULL) {
308 /* top-level item: normal resource bundle access */
309 UResourceBundle *rb;
310
311 rb=ures_open(path, locale, pErrorCode);
312
313 if(U_SUCCESS(*pErrorCode)) {
314 s=ures_getStringByKey(rb, tableKey, &length, pErrorCode);
315 /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
316 ures_close(rb);
317 }
318 } else {
319 /* Language code should not be a number. If it is, set the error code. */
320 if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) {
321 *pErrorCode = U_MISSING_RESOURCE_ERROR;
322 } else {
323 /* second-level item, use special fallback */
324 s=uloc_getTableStringWithFallback(path, locale,
325 tableKey,
326 subTableKey,
327 itemKey,
328 &length,
329 pErrorCode);
330 }
331 }
332
333 if(U_SUCCESS(*pErrorCode)) {
334 int32_t copyLength=uprv_min(length, destCapacity);
335 if(copyLength>0 && s != NULL) {
336 u_memcpy(dest, s, copyLength);
337 }
338 } else {
339 /* no string from a resource bundle: convert the substitute */
340 length=(int32_t)uprv_strlen(substitute);
341 u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
342 *pErrorCode=U_USING_DEFAULT_WARNING;
343 }
344
345 return u_terminateUChars(dest, destCapacity, length, pErrorCode);
346 }
347
348 typedef int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *);
349
350 static int32_t
_getDisplayNameForComponent(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UDisplayNameGetter * getter,const char * tag,UErrorCode * pErrorCode)351 _getDisplayNameForComponent(const char *locale,
352 const char *displayLocale,
353 UChar *dest, int32_t destCapacity,
354 UDisplayNameGetter *getter,
355 const char *tag,
356 UErrorCode *pErrorCode) {
357 char localeBuffer[ULOC_FULLNAME_CAPACITY*4];
358 int32_t length;
359 UErrorCode localStatus;
360 const char* root = NULL;
361
362 /* argument checking */
363 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
364 return 0;
365 }
366
367 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
368 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
369 return 0;
370 }
371
372 localStatus = U_ZERO_ERROR;
373 length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
374 if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
375 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
376 return 0;
377 }
378 if(length==0) {
379 return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
380 }
381
382 root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
383
384 return _getStringOrCopyKey(root, displayLocale,
385 tag, NULL, localeBuffer,
386 localeBuffer,
387 dest, destCapacity,
388 pErrorCode);
389 }
390
391 U_CAPI int32_t U_EXPORT2
uloc_getDisplayLanguage(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)392 uloc_getDisplayLanguage(const char *locale,
393 const char *displayLocale,
394 UChar *dest, int32_t destCapacity,
395 UErrorCode *pErrorCode) {
396 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
397 uloc_getLanguage, _kLanguages, pErrorCode);
398 }
399
400 U_CAPI int32_t U_EXPORT2
uloc_getDisplayScript(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)401 uloc_getDisplayScript(const char* locale,
402 const char* displayLocale,
403 UChar *dest, int32_t destCapacity,
404 UErrorCode *pErrorCode)
405 {
406 UErrorCode err = U_ZERO_ERROR;
407 int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
408 uloc_getScript, _kScriptsStandAlone, &err);
409
410 if ( err == U_USING_DEFAULT_WARNING ) {
411 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
412 uloc_getScript, _kScripts, pErrorCode);
413 } else {
414 *pErrorCode = err;
415 return res;
416 }
417 }
418
419 U_INTERNAL int32_t U_EXPORT2
uloc_getDisplayScriptInContext(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)420 uloc_getDisplayScriptInContext(const char* locale,
421 const char* displayLocale,
422 UChar *dest, int32_t destCapacity,
423 UErrorCode *pErrorCode)
424 {
425 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
426 uloc_getScript, _kScripts, pErrorCode);
427 }
428
429 U_CAPI int32_t U_EXPORT2
uloc_getDisplayCountry(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)430 uloc_getDisplayCountry(const char *locale,
431 const char *displayLocale,
432 UChar *dest, int32_t destCapacity,
433 UErrorCode *pErrorCode) {
434 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
435 uloc_getCountry, _kCountries, pErrorCode);
436 }
437
438 /*
439 * TODO separate variant1_variant2_variant3...
440 * by getting each tag's display string and concatenating them with ", "
441 * in between - similar to uloc_getDisplayName()
442 */
443 U_CAPI int32_t U_EXPORT2
uloc_getDisplayVariant(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)444 uloc_getDisplayVariant(const char *locale,
445 const char *displayLocale,
446 UChar *dest, int32_t destCapacity,
447 UErrorCode *pErrorCode) {
448 return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
449 uloc_getVariant, _kVariants, pErrorCode);
450 }
451
452 /* Instead of having a separate pass for 'special' patterns, reintegrate the two
453 * so we don't get bitten by preflight bugs again. We can be reasonably efficient
454 * without two separate code paths, this code isn't that performance-critical.
455 *
456 * This code is general enough to deal with patterns that have a prefix or swap the
457 * language and remainder components, since we gave developers enough rope to do such
458 * things if they futz with the pattern data. But since we don't give them a way to
459 * specify a pattern for arbitrary combinations of components, there's not much use in
460 * that. I don't think our data includes such patterns, the only variable I know if is
461 * whether there is a space before the open paren, or not. Oh, and zh uses different
462 * chars than the standard open/close paren (which ja and ko use, btw).
463 */
464 U_CAPI int32_t U_EXPORT2
uloc_getDisplayName(const char * locale,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * pErrorCode)465 uloc_getDisplayName(const char *locale,
466 const char *displayLocale,
467 UChar *dest, int32_t destCapacity,
468 UErrorCode *pErrorCode)
469 {
470 static const UChar defaultSeparator[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */
471 static const UChar sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
472 static const UChar sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
473 static const int32_t subLen = 3;
474 static const UChar defaultPattern[10] = {
475 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000
476 }; /* {0} ({1}) */
477 static const int32_t defaultPatLen = 9;
478 static const int32_t defaultSub0Pos = 0;
479 static const int32_t defaultSub1Pos = 5;
480
481 int32_t length; /* of formatted result */
482
483 const UChar *separator;
484 int32_t sepLen = 0;
485 const UChar *pattern;
486 int32_t patLen = 0;
487 int32_t sub0Pos, sub1Pos;
488
489 UChar formatOpenParen = 0x0028; // (
490 UChar formatReplaceOpenParen = 0x005B; // [
491 UChar formatCloseParen = 0x0029; // )
492 UChar formatReplaceCloseParen = 0x005D; // ]
493
494 UBool haveLang = TRUE; /* assume true, set false if we find we don't have
495 a lang component in the locale */
496 UBool haveRest = TRUE; /* assume true, set false if we find we don't have
497 any other component in the locale */
498 UBool retry = FALSE; /* set true if we need to retry, see below */
499
500 int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */
501
502 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
503 return 0;
504 }
505
506 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
507 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
508 return 0;
509 }
510
511 {
512 UErrorCode status = U_ZERO_ERROR;
513 UResourceBundle* locbundle=ures_open(U_ICUDATA_LANG, displayLocale, &status);
514 UResourceBundle* dspbundle=ures_getByKeyWithFallback(locbundle, _kLocaleDisplayPattern,
515 NULL, &status);
516
517 separator=ures_getStringByKeyWithFallback(dspbundle, _kSeparator, &sepLen, &status);
518 pattern=ures_getStringByKeyWithFallback(dspbundle, _kPattern, &patLen, &status);
519
520 ures_close(dspbundle);
521 ures_close(locbundle);
522 }
523
524 /* If we couldn't find any data, then use the defaults */
525 if(sepLen == 0) {
526 separator = defaultSeparator;
527 }
528 /* #10244: Even though separator is now a pattern, it is awkward to handle it as such
529 * here since we are trying to build the display string in place in the dest buffer,
530 * and to handle it as a pattern would entail having separate storage for the
531 * substrings that need to be combined (the first of which may be the result of
532 * previous such combinations). So for now we continue to treat the portion between
533 * {0} and {1} as a string to be appended when joining substrings, ignoring anything
534 * that is before {0} or after {1} (no existing separator pattern has any such thing).
535 * This is similar to how pattern is handled below.
536 */
537 {
538 UChar *p0=u_strstr(separator, sub0);
539 UChar *p1=u_strstr(separator, sub1);
540 if (p0==NULL || p1==NULL || p1<p0) {
541 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
542 return 0;
543 }
544 separator = (const UChar *)p0 + subLen;
545 sepLen = static_cast<int32_t>(p1 - separator);
546 }
547
548 if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) {
549 pattern=defaultPattern;
550 patLen=defaultPatLen;
551 sub0Pos=defaultSub0Pos;
552 sub1Pos=defaultSub1Pos;
553 // use default formatOpenParen etc. set above
554 } else { /* non-default pattern */
555 UChar *p0=u_strstr(pattern, sub0);
556 UChar *p1=u_strstr(pattern, sub1);
557 if (p0==NULL || p1==NULL) {
558 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
559 return 0;
560 }
561 sub0Pos = static_cast<int32_t>(p0-pattern);
562 sub1Pos = static_cast<int32_t>(p1-pattern);
563 if (sub1Pos < sub0Pos) { /* a very odd pattern */
564 int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t;
565 langi=1;
566 }
567 if (u_strchr(pattern, 0xFF08) != NULL) {
568 formatOpenParen = 0xFF08; // fullwidth (
569 formatReplaceOpenParen = 0xFF3B; // fullwidth [
570 formatCloseParen = 0xFF09; // fullwidth )
571 formatReplaceCloseParen = 0xFF3D; // fullwidth ]
572 }
573 }
574
575 /* We loop here because there is one case in which after the first pass we could need to
576 * reextract the data. If there's initial padding before the first element, we put in
577 * the padding and then write that element. If it turns out there's no second element,
578 * we didn't need the padding. If we do need the data (no preflight), and the first element
579 * would have fit but for the padding, we need to reextract. In this case (only) we
580 * adjust the parameters so padding is not added, and repeat.
581 */
582 do {
583 UChar* p=dest;
584 int32_t patPos=0; /* position in the pattern, used for non-substitution portions */
585 int32_t langLen=0; /* length of language substitution */
586 int32_t langPos=0; /* position in output of language substitution */
587 int32_t restLen=0; /* length of 'everything else' substitution */
588 int32_t restPos=0; /* position in output of 'everything else' substitution */
589 UEnumeration* kenum = NULL; /* keyword enumeration */
590
591 /* prefix of pattern, extremely likely to be empty */
592 if(sub0Pos) {
593 if(destCapacity >= sub0Pos) {
594 while (patPos < sub0Pos) {
595 *p++ = pattern[patPos++];
596 }
597 } else {
598 patPos=sub0Pos;
599 }
600 length=sub0Pos;
601 } else {
602 length=0;
603 }
604
605 for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/
606 UBool subdone = FALSE; /* set true when ready to move to next substitution */
607
608 /* prep p and cap for calls to get display components, pin cap to 0 since
609 they complain if cap is negative */
610 int32_t cap=destCapacity-length;
611 if (cap <= 0) {
612 cap=0;
613 } else {
614 p=dest+length;
615 }
616
617 if (subi == langi) { /* {0}*/
618 if(haveLang) {
619 langPos=length;
620 langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode);
621 length+=langLen;
622 haveLang=langLen>0;
623 }
624 subdone=TRUE;
625 } else { /* {1} */
626 if(!haveRest) {
627 subdone=TRUE;
628 } else {
629 int32_t len; /* length of component (plus other stuff) we just fetched */
630 switch(resti++) {
631 case 0:
632 restPos=length;
633 len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode);
634 break;
635 case 1:
636 len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode);
637 break;
638 case 2:
639 len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode);
640 break;
641 case 3:
642 kenum = uloc_openKeywords(locale, pErrorCode);
643 U_FALLTHROUGH;
644 default: {
645 const char* kw=uenum_next(kenum, &len, pErrorCode);
646 if (kw == NULL) {
647 uenum_close(kenum);
648 len=0; /* mark that we didn't add a component */
649 subdone=TRUE;
650 } else {
651 /* incorporating this behavior into the loop made it even more complex,
652 so just special case it here */
653 len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode);
654 if(len) {
655 if(len < cap) {
656 p[len]=0x3d; /* '=', assume we'll need it */
657 }
658 len+=1;
659
660 /* adjust for call to get keyword */
661 cap-=len;
662 if(cap <= 0) {
663 cap=0;
664 } else {
665 p+=len;
666 }
667 }
668 /* reset for call below */
669 if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
670 *pErrorCode=U_ZERO_ERROR;
671 }
672 int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale,
673 p, cap, pErrorCode);
674 if(len) {
675 if(vlen==0) {
676 --len; /* remove unneeded '=' */
677 }
678 /* restore cap and p to what they were at start */
679 cap=destCapacity-length;
680 if(cap <= 0) {
681 cap=0;
682 } else {
683 p=dest+length;
684 }
685 }
686 len+=vlen; /* total we added for key + '=' + value */
687 }
688 } break;
689 } /* end switch */
690
691 if (len>0) {
692 /* we addeed a component, so add separator and write it if there's room. */
693 if(len+sepLen<=cap) {
694 const UChar * plimit = p + len;
695 for (; p < plimit; p++) {
696 if (*p == formatOpenParen) {
697 *p = formatReplaceOpenParen;
698 } else if (*p == formatCloseParen) {
699 *p = formatReplaceCloseParen;
700 }
701 }
702 for(int32_t i=0;i<sepLen;++i) {
703 *p++=separator[i];
704 }
705 }
706 length+=len+sepLen;
707 } else if(subdone) {
708 /* remove separator if we added it */
709 if (length!=restPos) {
710 length-=sepLen;
711 }
712 restLen=length-restPos;
713 haveRest=restLen>0;
714 }
715 }
716 }
717
718 if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
719 *pErrorCode=U_ZERO_ERROR;
720 }
721
722 if(subdone) {
723 if(haveLang && haveRest) {
724 /* append internal portion of pattern, the first time,
725 or last portion of pattern the second time */
726 int32_t padLen;
727 patPos+=subLen;
728 padLen=(subi==0 ? sub1Pos : patLen)-patPos;
729 if(length+padLen < destCapacity) {
730 p=dest+length;
731 for(int32_t i=0;i<padLen;++i) {
732 *p++=pattern[patPos++];
733 }
734 } else {
735 patPos+=padLen;
736 }
737 length+=padLen;
738 } else if(subi==0) {
739 /* don't have first component, reset for second component */
740 sub0Pos=0;
741 length=0;
742 } else if(length>0) {
743 /* true length is the length of just the component we got. */
744 length=haveLang?langLen:restLen;
745 if(dest && sub0Pos!=0) {
746 if (sub0Pos+length<=destCapacity) {
747 /* first component not at start of result,
748 but we have full component in buffer. */
749 u_memmove(dest, dest+(haveLang?langPos:restPos), length);
750 } else {
751 /* would have fit, but didn't because of pattern prefix. */
752 sub0Pos=0; /* stops initial padding (and a second retry,
753 so we won't end up here again) */
754 retry=TRUE;
755 }
756 }
757 }
758
759 ++subi; /* move on to next substitution */
760 }
761 }
762 } while(retry);
763
764 return u_terminateUChars(dest, destCapacity, length, pErrorCode);
765 }
766
767 U_CAPI int32_t U_EXPORT2
uloc_getDisplayKeyword(const char * keyword,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * status)768 uloc_getDisplayKeyword(const char* keyword,
769 const char* displayLocale,
770 UChar* dest,
771 int32_t destCapacity,
772 UErrorCode* status){
773
774 /* argument checking */
775 if(status==NULL || U_FAILURE(*status)) {
776 return 0;
777 }
778
779 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
780 *status=U_ILLEGAL_ARGUMENT_ERROR;
781 return 0;
782 }
783
784
785 /* pass itemKey=NULL to look for a top-level item */
786 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
787 _kKeys, NULL,
788 keyword,
789 keyword,
790 dest, destCapacity,
791 status);
792
793 }
794
795
796 #define UCURRENCY_DISPLAY_NAME_INDEX 1
797
798 U_CAPI int32_t U_EXPORT2
uloc_getDisplayKeywordValue(const char * locale,const char * keyword,const char * displayLocale,UChar * dest,int32_t destCapacity,UErrorCode * status)799 uloc_getDisplayKeywordValue( const char* locale,
800 const char* keyword,
801 const char* displayLocale,
802 UChar* dest,
803 int32_t destCapacity,
804 UErrorCode* status){
805
806
807 char keywordValue[ULOC_FULLNAME_CAPACITY*4];
808 int32_t capacity = ULOC_FULLNAME_CAPACITY*4;
809 int32_t keywordValueLen =0;
810
811 /* argument checking */
812 if(status==NULL || U_FAILURE(*status)) {
813 return 0;
814 }
815
816 if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
817 *status=U_ILLEGAL_ARGUMENT_ERROR;
818 return 0;
819 }
820
821 /* get the keyword value */
822 keywordValue[0]=0;
823 keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status);
824 if (*status == U_STRING_NOT_TERMINATED_WARNING)
825 *status = U_BUFFER_OVERFLOW_ERROR;
826
827 /*
828 * if the keyword is equal to currency .. then to get the display name
829 * we need to do the fallback ourselves
830 */
831 if(uprv_stricmp(keyword, _kCurrency)==0){
832
833 int32_t dispNameLen = 0;
834 const UChar *dispName = NULL;
835
836 UResourceBundle *bundle = ures_open(U_ICUDATA_CURR, displayLocale, status);
837 UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status);
838 UResourceBundle *currency = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status);
839
840 dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
841
842 /*close the bundles */
843 ures_close(currency);
844 ures_close(currencies);
845 ures_close(bundle);
846
847 if(U_FAILURE(*status)){
848 if(*status == U_MISSING_RESOURCE_ERROR){
849 /* we just want to write the value over if nothing is available */
850 *status = U_USING_DEFAULT_WARNING;
851 }else{
852 return 0;
853 }
854 }
855
856 /* now copy the dispName over if not NULL */
857 if(dispName != NULL){
858 if(dispNameLen <= destCapacity){
859 u_memcpy(dest, dispName, dispNameLen);
860 return u_terminateUChars(dest, destCapacity, dispNameLen, status);
861 }else{
862 *status = U_BUFFER_OVERFLOW_ERROR;
863 return dispNameLen;
864 }
865 }else{
866 /* we have not found the display name for the value .. just copy over */
867 if(keywordValueLen <= destCapacity){
868 u_charsToUChars(keywordValue, dest, keywordValueLen);
869 return u_terminateUChars(dest, destCapacity, keywordValueLen, status);
870 }else{
871 *status = U_BUFFER_OVERFLOW_ERROR;
872 return keywordValueLen;
873 }
874 }
875
876
877 }else{
878
879 return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
880 _kTypes, keyword,
881 keywordValue,
882 keywordValue,
883 dest, destCapacity,
884 status);
885 }
886 }
887