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