Line data Source code
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&
41 0 : Locale::getDisplayLanguage(UnicodeString& dispLang) const
42 : {
43 0 : 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&
53 0 : Locale::getDisplayLanguage(const Locale &displayLocale,
54 : UnicodeString &result) const {
55 : UChar *buffer;
56 0 : UErrorCode errorCode=U_ZERO_ERROR;
57 : int32_t length;
58 :
59 0 : buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
60 0 : if(buffer==0) {
61 0 : result.truncate(0);
62 0 : return result;
63 : }
64 :
65 0 : length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
66 : buffer, result.getCapacity(),
67 0 : &errorCode);
68 0 : result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
69 :
70 0 : if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
71 0 : buffer=result.getBuffer(length);
72 0 : if(buffer==0) {
73 0 : result.truncate(0);
74 0 : return result;
75 : }
76 0 : errorCode=U_ZERO_ERROR;
77 0 : length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
78 : buffer, result.getCapacity(),
79 0 : &errorCode);
80 0 : result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
81 : }
82 :
83 0 : return result;
84 : }
85 :
86 : UnicodeString&
87 0 : Locale::getDisplayScript(UnicodeString& dispScript) const
88 : {
89 0 : return this->getDisplayScript(getDefault(), dispScript);
90 : }
91 :
92 : UnicodeString&
93 0 : Locale::getDisplayScript(const Locale &displayLocale,
94 : UnicodeString &result) const {
95 : UChar *buffer;
96 0 : UErrorCode errorCode=U_ZERO_ERROR;
97 : int32_t length;
98 :
99 0 : buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
100 0 : if(buffer==0) {
101 0 : result.truncate(0);
102 0 : return result;
103 : }
104 :
105 0 : length=uloc_getDisplayScript(fullName, displayLocale.fullName,
106 : buffer, result.getCapacity(),
107 0 : &errorCode);
108 0 : result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
109 :
110 0 : if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
111 0 : buffer=result.getBuffer(length);
112 0 : if(buffer==0) {
113 0 : result.truncate(0);
114 0 : return result;
115 : }
116 0 : errorCode=U_ZERO_ERROR;
117 0 : length=uloc_getDisplayScript(fullName, displayLocale.fullName,
118 : buffer, result.getCapacity(),
119 0 : &errorCode);
120 0 : result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
121 : }
122 :
123 0 : return result;
124 : }
125 :
126 : UnicodeString&
127 0 : Locale::getDisplayCountry(UnicodeString& dispCntry) const
128 : {
129 0 : return this->getDisplayCountry(getDefault(), dispCntry);
130 : }
131 :
132 : UnicodeString&
133 0 : Locale::getDisplayCountry(const Locale &displayLocale,
134 : UnicodeString &result) const {
135 : UChar *buffer;
136 0 : UErrorCode errorCode=U_ZERO_ERROR;
137 : int32_t length;
138 :
139 0 : buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
140 0 : if(buffer==0) {
141 0 : result.truncate(0);
142 0 : return result;
143 : }
144 :
145 0 : length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
146 : buffer, result.getCapacity(),
147 0 : &errorCode);
148 0 : result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
149 :
150 0 : if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
151 0 : buffer=result.getBuffer(length);
152 0 : if(buffer==0) {
153 0 : result.truncate(0);
154 0 : return result;
155 : }
156 0 : errorCode=U_ZERO_ERROR;
157 0 : length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
158 : buffer, result.getCapacity(),
159 0 : &errorCode);
160 0 : result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
161 : }
162 :
163 0 : return result;
164 : }
165 :
166 : UnicodeString&
167 0 : Locale::getDisplayVariant(UnicodeString& dispVar) const
168 : {
169 0 : return this->getDisplayVariant(getDefault(), dispVar);
170 : }
171 :
172 : UnicodeString&
173 0 : Locale::getDisplayVariant(const Locale &displayLocale,
174 : UnicodeString &result) const {
175 : UChar *buffer;
176 0 : UErrorCode errorCode=U_ZERO_ERROR;
177 : int32_t length;
178 :
179 0 : buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
180 0 : if(buffer==0) {
181 0 : result.truncate(0);
182 0 : return result;
183 : }
184 :
185 0 : length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
186 : buffer, result.getCapacity(),
187 0 : &errorCode);
188 0 : result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
189 :
190 0 : if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
191 0 : buffer=result.getBuffer(length);
192 0 : if(buffer==0) {
193 0 : result.truncate(0);
194 0 : return result;
195 : }
196 0 : errorCode=U_ZERO_ERROR;
197 0 : length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
198 : buffer, result.getCapacity(),
199 0 : &errorCode);
200 0 : result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
201 : }
202 :
203 0 : return result;
204 : }
205 :
206 : UnicodeString&
207 0 : Locale::getDisplayName( UnicodeString& name ) const
208 : {
209 0 : return this->getDisplayName(getDefault(), name);
210 : }
211 :
212 : UnicodeString&
213 0 : Locale::getDisplayName(const Locale &displayLocale,
214 : UnicodeString &result) const {
215 : UChar *buffer;
216 0 : UErrorCode errorCode=U_ZERO_ERROR;
217 : int32_t length;
218 :
219 0 : buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
220 0 : if(buffer==0) {
221 0 : result.truncate(0);
222 0 : return result;
223 : }
224 :
225 0 : length=uloc_getDisplayName(fullName, displayLocale.fullName,
226 : buffer, result.getCapacity(),
227 0 : &errorCode);
228 0 : result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
229 :
230 0 : if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
231 0 : buffer=result.getBuffer(length);
232 0 : if(buffer==0) {
233 0 : result.truncate(0);
234 0 : return result;
235 : }
236 0 : errorCode=U_ZERO_ERROR;
237 0 : length=uloc_getDisplayName(fullName, displayLocale.fullName,
238 : buffer, result.getCapacity(),
239 0 : &errorCode);
240 0 : result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
241 : }
242 :
243 0 : 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
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
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
297 0 : _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 0 : const UChar *s = NULL;
305 0 : int32_t length = 0;
306 :
307 0 : if(itemKey==NULL) {
308 : /* top-level item: normal resource bundle access */
309 : UResourceBundle *rb;
310 :
311 0 : rb=ures_open(path, locale, pErrorCode);
312 :
313 0 : if(U_SUCCESS(*pErrorCode)) {
314 0 : s=ures_getStringByKey(rb, tableKey, &length, pErrorCode);
315 : /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
316 0 : ures_close(rb);
317 : }
318 : } else {
319 : /* Language code should not be a number. If it is, set the error code. */
320 0 : if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) {
321 0 : *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 0 : pErrorCode);
330 : }
331 : }
332 :
333 0 : if(U_SUCCESS(*pErrorCode)) {
334 0 : int32_t copyLength=uprv_min(length, destCapacity);
335 0 : if(copyLength>0 && s != NULL) {
336 0 : u_memcpy(dest, s, copyLength);
337 : }
338 : } else {
339 : /* no string from a resource bundle: convert the substitute */
340 0 : length=(int32_t)uprv_strlen(substitute);
341 0 : u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
342 0 : *pErrorCode=U_USING_DEFAULT_WARNING;
343 : }
344 :
345 0 : 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
351 0 : _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 0 : const char* root = NULL;
361 :
362 : /* argument checking */
363 0 : if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
364 0 : return 0;
365 : }
366 :
367 0 : if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
368 0 : *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
369 0 : return 0;
370 : }
371 :
372 0 : localStatus = U_ZERO_ERROR;
373 0 : length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
374 0 : if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
375 0 : *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
376 0 : return 0;
377 : }
378 0 : if(length==0) {
379 0 : return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
380 : }
381 :
382 0 : 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 0 : pErrorCode);
389 : }
390 :
391 : U_CAPI int32_t U_EXPORT2
392 0 : 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 0 : uloc_getLanguage, _kLanguages, pErrorCode);
398 : }
399 :
400 : U_CAPI int32_t U_EXPORT2
401 0 : uloc_getDisplayScript(const char* locale,
402 : const char* displayLocale,
403 : UChar *dest, int32_t destCapacity,
404 : UErrorCode *pErrorCode)
405 : {
406 0 : UErrorCode err = U_ZERO_ERROR;
407 : int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
408 0 : uloc_getScript, _kScriptsStandAlone, &err);
409 :
410 0 : if ( err == U_USING_DEFAULT_WARNING ) {
411 : return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
412 0 : uloc_getScript, _kScripts, pErrorCode);
413 : } else {
414 0 : *pErrorCode = err;
415 0 : return res;
416 : }
417 : }
418 :
419 : U_INTERNAL int32_t U_EXPORT2
420 0 : 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 0 : uloc_getScript, _kScripts, pErrorCode);
427 : }
428 :
429 : U_CAPI int32_t U_EXPORT2
430 0 : 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 0 : 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
444 0 : 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 0 : 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
465 0 : 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 0 : int32_t sepLen = 0;
485 : const UChar *pattern;
486 0 : int32_t patLen = 0;
487 : int32_t sub0Pos, sub1Pos;
488 :
489 0 : UChar formatOpenParen = 0x0028; // (
490 0 : UChar formatReplaceOpenParen = 0x005B; // [
491 0 : UChar formatCloseParen = 0x0029; // )
492 0 : UChar formatReplaceCloseParen = 0x005D; // ]
493 :
494 0 : UBool haveLang = TRUE; /* assume true, set false if we find we don't have
495 : a lang component in the locale */
496 0 : UBool haveRest = TRUE; /* assume true, set false if we find we don't have
497 : any other component in the locale */
498 0 : UBool retry = FALSE; /* set true if we need to retry, see below */
499 :
500 0 : int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */
501 :
502 0 : if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
503 0 : return 0;
504 : }
505 :
506 0 : if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
507 0 : *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
508 0 : return 0;
509 : }
510 :
511 : {
512 0 : UErrorCode status = U_ZERO_ERROR;
513 0 : UResourceBundle* locbundle=ures_open(U_ICUDATA_LANG, displayLocale, &status);
514 : UResourceBundle* dspbundle=ures_getByKeyWithFallback(locbundle, _kLocaleDisplayPattern,
515 0 : NULL, &status);
516 :
517 0 : separator=ures_getStringByKeyWithFallback(dspbundle, _kSeparator, &sepLen, &status);
518 0 : pattern=ures_getStringByKeyWithFallback(dspbundle, _kPattern, &patLen, &status);
519 :
520 0 : ures_close(dspbundle);
521 0 : ures_close(locbundle);
522 : }
523 :
524 : /* If we couldn't find any data, then use the defaults */
525 0 : if(sepLen == 0) {
526 0 : 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 0 : UChar *p0=u_strstr(separator, sub0);
539 0 : UChar *p1=u_strstr(separator, sub1);
540 0 : if (p0==NULL || p1==NULL || p1<p0) {
541 0 : *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
542 0 : return 0;
543 : }
544 0 : separator = (const UChar *)p0 + subLen;
545 0 : sepLen = p1 - separator;
546 : }
547 :
548 0 : if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) {
549 0 : pattern=defaultPattern;
550 0 : patLen=defaultPatLen;
551 0 : sub0Pos=defaultSub0Pos;
552 0 : sub1Pos=defaultSub1Pos;
553 : // use default formatOpenParen etc. set above
554 : } else { /* non-default pattern */
555 0 : UChar *p0=u_strstr(pattern, sub0);
556 0 : UChar *p1=u_strstr(pattern, sub1);
557 0 : if (p0==NULL || p1==NULL) {
558 0 : *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
559 0 : return 0;
560 : }
561 0 : sub0Pos=p0-pattern;
562 0 : sub1Pos=p1-pattern;
563 0 : if (sub1Pos < sub0Pos) { /* a very odd pattern */
564 0 : int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t;
565 0 : langi=1;
566 : }
567 0 : if (u_strchr(pattern, 0xFF08) != NULL) {
568 0 : formatOpenParen = 0xFF08; // fullwidth (
569 0 : formatReplaceOpenParen = 0xFF3B; // fullwidth [
570 0 : formatCloseParen = 0xFF09; // fullwidth )
571 0 : 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 0 : do {
583 0 : UChar* p=dest;
584 0 : int32_t patPos=0; /* position in the pattern, used for non-substitution portions */
585 0 : int32_t langLen=0; /* length of language substitution */
586 0 : int32_t langPos=0; /* position in output of language substitution */
587 0 : int32_t restLen=0; /* length of 'everything else' substitution */
588 0 : int32_t restPos=0; /* position in output of 'everything else' substitution */
589 0 : UEnumeration* kenum = NULL; /* keyword enumeration */
590 :
591 : /* prefix of pattern, extremely likely to be empty */
592 0 : if(sub0Pos) {
593 0 : if(destCapacity >= sub0Pos) {
594 0 : while (patPos < sub0Pos) {
595 0 : *p++ = pattern[patPos++];
596 : }
597 : } else {
598 0 : patPos=sub0Pos;
599 : }
600 0 : length=sub0Pos;
601 : } else {
602 0 : length=0;
603 : }
604 :
605 0 : for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/
606 0 : 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 0 : int32_t cap=destCapacity-length;
611 0 : if (cap <= 0) {
612 0 : cap=0;
613 : } else {
614 0 : p=dest+length;
615 : }
616 :
617 0 : if (subi == langi) { /* {0}*/
618 0 : if(haveLang) {
619 0 : langPos=length;
620 0 : langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode);
621 0 : length+=langLen;
622 0 : haveLang=langLen>0;
623 : }
624 0 : subdone=TRUE;
625 : } else { /* {1} */
626 0 : if(!haveRest) {
627 0 : subdone=TRUE;
628 : } else {
629 : int32_t len; /* length of component (plus other stuff) we just fetched */
630 0 : switch(resti++) {
631 : case 0:
632 0 : restPos=length;
633 0 : len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode);
634 0 : break;
635 : case 1:
636 0 : len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode);
637 0 : break;
638 : case 2:
639 0 : len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode);
640 0 : break;
641 : case 3:
642 0 : kenum = uloc_openKeywords(locale, pErrorCode);
643 : U_FALLTHROUGH;
644 : default: {
645 0 : const char* kw=uenum_next(kenum, &len, pErrorCode);
646 0 : if (kw == NULL) {
647 0 : uenum_close(kenum);
648 0 : len=0; /* mark that we didn't add a component */
649 0 : subdone=TRUE;
650 : } else {
651 : /* incorporating this behavior into the loop made it even more complex,
652 : so just special case it here */
653 0 : len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode);
654 0 : if(len) {
655 0 : if(len < cap) {
656 0 : p[len]=0x3d; /* '=', assume we'll need it */
657 : }
658 0 : len+=1;
659 :
660 : /* adjust for call to get keyword */
661 0 : cap-=len;
662 0 : if(cap <= 0) {
663 0 : cap=0;
664 : } else {
665 0 : p+=len;
666 : }
667 : }
668 : /* reset for call below */
669 0 : if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
670 0 : *pErrorCode=U_ZERO_ERROR;
671 : }
672 : int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale,
673 0 : p, cap, pErrorCode);
674 0 : if(len) {
675 0 : if(vlen==0) {
676 0 : --len; /* remove unneeded '=' */
677 : }
678 : /* restore cap and p to what they were at start */
679 0 : cap=destCapacity-length;
680 0 : if(cap <= 0) {
681 0 : cap=0;
682 : } else {
683 0 : p=dest+length;
684 : }
685 : }
686 0 : len+=vlen; /* total we added for key + '=' + value */
687 : }
688 0 : } break;
689 : } /* end switch */
690 :
691 0 : if (len>0) {
692 : /* we addeed a component, so add separator and write it if there's room. */
693 0 : if(len+sepLen<=cap) {
694 0 : const UChar * plimit = p + len;
695 0 : for (; p < plimit; p++) {
696 0 : if (*p == formatOpenParen) {
697 0 : *p = formatReplaceOpenParen;
698 0 : } else if (*p == formatCloseParen) {
699 0 : *p = formatReplaceCloseParen;
700 : }
701 : }
702 0 : for(int32_t i=0;i<sepLen;++i) {
703 0 : *p++=separator[i];
704 : }
705 : }
706 0 : length+=len+sepLen;
707 0 : } else if(subdone) {
708 : /* remove separator if we added it */
709 0 : if (length!=restPos) {
710 0 : length-=sepLen;
711 : }
712 0 : restLen=length-restPos;
713 0 : haveRest=restLen>0;
714 : }
715 : }
716 : }
717 :
718 0 : if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
719 0 : *pErrorCode=U_ZERO_ERROR;
720 : }
721 :
722 0 : if(subdone) {
723 0 : 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 0 : patPos+=subLen;
728 0 : padLen=(subi==0 ? sub1Pos : patLen)-patPos;
729 0 : if(length+padLen < destCapacity) {
730 0 : p=dest+length;
731 0 : for(int32_t i=0;i<padLen;++i) {
732 0 : *p++=pattern[patPos++];
733 : }
734 : } else {
735 0 : patPos+=padLen;
736 : }
737 0 : length+=padLen;
738 0 : } else if(subi==0) {
739 : /* don't have first component, reset for second component */
740 0 : sub0Pos=0;
741 0 : length=0;
742 0 : } else if(length>0) {
743 : /* true length is the length of just the component we got. */
744 0 : length=haveLang?langLen:restLen;
745 0 : if(dest && sub0Pos!=0) {
746 0 : if (sub0Pos+length<=destCapacity) {
747 : /* first component not at start of result,
748 : but we have full component in buffer. */
749 0 : u_memmove(dest, dest+(haveLang?langPos:restPos), length);
750 : } else {
751 : /* would have fit, but didn't because of pattern prefix. */
752 0 : sub0Pos=0; /* stops initial padding (and a second retry,
753 : so we won't end up here again) */
754 0 : retry=TRUE;
755 : }
756 : }
757 : }
758 :
759 0 : ++subi; /* move on to next substitution */
760 : }
761 : }
762 0 : } while(retry);
763 :
764 0 : return u_terminateUChars(dest, destCapacity, length, pErrorCode);
765 : }
766 :
767 : U_CAPI int32_t U_EXPORT2
768 0 : uloc_getDisplayKeyword(const char* keyword,
769 : const char* displayLocale,
770 : UChar* dest,
771 : int32_t destCapacity,
772 : UErrorCode* status){
773 :
774 : /* argument checking */
775 0 : if(status==NULL || U_FAILURE(*status)) {
776 0 : return 0;
777 : }
778 :
779 0 : if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
780 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
781 0 : 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 0 : status);
792 :
793 : }
794 :
795 :
796 : #define UCURRENCY_DISPLAY_NAME_INDEX 1
797 :
798 : U_CAPI int32_t U_EXPORT2
799 0 : 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 0 : int32_t capacity = ULOC_FULLNAME_CAPACITY*4;
809 0 : int32_t keywordValueLen =0;
810 :
811 : /* argument checking */
812 0 : if(status==NULL || U_FAILURE(*status)) {
813 0 : return 0;
814 : }
815 :
816 0 : if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
817 0 : *status=U_ILLEGAL_ARGUMENT_ERROR;
818 0 : return 0;
819 : }
820 :
821 : /* get the keyword value */
822 0 : keywordValue[0]=0;
823 0 : keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status);
824 :
825 : /*
826 : * if the keyword is equal to currency .. then to get the display name
827 : * we need to do the fallback ourselves
828 : */
829 0 : if(uprv_stricmp(keyword, _kCurrency)==0){
830 :
831 0 : int32_t dispNameLen = 0;
832 0 : const UChar *dispName = NULL;
833 :
834 0 : UResourceBundle *bundle = ures_open(U_ICUDATA_CURR, displayLocale, status);
835 0 : UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status);
836 0 : UResourceBundle *currency = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status);
837 :
838 0 : dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
839 :
840 : /*close the bundles */
841 0 : ures_close(currency);
842 0 : ures_close(currencies);
843 0 : ures_close(bundle);
844 :
845 0 : if(U_FAILURE(*status)){
846 0 : if(*status == U_MISSING_RESOURCE_ERROR){
847 : /* we just want to write the value over if nothing is available */
848 0 : *status = U_USING_DEFAULT_WARNING;
849 : }else{
850 0 : return 0;
851 : }
852 : }
853 :
854 : /* now copy the dispName over if not NULL */
855 0 : if(dispName != NULL){
856 0 : if(dispNameLen <= destCapacity){
857 0 : u_memcpy(dest, dispName, dispNameLen);
858 0 : return u_terminateUChars(dest, destCapacity, dispNameLen, status);
859 : }else{
860 0 : *status = U_BUFFER_OVERFLOW_ERROR;
861 0 : return dispNameLen;
862 : }
863 : }else{
864 : /* we have not found the display name for the value .. just copy over */
865 0 : if(keywordValueLen <= destCapacity){
866 0 : u_charsToUChars(keywordValue, dest, keywordValueLen);
867 0 : return u_terminateUChars(dest, destCapacity, keywordValueLen, status);
868 : }else{
869 0 : *status = U_BUFFER_OVERFLOW_ERROR;
870 0 : return keywordValueLen;
871 : }
872 : }
873 :
874 :
875 : }else{
876 :
877 : return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
878 : _kTypes, keyword,
879 : keywordValue,
880 : keywordValue,
881 : dest, destCapacity,
882 0 : status);
883 : }
884 : }
|