|
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& |
|
39 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& |
|
51 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& |
|
85 Locale::getDisplayScript(UnicodeString& dispScript) const |
|
86 { |
|
87 return this->getDisplayScript(getDefault(), dispScript); |
|
88 } |
|
89 |
|
90 UnicodeString& |
|
91 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& |
|
125 Locale::getDisplayCountry(UnicodeString& dispCntry) const |
|
126 { |
|
127 return this->getDisplayCountry(getDefault(), dispCntry); |
|
128 } |
|
129 |
|
130 UnicodeString& |
|
131 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& |
|
165 Locale::getDisplayVariant(UnicodeString& dispVar) const |
|
166 { |
|
167 return this->getDisplayVariant(getDefault(), dispVar); |
|
168 } |
|
169 |
|
170 UnicodeString& |
|
171 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& |
|
205 Locale::getDisplayName( UnicodeString& name ) const |
|
206 { |
|
207 return this->getDisplayName(getDefault(), name); |
|
208 } |
|
209 |
|
210 UnicodeString& |
|
211 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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 } |