]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/ucurr.cpp
ICU-461.18.tar.gz
[apple/icu.git] / icuSources / i18n / ucurr.cpp
1 /*
2 **********************************************************************
3 * Copyright (c) 2002-2010, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
6 */
7
8 #include "unicode/utypes.h"
9
10 #if !UCONFIG_NO_FORMATTING
11
12 #include "unicode/ucurr.h"
13 #include "unicode/locid.h"
14 #include "unicode/ures.h"
15 #include "unicode/ustring.h"
16 #include "unicode/choicfmt.h"
17 #include "unicode/parsepos.h"
18 #include "ustr_imp.h"
19 #include "cmemory.h"
20 #include "cstring.h"
21 #include "uassert.h"
22 #include "umutex.h"
23 #include "ucln_in.h"
24 #include "uenumimp.h"
25 #include "uhash.h"
26 #include "uresimp.h"
27 #include "ulist.h"
28 #include "ureslocs.h"
29
30 // #define UCURR_DEBUG 1
31 #ifdef UCURR_DEBUG
32 #include "stdio.h"
33 #endif
34
35 //------------------------------------------------------------
36 // Constants
37
38 // Default currency meta data of last resort. We try to use the
39 // defaults encoded in the meta data resource bundle. If there is a
40 // configuration/build error and these are not available, we use these
41 // hard-coded defaults (which should be identical).
42 static const int32_t LAST_RESORT_DATA[] = { 2, 0 };
43
44 // POW10[i] = 10^i, i=0..MAX_POW10
45 static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
46 1000000, 10000000, 100000000, 1000000000 };
47
48 static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1;
49
50 #define ISO_COUNTRY_CODE_LENGTH 3
51
52 //------------------------------------------------------------
53 // Resource tags
54 //
55
56 static const char CURRENCY_DATA[] = "supplementalData";
57 // Tag for meta-data, in root.
58 static const char CURRENCY_META[] = "CurrencyMeta";
59
60 // Tag for map from countries to currencies, in root.
61 static const char CURRENCY_MAP[] = "CurrencyMap";
62
63 // Tag for default meta-data, in CURRENCY_META
64 static const char DEFAULT_META[] = "DEFAULT";
65
66 // Variant for legacy pre-euro mapping in CurrencyMap
67 static const char VAR_PRE_EURO[] = "PREEURO";
68
69 // Variant for legacy euro mapping in CurrencyMap
70 static const char VAR_EURO[] = "EURO";
71
72 // Variant delimiter
73 static const char VAR_DELIM = '_';
74 static const char VAR_DELIM_STR[] = "_";
75
76 // Variant for legacy euro mapping in CurrencyMap
77 //static const char VAR_DELIM_EURO[] = "_EURO";
78
79 #define VARIANT_IS_EMPTY 0
80 #define VARIANT_IS_EURO 0x1
81 #define VARIANT_IS_PREEURO 0x2
82
83 // Tag for localized display names (symbols) of currencies
84 static const char CURRENCIES[] = "Currencies";
85 static const char CURRENCYPLURALS[] = "CurrencyPlurals";
86
87 // Marker character indicating that a display name is a ChoiceFormat
88 // pattern. Strings that start with one mark are ChoiceFormat
89 // patterns. Strings that start with 2 marks are static strings, and
90 // the first mark is deleted.
91 static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign
92
93 static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
94
95 //------------------------------------------------------------
96 // Code
97
98 /**
99 * Unfortunately, we have to convert the UChar* currency code to char*
100 * to use it as a resource key.
101 */
102 static inline char*
103 myUCharsToChars(char* resultOfLen4, const UChar* currency) {
104 u_UCharsToChars(currency, resultOfLen4, ISO_COUNTRY_CODE_LENGTH);
105 resultOfLen4[ISO_COUNTRY_CODE_LENGTH] = 0;
106 return resultOfLen4;
107 }
108
109 /**
110 * Internal function to look up currency data. Result is an array of
111 * two integers. The first is the fraction digits. The second is the
112 * rounding increment, or 0 if none. The rounding increment is in
113 * units of 10^(-fraction_digits).
114 */
115 static const int32_t*
116 _findMetaData(const UChar* currency, UErrorCode& ec) {
117
118 if (currency == 0 || *currency == 0) {
119 if (U_SUCCESS(ec)) {
120 ec = U_ILLEGAL_ARGUMENT_ERROR;
121 }
122 return LAST_RESORT_DATA;
123 }
124
125 // Get CurrencyMeta resource out of root locale file. [This may
126 // move out of the root locale file later; if it does, update this
127 // code.]
128 UResourceBundle* currencyData = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &ec);
129 UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec);
130
131 if (U_FAILURE(ec)) {
132 ures_close(currencyMeta);
133 // Config/build error; return hard-coded defaults
134 return LAST_RESORT_DATA;
135 }
136
137 // Look up our currency, or if that's not available, then DEFAULT
138 char buf[ISO_COUNTRY_CODE_LENGTH+1];
139 UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure
140 UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2);
141 if (U_FAILURE(ec2)) {
142 ures_close(rb);
143 rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec);
144 if (U_FAILURE(ec)) {
145 ures_close(currencyMeta);
146 ures_close(rb);
147 // Config/build error; return hard-coded defaults
148 return LAST_RESORT_DATA;
149 }
150 }
151
152 int32_t len;
153 const int32_t *data = ures_getIntVector(rb, &len, &ec);
154 if (U_FAILURE(ec) || len != 2) {
155 // Config/build error; return hard-coded defaults
156 if (U_SUCCESS(ec)) {
157 ec = U_INVALID_FORMAT_ERROR;
158 }
159 ures_close(currencyMeta);
160 ures_close(rb);
161 return LAST_RESORT_DATA;
162 }
163
164 ures_close(currencyMeta);
165 ures_close(rb);
166 return data;
167 }
168
169 // -------------------------------------
170
171 /**
172 * @see VARIANT_IS_EURO
173 * @see VARIANT_IS_PREEURO
174 */
175 static uint32_t
176 idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec)
177 {
178 uint32_t variantType = 0;
179 // !!! this is internal only, assumes buffer is not null and capacity is sufficient
180 // Extract the country name and variant name. We only
181 // recognize two variant names, EURO and PREEURO.
182 char variant[ULOC_FULLNAME_CAPACITY];
183 uloc_getCountry(locale, countryAndVariant, capacity, ec);
184 uloc_getVariant(locale, variant, sizeof(variant), ec);
185 if (variant[0] != 0) {
186 variantType = (0 == uprv_strcmp(variant, VAR_EURO))
187 | ((0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1);
188 if (variantType)
189 {
190 uprv_strcat(countryAndVariant, VAR_DELIM_STR);
191 uprv_strcat(countryAndVariant, variant);
192 }
193 }
194 return variantType;
195 }
196
197 // ------------------------------------------
198 //
199 // Registration
200 //
201 //-------------------------------------------
202
203 // don't use ICUService since we don't need fallback
204
205 #if !UCONFIG_NO_SERVICE
206 U_CDECL_BEGIN
207 static UBool U_CALLCONV currency_cleanup(void);
208 U_CDECL_END
209 struct CReg;
210
211 static UMTX gCRegLock = 0;
212 static CReg* gCRegHead = 0;
213
214 struct CReg : public U_NAMESPACE_QUALIFIER UMemory {
215 CReg *next;
216 UChar iso[ISO_COUNTRY_CODE_LENGTH+1];
217 char id[ULOC_FULLNAME_CAPACITY];
218
219 CReg(const UChar* _iso, const char* _id)
220 : next(0)
221 {
222 int32_t len = (int32_t)uprv_strlen(_id);
223 if (len > (int32_t)(sizeof(id)-1)) {
224 len = (sizeof(id)-1);
225 }
226 uprv_strncpy(id, _id, len);
227 id[len] = 0;
228 uprv_memcpy(iso, _iso, ISO_COUNTRY_CODE_LENGTH * sizeof(const UChar));
229 iso[ISO_COUNTRY_CODE_LENGTH] = 0;
230 }
231
232 static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status)
233 {
234 if (status && U_SUCCESS(*status) && _iso && _id) {
235 CReg* n = new CReg(_iso, _id);
236 if (n) {
237 umtx_lock(&gCRegLock);
238 if (!gCRegHead) {
239 /* register for the first time */
240 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
241 }
242 n->next = gCRegHead;
243 gCRegHead = n;
244 umtx_unlock(&gCRegLock);
245 return n;
246 }
247 *status = U_MEMORY_ALLOCATION_ERROR;
248 }
249 return 0;
250 }
251
252 static UBool unreg(UCurrRegistryKey key) {
253 UBool found = FALSE;
254 umtx_lock(&gCRegLock);
255
256 CReg** p = &gCRegHead;
257 while (*p) {
258 if (*p == key) {
259 *p = ((CReg*)key)->next;
260 delete (CReg*)key;
261 found = TRUE;
262 break;
263 }
264 p = &((*p)->next);
265 }
266
267 umtx_unlock(&gCRegLock);
268 return found;
269 }
270
271 static const UChar* get(const char* id) {
272 const UChar* result = NULL;
273 umtx_lock(&gCRegLock);
274 CReg* p = gCRegHead;
275
276 /* register cleanup of the mutex */
277 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
278 while (p) {
279 if (uprv_strcmp(id, p->id) == 0) {
280 result = p->iso;
281 break;
282 }
283 p = p->next;
284 }
285 umtx_unlock(&gCRegLock);
286 return result;
287 }
288
289 /* This doesn't need to be thread safe. It's for u_cleanup only. */
290 static void cleanup(void) {
291 while (gCRegHead) {
292 CReg* n = gCRegHead;
293 gCRegHead = gCRegHead->next;
294 delete n;
295 }
296 umtx_destroy(&gCRegLock);
297 }
298 };
299
300 /**
301 * Release all static memory held by currency.
302 */
303 /*The declaration here is needed so currency_cleanup(void)
304 * can call this function.
305 */
306 static UBool U_CALLCONV
307 currency_cache_cleanup(void);
308
309 U_CDECL_BEGIN
310 static UBool U_CALLCONV currency_cleanup(void) {
311 #if !UCONFIG_NO_SERVICE
312 CReg::cleanup();
313 #endif
314 /*
315 * There might be some cached currency data.
316 */
317 currency_cache_cleanup();
318 return TRUE;
319 }
320 U_CDECL_END
321
322 // -------------------------------------
323
324 U_CAPI UCurrRegistryKey U_EXPORT2
325 ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
326 {
327 if (status && U_SUCCESS(*status)) {
328 char id[ULOC_FULLNAME_CAPACITY];
329 idForLocale(locale, id, sizeof(id), status);
330 return CReg::reg(isoCode, id, status);
331 }
332 return NULL;
333 }
334
335 // -------------------------------------
336
337 U_CAPI UBool U_EXPORT2
338 ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
339 {
340 if (status && U_SUCCESS(*status)) {
341 return CReg::unreg(key);
342 }
343 return FALSE;
344 }
345 #endif /* UCONFIG_NO_SERVICE */
346
347 // -------------------------------------
348
349 U_CAPI int32_t U_EXPORT2
350 ucurr_forLocale(const char* locale,
351 UChar* buff,
352 int32_t buffCapacity,
353 UErrorCode* ec)
354 {
355 int32_t resLen = 0;
356 const UChar* s = NULL;
357 if (ec != NULL && U_SUCCESS(*ec)) {
358 if ((buff && buffCapacity) || !buffCapacity) {
359 UErrorCode localStatus = U_ZERO_ERROR;
360 char id[ULOC_FULLNAME_CAPACITY];
361 if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) {
362 // there is a currency keyword. Try to see if it's valid
363 if(buffCapacity > resLen) {
364 /* Normalize the currency keyword value to upper case. */
365 T_CString_toUpperCase(id);
366 u_charsToUChars(id, buff, resLen);
367 }
368 } else {
369 // get country or country_variant in `id'
370 uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
371
372 if (U_FAILURE(*ec)) {
373 return 0;
374 }
375
376 #if !UCONFIG_NO_SERVICE
377 const UChar* result = CReg::get(id);
378 if (result) {
379 if(buffCapacity > u_strlen(result)) {
380 u_strcpy(buff, result);
381 }
382 return u_strlen(result);
383 }
384 #endif
385 // Remove variants, which is only needed for registration.
386 char *idDelim = strchr(id, VAR_DELIM);
387 if (idDelim) {
388 idDelim[0] = 0;
389 }
390
391 // Look up the CurrencyMap element in the root bundle.
392 UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
393 UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
394 UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
395 UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus);
396 s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
397
398 /*
399 Get the second item when PREEURO is requested, and this is a known Euro country.
400 If the requested variant is PREEURO, and this isn't a Euro country, assume
401 that the country changed over to the Euro in the future. This is probably
402 an old version of ICU that hasn't been updated yet. The latest currency is
403 probably correct.
404 */
405 if (U_SUCCESS(localStatus)) {
406 if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) {
407 currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus);
408 s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
409 }
410 else if ((variantType & VARIANT_IS_EURO)) {
411 s = EUR_STR;
412 }
413 }
414 ures_close(countryArray);
415 ures_close(currencyReq);
416
417 if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0)
418 {
419 // We don't know about it. Check to see if we support the variant.
420 uloc_getParent(locale, id, sizeof(id), ec);
421 *ec = U_USING_FALLBACK_WARNING;
422 return ucurr_forLocale(id, buff, buffCapacity, ec);
423 }
424 else if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) {
425 // There is nothing to fallback to. Report the failure/warning if possible.
426 *ec = localStatus;
427 }
428 if (U_SUCCESS(*ec)) {
429 if(buffCapacity > resLen) {
430 u_strcpy(buff, s);
431 }
432 }
433 }
434 return u_terminateUChars(buff, buffCapacity, resLen, ec);
435 } else {
436 *ec = U_ILLEGAL_ARGUMENT_ERROR;
437 }
438 }
439 return resLen;
440 }
441
442 // end registration
443
444 /**
445 * Modify the given locale name by removing the rightmost _-delimited
446 * element. If there is none, empty the string ("" == root).
447 * NOTE: The string "root" is not recognized; do not use it.
448 * @return TRUE if the fallback happened; FALSE if locale is already
449 * root ("").
450 */
451 static UBool fallback(char *loc) {
452 if (!*loc) {
453 return FALSE;
454 }
455 UErrorCode status = U_ZERO_ERROR;
456 uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status);
457 /*
458 char *i = uprv_strrchr(loc, '_');
459 if (i == NULL) {
460 i = loc;
461 }
462 *i = 0;
463 */
464 return TRUE;
465 }
466
467
468 U_CAPI const UChar* U_EXPORT2
469 ucurr_getName(const UChar* currency,
470 const char* locale,
471 UCurrNameStyle nameStyle,
472 UBool* isChoiceFormat, // fillin
473 int32_t* len, // fillin
474 UErrorCode* ec) {
475
476 // Look up the Currencies resource for the given locale. The
477 // Currencies locale data looks like this:
478 //|en {
479 //| Currencies {
480 //| USD { "US$", "US Dollar" }
481 //| CHF { "Sw F", "Swiss Franc" }
482 //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
483 //| //...
484 //| }
485 //|}
486
487 if (U_FAILURE(*ec)) {
488 return 0;
489 }
490
491 int32_t choice = (int32_t) nameStyle;
492 if (choice < 0 || choice > 1) {
493 *ec = U_ILLEGAL_ARGUMENT_ERROR;
494 return 0;
495 }
496
497 // In the future, resource bundles may implement multi-level
498 // fallback. That is, if a currency is not found in the en_US
499 // Currencies data, then the en Currencies data will be searched.
500 // Currently, if a Currencies datum exists in en_US and en, the
501 // en_US entry hides that in en.
502
503 // We want multi-level fallback for this resource, so we implement
504 // it manually.
505
506 // Use a separate UErrorCode here that does not propagate out of
507 // this function.
508 UErrorCode ec2 = U_ZERO_ERROR;
509
510 char loc[ULOC_FULLNAME_CAPACITY];
511 uloc_getName(locale, loc, sizeof(loc), &ec2);
512 if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
513 *ec = U_ILLEGAL_ARGUMENT_ERROR;
514 return 0;
515 }
516
517 char buf[ISO_COUNTRY_CODE_LENGTH+1];
518 myUCharsToChars(buf, currency);
519
520 /* Normalize the keyword value to uppercase */
521 T_CString_toUpperCase(buf);
522
523 const UChar* s = NULL;
524 ec2 = U_ZERO_ERROR;
525 UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
526
527 rb = ures_getByKey(rb, CURRENCIES, rb, &ec2);
528
529 // Fetch resource with multi-level resource inheritance fallback
530 rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
531
532 s = ures_getStringByIndex(rb, choice, len, &ec2);
533 ures_close(rb);
534
535 // If we've succeeded we're done. Otherwise, try to fallback.
536 // If that fails (because we are already at root) then exit.
537 if (U_SUCCESS(ec2)) {
538 if (ec2 == U_USING_DEFAULT_WARNING
539 || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
540 *ec = ec2;
541 }
542 }
543
544 // Determine if this is a ChoiceFormat pattern. One leading mark
545 // indicates a ChoiceFormat. Two indicates a static string that
546 // starts with a mark. In either case, the first mark is ignored,
547 // if present. Marks in the rest of the string have no special
548 // meaning.
549 *isChoiceFormat = FALSE;
550 if (U_SUCCESS(ec2)) {
551 U_ASSERT(s != NULL);
552 int32_t i=0;
553 while (i < *len && s[i] == CHOICE_FORMAT_MARK && i < 2) {
554 ++i;
555 }
556 *isChoiceFormat = (i == 1);
557 if (i != 0) ++s; // Skip over first mark
558 return s;
559 }
560
561 // If we fail to find a match, use the ISO 4217 code
562 *len = u_strlen(currency); // Should == ISO_COUNTRY_CODE_LENGTH, but maybe not...?
563 *ec = U_USING_DEFAULT_WARNING;
564 return currency;
565 }
566
567 U_CAPI const UChar* U_EXPORT2
568 ucurr_getPluralName(const UChar* currency,
569 const char* locale,
570 UBool* isChoiceFormat,
571 const char* pluralCount,
572 int32_t* len, // fillin
573 UErrorCode* ec) {
574 // Look up the Currencies resource for the given locale. The
575 // Currencies locale data looks like this:
576 //|en {
577 //| CurrencyPlurals {
578 //| USD{
579 //| one{"US dollar"}
580 //| other{"US dollars"}
581 //| }
582 //| }
583 //|}
584
585 if (U_FAILURE(*ec)) {
586 return 0;
587 }
588
589 // Use a separate UErrorCode here that does not propagate out of
590 // this function.
591 UErrorCode ec2 = U_ZERO_ERROR;
592
593 char loc[ULOC_FULLNAME_CAPACITY];
594 uloc_getName(locale, loc, sizeof(loc), &ec2);
595 if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
596 *ec = U_ILLEGAL_ARGUMENT_ERROR;
597 return 0;
598 }
599
600 char buf[ISO_COUNTRY_CODE_LENGTH+1];
601 myUCharsToChars(buf, currency);
602
603 const UChar* s = NULL;
604 ec2 = U_ZERO_ERROR;
605 UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
606
607 rb = ures_getByKey(rb, CURRENCYPLURALS, rb, &ec2);
608
609 // Fetch resource with multi-level resource inheritance fallback
610 rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
611
612 s = ures_getStringByKeyWithFallback(rb, pluralCount, len, &ec2);
613 if (U_FAILURE(ec2)) {
614 // fall back to "other"
615 ec2 = U_ZERO_ERROR;
616 s = ures_getStringByKeyWithFallback(rb, "other", len, &ec2);
617 if (U_FAILURE(ec2)) {
618 ures_close(rb);
619 // fall back to long name in Currencies
620 return ucurr_getName(currency, locale, UCURR_LONG_NAME,
621 isChoiceFormat, len, ec);
622 }
623 }
624 ures_close(rb);
625
626 // If we've succeeded we're done. Otherwise, try to fallback.
627 // If that fails (because we are already at root) then exit.
628 if (U_SUCCESS(ec2)) {
629 if (ec2 == U_USING_DEFAULT_WARNING
630 || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
631 *ec = ec2;
632 }
633 U_ASSERT(s != NULL);
634 return s;
635 }
636
637 // If we fail to find a match, use the ISO 4217 code
638 *len = u_strlen(currency); // Should == ISO_COUNTRY_CODE_LENGTH, but maybe not...?
639 *ec = U_USING_DEFAULT_WARNING;
640 return currency;
641 }
642
643
644 //========================================================================
645 // Following are structure and function for parsing currency names
646
647 #define NEED_TO_BE_DELETED 0x1
648
649 // TODO: a better way to define this?
650 #define MAX_CURRENCY_NAME_LEN 100
651
652 typedef struct {
653 const char* IsoCode; // key
654 UChar* currencyName; // value
655 int32_t currencyNameLen; // value length
656 int32_t flag; // flags
657 } CurrencyNameStruct;
658
659
660 #ifndef MIN
661 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
662 #endif
663
664 #ifndef MAX
665 #define MAX(a,b) (((a)<(b)) ? (b) : (a))
666 #endif
667
668
669 // Comparason function used in quick sort.
670 static int U_CALLCONV currencyNameComparator(const void* a, const void* b) {
671 const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
672 const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b;
673 for (int32_t i = 0;
674 i < MIN(currName_1->currencyNameLen, currName_2->currencyNameLen);
675 ++i) {
676 if (currName_1->currencyName[i] < currName_2->currencyName[i]) {
677 return -1;
678 }
679 if (currName_1->currencyName[i] > currName_2->currencyName[i]) {
680 return 1;
681 }
682 }
683 if (currName_1->currencyNameLen < currName_2->currencyNameLen) {
684 return -1;
685 } else if (currName_1->currencyNameLen > currName_2->currencyNameLen) {
686 return 1;
687 }
688 return 0;
689 }
690
691
692 // Give a locale, return the maximum number of currency names associated with
693 // this locale.
694 // It gets currency names from resource bundles using fallback.
695 // It is the maximum number because in the fallback chain, some of the
696 // currency names are duplicated.
697 // For example, given locale as "en_US", the currency names get from resource
698 // bundle in "en_US" and "en" are duplicated. The fallback mechanism will count
699 // all currency names in "en_US" and "en".
700 static void
701 getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_t* total_currency_symbol_count) {
702 U_NAMESPACE_USE
703 *total_currency_name_count = 0;
704 *total_currency_symbol_count = 0;
705 const UChar* s = NULL;
706 char locale[ULOC_FULLNAME_CAPACITY];
707 uprv_strcpy(locale, loc);
708 for (;;) {
709 UErrorCode ec2 = U_ZERO_ERROR;
710 // TODO: ures_openDirect?
711 UResourceBundle* rb = ures_open(U_ICUDATA_CURR, locale, &ec2);
712 UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
713 int32_t n = ures_getSize(curr);
714 for (int32_t i=0; i<n; ++i) {
715 UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
716 int32_t len;
717 s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
718 UBool isChoice = FALSE;
719 if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
720 ++s;
721 --len;
722 if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
723 isChoice = TRUE;
724 }
725 }
726 if (isChoice) {
727 ChoiceFormat fmt(s, ec2);
728 int32_t fmt_count;
729 fmt.getFormats(fmt_count);
730 *total_currency_symbol_count += fmt_count;
731 } else {
732 ++(*total_currency_symbol_count); // currency symbol
733 }
734
735 ++(*total_currency_symbol_count); // iso code
736 ++(*total_currency_name_count); // long name
737 ures_close(names);
738 }
739
740 // currency plurals
741 UErrorCode ec3 = U_ZERO_ERROR;
742 UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
743 n = ures_getSize(curr_p);
744 for (int32_t i=0; i<n; ++i) {
745 UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
746 *total_currency_name_count += ures_getSize(names);
747 ures_close(names);
748 }
749 ures_close(curr_p);
750 ures_close(curr);
751 ures_close(rb);
752
753 if (!fallback(locale)) {
754 break;
755 }
756 }
757 }
758
759 // TODO: locale dependent
760 static UChar*
761 toUpperCase(const UChar* source, int32_t len) {
762 UChar* dest = NULL;
763 UErrorCode ec = U_ZERO_ERROR;
764 int32_t destLen = u_strToUpper(dest, 0, source, len, NULL, &ec);
765
766 ec = U_ZERO_ERROR;
767 dest = (UChar*)uprv_malloc(sizeof(UChar) * MAX(destLen, len));
768 u_strToUpper(dest, destLen, source, len, NULL, &ec);
769 if (U_FAILURE(ec)) {
770 uprv_memcpy(dest, source, sizeof(UChar) * len);
771 }
772 return dest;
773 }
774
775
776 // Collect all available currency names associated with the give locale
777 // (enable fallback chain).
778 // Read currenc names defined in resource bundle "Currencies" and
779 // "CurrencyPlural", enable fallback chain.
780 // return the malloc-ed currency name arrays and the total number of currency
781 // names in the array.
782 static void
783 collectCurrencyNames(const char* locale,
784 CurrencyNameStruct** currencyNames,
785 int32_t* total_currency_name_count,
786 CurrencyNameStruct** currencySymbols,
787 int32_t* total_currency_symbol_count,
788 UErrorCode& ec) {
789 U_NAMESPACE_USE
790 // Look up the Currencies resource for the given locale.
791 UErrorCode ec2 = U_ZERO_ERROR;
792
793 char loc[ULOC_FULLNAME_CAPACITY];
794 uloc_getName(locale, loc, sizeof(loc), &ec2);
795 if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
796 ec = U_ILLEGAL_ARGUMENT_ERROR;
797 }
798
799 // Get maximum currency name count first.
800 getCurrencyNameCount(loc, total_currency_name_count, total_currency_symbol_count);
801
802 *currencyNames = (CurrencyNameStruct*)uprv_malloc
803 (sizeof(CurrencyNameStruct) * (*total_currency_name_count));
804 *currencySymbols = (CurrencyNameStruct*)uprv_malloc
805 (sizeof(CurrencyNameStruct) * (*total_currency_symbol_count));
806
807 const UChar* s = NULL; // currency name
808 char* iso = NULL; // currency ISO code
809
810 *total_currency_name_count = 0;
811 *total_currency_symbol_count = 0;
812
813 UErrorCode ec3 = U_ZERO_ERROR;
814 UErrorCode ec4 = U_ZERO_ERROR;
815
816 // Using hash to remove duplicates caused by locale fallback
817 UHashtable* currencyIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec3);
818 UHashtable* currencyPluralIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec4);
819 for (int32_t localeLevel = 0; ; ++localeLevel) {
820 ec2 = U_ZERO_ERROR;
821 // TODO: ures_openDirect
822 UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
823 UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
824 int32_t n = ures_getSize(curr);
825 for (int32_t i=0; i<n; ++i) {
826 UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
827 int32_t len;
828 s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
829 // TODO: uhash_put wont change key/value?
830 iso = (char*)ures_getKey(names);
831 if (localeLevel == 0) {
832 uhash_put(currencyIsoCodes, iso, iso, &ec3);
833 } else {
834 if (uhash_get(currencyIsoCodes, iso) != NULL) {
835 ures_close(names);
836 continue;
837 } else {
838 uhash_put(currencyIsoCodes, iso, iso, &ec3);
839 }
840 }
841 UBool isChoice = FALSE;
842 if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
843 ++s;
844 --len;
845 if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
846 isChoice = TRUE;
847 }
848 }
849 if (isChoice) {
850 ChoiceFormat fmt(s, ec2);
851 int32_t fmt_count;
852 const UnicodeString* formats = fmt.getFormats(fmt_count);
853 for (int i = 0; i < fmt_count; ++i) {
854 // put iso, formats[i]; into array
855 int32_t length = formats[i].length();
856 UChar* name = (UChar*)uprv_malloc(sizeof(UChar)*length);
857 formats[i].extract(0, length, name);
858 (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
859 (*currencySymbols)[*total_currency_symbol_count].currencyName = name;
860 (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
861 (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = length;
862 }
863 } else {
864 // Add currency symbol.
865 (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
866 (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s;
867 (*currencySymbols)[*total_currency_symbol_count].flag = 0;
868 (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
869 }
870
871 // Add currency long name.
872 s = ures_getStringByIndex(names, UCURR_LONG_NAME, &len, &ec2);
873 (*currencyNames)[*total_currency_name_count].IsoCode = iso;
874 UChar* upperName = toUpperCase(s, len);
875 (*currencyNames)[*total_currency_name_count].currencyName = upperName;
876 (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
877 (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
878
879 // put (iso, 3, and iso) in to array
880 // Add currency ISO code.
881 (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
882 (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
883 // Must convert iso[] into Unicode
884 u_charsToUChars(iso, (*currencySymbols)[*total_currency_symbol_count].currencyName, 3);
885 (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
886 (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = 3;
887
888 ures_close(names);
889 }
890
891 // currency plurals
892 UErrorCode ec3 = U_ZERO_ERROR;
893 UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
894 n = ures_getSize(curr_p);
895 for (int32_t i=0; i<n; ++i) {
896 UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
897 iso = (char*)ures_getKey(names);
898 // Using hash to remove duplicated ISO codes in fallback chain.
899 if (localeLevel == 0) {
900 uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
901 } else {
902 if (uhash_get(currencyPluralIsoCodes, iso) != NULL) {
903 ures_close(names);
904 continue;
905 } else {
906 uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
907 }
908 }
909 int32_t num = ures_getSize(names);
910 int32_t len;
911 for (int32_t j = 0; j < num; ++j) {
912 // TODO: remove duplicates between singular name and
913 // currency long name?
914 s = ures_getStringByIndex(names, j, &len, &ec3);
915 (*currencyNames)[*total_currency_name_count].IsoCode = iso;
916 UChar* upperName = toUpperCase(s, len);
917 (*currencyNames)[*total_currency_name_count].currencyName = upperName;
918 (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
919 (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
920 }
921 ures_close(names);
922 }
923 ures_close(curr_p);
924 ures_close(curr);
925 ures_close(rb);
926
927 if (!fallback(loc)) {
928 break;
929 }
930 }
931
932 uhash_close(currencyIsoCodes);
933 uhash_close(currencyPluralIsoCodes);
934
935 // quick sort the struct
936 qsort(*currencyNames, *total_currency_name_count,
937 sizeof(CurrencyNameStruct), currencyNameComparator);
938 qsort(*currencySymbols, *total_currency_symbol_count,
939 sizeof(CurrencyNameStruct), currencyNameComparator);
940
941 #ifdef UCURR_DEBUG
942 printf("currency name count: %d\n", *total_currency_name_count);
943 for (int32_t index = 0; index < *total_currency_name_count; ++index) {
944 printf("index: %d\n", index);
945 printf("iso: %s\n", (*currencyNames)[index].IsoCode);
946 printf("currencyName:");
947 for (int32_t i = 0; i < (*currencyNames)[index].currencyNameLen; ++i) {
948 printf("%c", (unsigned char)(*currencyNames)[index].currencyName[i]);
949 }
950 printf("\n");
951 printf("len: %d\n", (*currencyNames)[index].currencyNameLen);
952 }
953 printf("currency symbol count: %d\n", *total_currency_symbol_count);
954 for (int32_t index = 0; index < *total_currency_symbol_count; ++index) {
955 printf("index: %d\n", index);
956 printf("iso: %s\n", (*currencySymbols)[index].IsoCode);
957 printf("currencySymbol:");
958 for (int32_t i = 0; i < (*currencySymbols)[index].currencyNameLen; ++i) {
959 printf("%c", (unsigned char)(*currencySymbols)[index].currencyName[i]);
960 }
961 printf("\n");
962 printf("len: %d\n", (*currencySymbols)[index].currencyNameLen);
963 }
964 #endif
965 }
966
967 // @param currencyNames: currency names array
968 // @param indexInCurrencyNames: the index of the character in currency names
969 // array against which the comparison is done
970 // @param key: input text char to compare against
971 // @param begin(IN/OUT): the begin index of matching range in currency names array
972 // @param end(IN/OUT): the end index of matching range in currency names array.
973 static int32_t
974 binarySearch(const CurrencyNameStruct* currencyNames,
975 int32_t indexInCurrencyNames,
976 const UChar key,
977 int32_t* begin, int32_t* end) {
978 #ifdef UCURR_DEBUG
979 printf("key = %x\n", key);
980 #endif
981 int32_t first = *begin;
982 int32_t last = *end;
983 while (first <= last) {
984 int32_t mid = (first + last) / 2; // compute mid point.
985 if (indexInCurrencyNames >= currencyNames[mid].currencyNameLen) {
986 first = mid + 1;
987 } else {
988 if (key > currencyNames[mid].currencyName[indexInCurrencyNames]) {
989 first = mid + 1;
990 }
991 else if (key < currencyNames[mid].currencyName[indexInCurrencyNames]) {
992 last = mid - 1;
993 }
994 else {
995 // Find a match, and looking for ranges
996 // Now do two more binary searches. First, on the left side for
997 // the greatest L such that CurrencyNameStruct[L] < key.
998 int32_t L = *begin;
999 int32_t R = mid;
1000
1001 #ifdef UCURR_DEBUG
1002 printf("mid = %d\n", mid);
1003 #endif
1004 while (L < R) {
1005 int32_t M = (L + R) / 2;
1006 #ifdef UCURR_DEBUG
1007 printf("L = %d, R = %d, M = %d\n", L, R, M);
1008 #endif
1009 if (indexInCurrencyNames >= currencyNames[M].currencyNameLen) {
1010 L = M + 1;
1011 } else {
1012 if (currencyNames[M].currencyName[indexInCurrencyNames] < key) {
1013 L = M + 1;
1014 } else {
1015 #ifdef UCURR_DEBUG
1016 U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
1017 #endif
1018 R = M;
1019 }
1020 }
1021 }
1022 #ifdef UCURR_DEBUG
1023 U_ASSERT(L == R);
1024 #endif
1025 *begin = L;
1026 #ifdef UCURR_DEBUG
1027 printf("begin = %d\n", *begin);
1028 U_ASSERT(currencyNames[*begin].currencyName[indexInCurrencyNames] == key);
1029 #endif
1030
1031 // Now for the second search, finding the least R such that
1032 // key < CurrencyNameStruct[R].
1033 L = mid;
1034 R = *end;
1035 while (L < R) {
1036 int32_t M = (L + R) / 2;
1037 #ifdef UCURR_DEBUG
1038 printf("L = %d, R = %d, M = %d\n", L, R, M);
1039 #endif
1040 if (currencyNames[M].currencyNameLen < indexInCurrencyNames) {
1041 L = M + 1;
1042 } else {
1043 if (currencyNames[M].currencyName[indexInCurrencyNames] > key) {
1044 R = M;
1045 } else {
1046 #ifdef UCURR_DEBUG
1047 U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
1048 #endif
1049 L = M + 1;
1050 }
1051 }
1052 }
1053 #ifdef UCURR_DEBUG
1054 U_ASSERT(L == R);
1055 #endif
1056 if (currencyNames[R].currencyName[indexInCurrencyNames] > key) {
1057 *end = R - 1;
1058 } else {
1059 *end = R;
1060 }
1061 #ifdef UCURR_DEBUG
1062 printf("end = %d\n", *end);
1063 #endif
1064
1065 // now, found the range. check whether there is exact match
1066 if (currencyNames[*begin].currencyNameLen == indexInCurrencyNames + 1) {
1067 return *begin; // find range and exact match.
1068 }
1069 return -1; // find range, but no exact match.
1070 }
1071 }
1072 }
1073 *begin = -1;
1074 *end = -1;
1075 return -1; // failed to find range.
1076 }
1077
1078
1079 // Linear search "text" in "currencyNames".
1080 // @param begin, end: the begin and end index in currencyNames, within which
1081 // range should the search be performed.
1082 // @param textLen: the length of the text to be compared
1083 // @param maxMatchLen(IN/OUT): passing in the computed max matching length
1084 // pass out the new max matching length
1085 // @param maxMatchIndex: the index in currencyName which has the longest
1086 // match with input text.
1087 static void
1088 linearSearch(const CurrencyNameStruct* currencyNames,
1089 int32_t begin, int32_t end,
1090 const UChar* text, int32_t textLen,
1091 int32_t *maxMatchLen, int32_t* maxMatchIndex) {
1092 for (int32_t index = begin; index <= end; ++index) {
1093 int32_t len = currencyNames[index].currencyNameLen;
1094 if (len > *maxMatchLen && len <= textLen &&
1095 uprv_memcmp(currencyNames[index].currencyName, text, len * sizeof(UChar)) == 0) {
1096 *maxMatchIndex = index;
1097 *maxMatchLen = len;
1098 #ifdef UCURR_DEBUG
1099 printf("maxMatchIndex = %d, maxMatchLen = %d\n",
1100 *maxMatchIndex, *maxMatchLen);
1101 #endif
1102 }
1103 }
1104 }
1105
1106 #define LINEAR_SEARCH_THRESHOLD 10
1107
1108 // Find longest match between "text" and currency names in "currencyNames".
1109 // @param total_currency_count: total number of currency names in CurrencyNames.
1110 // @param textLen: the length of the text to be compared
1111 // @param maxMatchLen: passing in the computed max matching length
1112 // pass out the new max matching length
1113 // @param maxMatchIndex: the index in currencyName which has the longest
1114 // match with input text.
1115 static void
1116 searchCurrencyName(const CurrencyNameStruct* currencyNames,
1117 int32_t total_currency_count,
1118 const UChar* text, int32_t textLen,
1119 int32_t* maxMatchLen, int32_t* maxMatchIndex) {
1120 *maxMatchIndex = -1;
1121 *maxMatchLen = 0;
1122 int32_t matchIndex = -1;
1123 int32_t binarySearchBegin = 0;
1124 int32_t binarySearchEnd = total_currency_count - 1;
1125 // It is a variant of binary search.
1126 // For example, given the currency names in currencyNames array are:
1127 // A AB ABC AD AZ B BB BBEX BBEXYZ BS C D E....
1128 // and the input text is BBEXST
1129 // The first round binary search search "B" in the text against
1130 // the first char in currency names, and find the first char matching range
1131 // to be "B BB BBEX BBEXYZ BS" (and the maximum matching "B").
1132 // The 2nd round binary search search the second "B" in the text against
1133 // the 2nd char in currency names, and narrow the matching range to
1134 // "BB BBEX BBEXYZ" (and the maximum matching "BB").
1135 // The 3rd round returnes the range as "BBEX BBEXYZ" (without changing
1136 // maximum matching).
1137 // The 4th round returns the same range (the maximum matching is "BBEX").
1138 // The 5th round returns no matching range.
1139 for (int32_t index = 0; index < textLen; ++index) {
1140 // matchIndex saves the one with exact match till the current point.
1141 // [binarySearchBegin, binarySearchEnd] saves the matching range.
1142 matchIndex = binarySearch(currencyNames, index,
1143 text[index],
1144 &binarySearchBegin, &binarySearchEnd);
1145 if (binarySearchBegin == -1) { // did not find the range
1146 break;
1147 }
1148 if (matchIndex != -1) {
1149 // find an exact match for text from text[0] to text[index]
1150 // in currencyNames array.
1151 *maxMatchLen = index + 1;
1152 *maxMatchIndex = matchIndex;
1153 }
1154 if (binarySearchEnd - binarySearchBegin < LINEAR_SEARCH_THRESHOLD) {
1155 // linear search if within threshold.
1156 linearSearch(currencyNames, binarySearchBegin, binarySearchEnd,
1157 text, textLen,
1158 maxMatchLen, maxMatchIndex);
1159 break;
1160 }
1161 }
1162 return;
1163 }
1164
1165 //========================= currency name cache =====================
1166 typedef struct {
1167 char locale[ULOC_FULLNAME_CAPACITY]; //key
1168 // currency names, case insensitive
1169 CurrencyNameStruct* currencyNames; // value
1170 int32_t totalCurrencyNameCount; // currency name count
1171 // currency symbols and ISO code, case sensitive
1172 CurrencyNameStruct* currencySymbols; // value
1173 int32_t totalCurrencySymbolCount; // count
1174 // reference count.
1175 // reference count is set to 1 when an entry is put to cache.
1176 // it increases by 1 before accessing, and decreased by 1 after accessing.
1177 // The entry is deleted when ref count is zero, which means
1178 // the entry is replaced out of cache and no process is accessing it.
1179 int32_t refCount;
1180 } CurrencyNameCacheEntry;
1181
1182
1183 #define CURRENCY_NAME_CACHE_NUM 10
1184
1185 // Reserve 10 cache entries.
1186 static CurrencyNameCacheEntry* currCache[CURRENCY_NAME_CACHE_NUM] = {NULL};
1187 // Using an index to indicate which entry to be replaced when cache is full.
1188 // It is a simple round-robin replacement strategy.
1189 static int8_t currentCacheEntryIndex = 0;
1190
1191 // Cache deletion
1192 static void
1193 deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
1194 for (int32_t index = 0; index < count; ++index) {
1195 if ( (currencyNames[index].flag & NEED_TO_BE_DELETED) ) {
1196 uprv_free(currencyNames[index].currencyName);
1197 }
1198 }
1199 uprv_free(currencyNames);
1200 }
1201
1202
1203 static void
1204 deleteCacheEntry(CurrencyNameCacheEntry* entry) {
1205 deleteCurrencyNames(entry->currencyNames, entry->totalCurrencyNameCount);
1206 deleteCurrencyNames(entry->currencySymbols, entry->totalCurrencySymbolCount);
1207 uprv_free(entry);
1208 }
1209
1210
1211 // Cache clean up
1212 static UBool U_CALLCONV
1213 currency_cache_cleanup(void) {
1214 for (int32_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
1215 if (currCache[i]) {
1216 deleteCacheEntry(currCache[i]);
1217 currCache[i] = 0;
1218 }
1219 }
1220 return TRUE;
1221 }
1222
1223
1224 U_CFUNC void
1225 uprv_parseCurrency(const char* locale,
1226 const U_NAMESPACE_QUALIFIER UnicodeString& text,
1227 U_NAMESPACE_QUALIFIER ParsePosition& pos,
1228 int8_t type,
1229 UChar* result,
1230 UErrorCode& ec)
1231 {
1232 U_NAMESPACE_USE
1233
1234 if (U_FAILURE(ec)) {
1235 return;
1236 }
1237
1238 int32_t total_currency_name_count = 0;
1239 CurrencyNameStruct* currencyNames = NULL;
1240 int32_t total_currency_symbol_count = 0;
1241 CurrencyNameStruct* currencySymbols = NULL;
1242 CurrencyNameCacheEntry* cacheEntry = NULL;
1243
1244 umtx_lock(NULL);
1245 // in order to handle racing correctly,
1246 // not putting 'search' in a separate function and using UMTX.
1247 int8_t found = -1;
1248 for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
1249 if (currCache[i]!= NULL &&
1250 uprv_strcmp(locale, currCache[i]->locale) == 0) {
1251 found = i;
1252 break;
1253 }
1254 }
1255 if (found != -1) {
1256 cacheEntry = currCache[found];
1257 currencyNames = cacheEntry->currencyNames;
1258 total_currency_name_count = cacheEntry->totalCurrencyNameCount;
1259 currencySymbols = cacheEntry->currencySymbols;
1260 total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
1261 ++(cacheEntry->refCount);
1262 }
1263 umtx_unlock(NULL);
1264 if (found == -1) {
1265 collectCurrencyNames(locale, &currencyNames, &total_currency_name_count, &currencySymbols, &total_currency_symbol_count, ec);
1266 if (U_FAILURE(ec)) {
1267 return;
1268 }
1269 umtx_lock(NULL);
1270 // check again.
1271 int8_t found = -1;
1272 for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
1273 if (currCache[i]!= NULL &&
1274 uprv_strcmp(locale, currCache[i]->locale) == 0) {
1275 found = i;
1276 break;
1277 }
1278 }
1279 if (found == -1) {
1280 // insert new entry to
1281 // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
1282 // and remove the existing entry
1283 // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
1284 // from cache.
1285 cacheEntry = currCache[currentCacheEntryIndex];
1286 if (cacheEntry) {
1287 --(cacheEntry->refCount);
1288 // delete if the ref count is zero
1289 if (cacheEntry->refCount == 0) {
1290 deleteCacheEntry(cacheEntry);
1291 }
1292 }
1293 cacheEntry = (CurrencyNameCacheEntry*)uprv_malloc(sizeof(CurrencyNameCacheEntry));
1294 currCache[currentCacheEntryIndex] = cacheEntry;
1295 uprv_strcpy(cacheEntry->locale, locale);
1296 cacheEntry->currencyNames = currencyNames;
1297 cacheEntry->totalCurrencyNameCount = total_currency_name_count;
1298 cacheEntry->currencySymbols = currencySymbols;
1299 cacheEntry->totalCurrencySymbolCount = total_currency_symbol_count;
1300 cacheEntry->refCount = 2; // one for cache, one for reference
1301 currentCacheEntryIndex = (currentCacheEntryIndex + 1) % CURRENCY_NAME_CACHE_NUM;
1302 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cache_cleanup);
1303
1304 } else {
1305 deleteCurrencyNames(currencyNames, total_currency_name_count);
1306 deleteCurrencyNames(currencySymbols, total_currency_symbol_count);
1307 cacheEntry = currCache[found];
1308 currencyNames = cacheEntry->currencyNames;
1309 total_currency_name_count = cacheEntry->totalCurrencyNameCount;
1310 currencySymbols = cacheEntry->currencySymbols;
1311 total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
1312 ++(cacheEntry->refCount);
1313 }
1314 umtx_unlock(NULL);
1315 }
1316
1317 int32_t start = pos.getIndex();
1318
1319 UChar inputText[MAX_CURRENCY_NAME_LEN];
1320 UChar upperText[MAX_CURRENCY_NAME_LEN];
1321 int32_t textLen = MIN(MAX_CURRENCY_NAME_LEN, text.length() - start);
1322 text.extract(start, textLen, inputText);
1323 UErrorCode ec1 = U_ZERO_ERROR;
1324 textLen = u_strToUpper(upperText, MAX_CURRENCY_NAME_LEN, inputText, textLen, NULL, &ec1);
1325
1326 int32_t max = 0;
1327 int32_t matchIndex = -1;
1328 // case in-sensitive comparision against currency names
1329 searchCurrencyName(currencyNames, total_currency_name_count,
1330 upperText, textLen, &max, &matchIndex);
1331
1332 #ifdef UCURR_DEBUG
1333 printf("search in names, max = %d, matchIndex = %d\n", max, matchIndex);
1334 #endif
1335
1336 int32_t maxInSymbol = 0;
1337 int32_t matchIndexInSymbol = -1;
1338 if (type != UCURR_LONG_NAME) { // not name only
1339 // case sensitive comparison against currency symbols and ISO code.
1340 searchCurrencyName(currencySymbols, total_currency_symbol_count,
1341 inputText, textLen,
1342 &maxInSymbol, &matchIndexInSymbol);
1343 }
1344
1345 #ifdef UCURR_DEBUG
1346 printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol);
1347 #endif
1348
1349 if (max >= maxInSymbol && matchIndex != -1) {
1350 u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4);
1351 pos.setIndex(start + max);
1352 } else if (maxInSymbol >= max && matchIndexInSymbol != -1) {
1353 u_charsToUChars(currencySymbols[matchIndexInSymbol].IsoCode, result, 4);
1354 pos.setIndex(start + maxInSymbol);
1355 }
1356
1357 // decrease reference count
1358 umtx_lock(NULL);
1359 --(cacheEntry->refCount);
1360 if (cacheEntry->refCount == 0) { // remove
1361 deleteCacheEntry(cacheEntry);
1362 }
1363 umtx_unlock(NULL);
1364 }
1365
1366
1367 /**
1368 * Internal method. Given a currency ISO code and a locale, return
1369 * the "static" currency name. This is usually the same as the
1370 * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
1371 * format is applied to the number 2.0 (to yield the more common
1372 * plural) to return a static name.
1373 *
1374 * This is used for backward compatibility with old currency logic in
1375 * DecimalFormat and DecimalFormatSymbols.
1376 */
1377 U_CFUNC void
1378 uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
1379 U_NAMESPACE_QUALIFIER UnicodeString& result, UErrorCode& ec)
1380 {
1381 U_NAMESPACE_USE
1382
1383 UBool isChoiceFormat;
1384 int32_t len;
1385 const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME,
1386 &isChoiceFormat, &len, &ec);
1387 if (U_SUCCESS(ec)) {
1388 // If this is a ChoiceFormat currency, then format an
1389 // arbitrary value; pick something != 1; more common.
1390 result.truncate(0);
1391 if (isChoiceFormat) {
1392 ChoiceFormat f(currname, ec);
1393 if (U_SUCCESS(ec)) {
1394 f.format(2.0, result);
1395 } else {
1396 result = iso;
1397 }
1398 } else {
1399 result = currname;
1400 }
1401 }
1402 }
1403
1404 U_CAPI int32_t U_EXPORT2
1405 ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) {
1406 return (_findMetaData(currency, *ec))[0];
1407 }
1408
1409 U_CAPI double U_EXPORT2
1410 ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) {
1411 const int32_t *data = _findMetaData(currency, *ec);
1412
1413 // If the meta data is invalid, return 0.0.
1414 if (data[0] < 0 || data[0] > MAX_POW10) {
1415 if (U_SUCCESS(*ec)) {
1416 *ec = U_INVALID_FORMAT_ERROR;
1417 }
1418 return 0.0;
1419 }
1420
1421 // If there is no rounding, return 0.0 to indicate no rounding. A
1422 // rounding value (data[1]) of 0 or 1 indicates no rounding.
1423 if (data[1] < 2) {
1424 return 0.0;
1425 }
1426
1427 // Return data[1] / 10^(data[0]). The only actual rounding data,
1428 // as of this writing, is CHF { 2, 5 }.
1429 return double(data[1]) / POW10[data[0]];
1430 }
1431
1432 U_CDECL_BEGIN
1433
1434 typedef struct UCurrencyContext {
1435 uint32_t currType; /* UCurrCurrencyType */
1436 uint32_t listIdx;
1437 } UCurrencyContext;
1438
1439 /*
1440 Please keep this list in alphabetical order.
1441 You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
1442 of these items.
1443 ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
1444 */
1445 static const struct CurrencyList {
1446 const char *currency;
1447 uint32_t currType;
1448 } gCurrencyList[] = {
1449 {"ADP", UCURR_COMMON|UCURR_DEPRECATED},
1450 {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED},
1451 {"AFA", UCURR_COMMON|UCURR_DEPRECATED},
1452 {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1453 {"ALK", UCURR_COMMON|UCURR_DEPRECATED},
1454 {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1455 {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1456 {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1457 {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED},
1458 {"AOK", UCURR_COMMON|UCURR_DEPRECATED},
1459 {"AON", UCURR_COMMON|UCURR_DEPRECATED},
1460 {"AOR", UCURR_COMMON|UCURR_DEPRECATED},
1461 {"ARA", UCURR_COMMON|UCURR_DEPRECATED},
1462 {"ARL", UCURR_COMMON|UCURR_DEPRECATED},
1463 {"ARM", UCURR_COMMON|UCURR_DEPRECATED},
1464 {"ARP", UCURR_COMMON|UCURR_DEPRECATED},
1465 {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1466 {"ATS", UCURR_COMMON|UCURR_DEPRECATED},
1467 {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1468 {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1469 {"AZM", UCURR_COMMON|UCURR_DEPRECATED},
1470 {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1471 {"BAD", UCURR_COMMON|UCURR_DEPRECATED},
1472 {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED},
1473 {"BAN", UCURR_COMMON|UCURR_DEPRECATED},
1474 {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1475 {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED},
1476 {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED},
1477 {"BEF", UCURR_COMMON|UCURR_DEPRECATED},
1478 {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED},
1479 {"BGL", UCURR_COMMON|UCURR_DEPRECATED},
1480 {"BGM", UCURR_COMMON|UCURR_DEPRECATED},
1481 {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1482 {"BGO", UCURR_COMMON|UCURR_DEPRECATED},
1483 {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1484 {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1485 {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1486 {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED},
1487 {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1488 {"BOL", UCURR_COMMON|UCURR_DEPRECATED},
1489 {"BOP", UCURR_COMMON|UCURR_DEPRECATED},
1490 {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1491 {"BRB", UCURR_COMMON|UCURR_DEPRECATED},
1492 {"BRC", UCURR_COMMON|UCURR_DEPRECATED},
1493 {"BRE", UCURR_COMMON|UCURR_DEPRECATED},
1494 {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1495 {"BRN", UCURR_COMMON|UCURR_DEPRECATED},
1496 {"BRR", UCURR_COMMON|UCURR_DEPRECATED},
1497 {"BRZ", UCURR_COMMON|UCURR_DEPRECATED},
1498 {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1499 {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1500 {"BUK", UCURR_COMMON|UCURR_DEPRECATED},
1501 {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1502 {"BYB", UCURR_COMMON|UCURR_DEPRECATED},
1503 {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1504 {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1505 {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1506 {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1507 {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1508 {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1509 {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1510 {"CLE", UCURR_COMMON|UCURR_DEPRECATED},
1511 {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1512 {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1513 {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED},
1514 {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED},
1515 {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1516 {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1517 {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED},
1518 {"CSD", UCURR_COMMON|UCURR_DEPRECATED},
1519 {"CSK", UCURR_COMMON|UCURR_DEPRECATED},
1520 {"CUC", UCURR_COMMON|UCURR_NON_DEPRECATED},
1521 {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1522 {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED},
1523 {"CYP", UCURR_COMMON|UCURR_DEPRECATED},
1524 {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1525 {"DDM", UCURR_COMMON|UCURR_DEPRECATED},
1526 {"DEM", UCURR_COMMON|UCURR_DEPRECATED},
1527 {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1528 {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1529 {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1530 {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1531 {"ECS", UCURR_COMMON|UCURR_DEPRECATED},
1532 {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED},
1533 {"EEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1534 {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1535 {"EQE", UCURR_COMMON|UCURR_DEPRECATED},
1536 {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1537 {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
1538 {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
1539 {"ESP", UCURR_COMMON|UCURR_DEPRECATED},
1540 {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1541 {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1542 {"FIM", UCURR_COMMON|UCURR_DEPRECATED},
1543 {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1544 {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1545 {"FRF", UCURR_COMMON|UCURR_DEPRECATED},
1546 {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1547 {"GEK", UCURR_COMMON|UCURR_DEPRECATED},
1548 {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1549 {"GHC", UCURR_COMMON|UCURR_DEPRECATED},
1550 {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1551 {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1552 {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1553 {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1554 {"GNS", UCURR_COMMON|UCURR_DEPRECATED},
1555 {"GQE", UCURR_COMMON|UCURR_DEPRECATED},
1556 {"GRD", UCURR_COMMON|UCURR_DEPRECATED},
1557 {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
1558 {"GWE", UCURR_COMMON|UCURR_DEPRECATED},
1559 {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1560 {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1561 {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1562 {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1563 {"HRD", UCURR_COMMON|UCURR_DEPRECATED},
1564 {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1565 {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1566 {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1567 {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1568 {"IEP", UCURR_COMMON|UCURR_DEPRECATED},
1569 {"ILP", UCURR_COMMON|UCURR_DEPRECATED},
1570 {"ILR", UCURR_COMMON|UCURR_DEPRECATED},
1571 {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1572 {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1573 {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1574 {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1575 {"ISJ", UCURR_COMMON|UCURR_DEPRECATED},
1576 {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1577 {"ITL", UCURR_COMMON|UCURR_DEPRECATED},
1578 {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1579 {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1580 {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED},
1581 {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED},
1582 {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1583 {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1584 {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1585 {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED},
1586 {"KRH", UCURR_COMMON|UCURR_DEPRECATED},
1587 {"KRO", UCURR_COMMON|UCURR_DEPRECATED},
1588 {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED},
1589 {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1590 {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1591 {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED},
1592 {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1593 {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1594 {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1595 {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1596 {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1597 {"LSM", UCURR_COMMON|UCURR_DEPRECATED},
1598 {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1599 {"LTT", UCURR_COMMON|UCURR_DEPRECATED},
1600 {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED},
1601 {"LUF", UCURR_COMMON|UCURR_DEPRECATED},
1602 {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED},
1603 {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1604 {"LVR", UCURR_COMMON|UCURR_DEPRECATED},
1605 {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1606 {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1607 {"MAF", UCURR_COMMON|UCURR_DEPRECATED},
1608 {"MCF", UCURR_COMMON|UCURR_DEPRECATED},
1609 {"MDC", UCURR_COMMON|UCURR_DEPRECATED},
1610 {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1611 {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED},
1612 {"MGF", UCURR_COMMON|UCURR_DEPRECATED},
1613 {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1614 {"MKN", UCURR_COMMON|UCURR_DEPRECATED},
1615 {"MLF", UCURR_COMMON|UCURR_DEPRECATED},
1616 {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1617 {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED},
1618 {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1619 {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED},
1620 {"MTL", UCURR_COMMON|UCURR_DEPRECATED},
1621 {"MTP", UCURR_COMMON|UCURR_DEPRECATED},
1622 {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1623 {"MVP", UCURR_COMMON|UCURR_DEPRECATED},
1624 {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1625 {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1626 {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1627 {"MXP", UCURR_COMMON|UCURR_DEPRECATED},
1628 {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1629 {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1630 {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED},
1631 {"MZM", UCURR_COMMON|UCURR_DEPRECATED},
1632 {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1633 {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1634 {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1635 {"NIC", UCURR_COMMON|UCURR_DEPRECATED},
1636 {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED},
1637 {"NLG", UCURR_COMMON|UCURR_DEPRECATED},
1638 {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1639 {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1640 {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1641 {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1642 {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1643 {"PEI", UCURR_COMMON|UCURR_DEPRECATED},
1644 {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1645 {"PES", UCURR_COMMON|UCURR_DEPRECATED},
1646 {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1647 {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1648 {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1649 {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1650 {"PLZ", UCURR_COMMON|UCURR_DEPRECATED},
1651 {"PTE", UCURR_COMMON|UCURR_DEPRECATED},
1652 {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1653 {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1654 {"RHD", UCURR_COMMON|UCURR_DEPRECATED},
1655 {"ROL", UCURR_COMMON|UCURR_DEPRECATED},
1656 {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED},
1657 {"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1658 {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1659 {"RUR", UCURR_COMMON|UCURR_DEPRECATED},
1660 {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1661 {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1662 {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1663 {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1664 {"SDD", UCURR_COMMON|UCURR_DEPRECATED},
1665 {"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1666 {"SDP", UCURR_COMMON|UCURR_DEPRECATED},
1667 {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1668 {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1669 {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1670 {"SIT", UCURR_COMMON|UCURR_DEPRECATED},
1671 {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1672 {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1673 {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1674 {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1675 {"SRG", UCURR_COMMON|UCURR_DEPRECATED},
1676 {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1677 {"SUR", UCURR_COMMON|UCURR_DEPRECATED},
1678 {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
1679 {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1680 {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1681 {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1682 {"TJR", UCURR_COMMON|UCURR_DEPRECATED},
1683 {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1684 {"TMM", UCURR_COMMON|UCURR_DEPRECATED},
1685 {"TMT", UCURR_COMMON|UCURR_NON_DEPRECATED},
1686 {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
1687 {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1688 {"TPE", UCURR_COMMON|UCURR_DEPRECATED},
1689 {"TRL", UCURR_COMMON|UCURR_DEPRECATED},
1690 {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
1691 {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1692 {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1693 {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1694 {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
1695 {"UAK", UCURR_COMMON|UCURR_DEPRECATED},
1696 {"UGS", UCURR_COMMON|UCURR_DEPRECATED},
1697 {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
1698 {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1699 {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1700 {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1701 {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1702 {"UYP", UCURR_COMMON|UCURR_DEPRECATED},
1703 {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
1704 {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1705 {"VEB", UCURR_COMMON|UCURR_DEPRECATED},
1706 {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1707 {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
1708 {"VNN", UCURR_COMMON|UCURR_DEPRECATED},
1709 {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
1710 {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
1711 {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1712 {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1713 {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1714 {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1715 {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1716 {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1717 {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1718 {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1719 {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1720 {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
1721 {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1722 {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1723 {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1724 {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1725 {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1726 {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1727 {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1728 {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1729 {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1730 {"YDD", UCURR_COMMON|UCURR_DEPRECATED},
1731 {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
1732 {"YUD", UCURR_COMMON|UCURR_DEPRECATED},
1733 {"YUM", UCURR_COMMON|UCURR_DEPRECATED},
1734 {"YUN", UCURR_COMMON|UCURR_DEPRECATED},
1735 {"YUR", UCURR_COMMON|UCURR_DEPRECATED},
1736 {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1737 {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1738 {"ZMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1739 {"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
1740 {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
1741 {"ZWL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1742 {"ZWR", UCURR_COMMON|UCURR_DEPRECATED},
1743 {"ZWD", UCURR_COMMON|UCURR_DEPRECATED},
1744 { NULL, 0 } // Leave here to denote the end of the list.
1745 };
1746
1747 #define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
1748 ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
1749
1750 static int32_t U_CALLCONV
1751 ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
1752 UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
1753 uint32_t currType = myContext->currType;
1754 int32_t count = 0;
1755
1756 /* Count the number of items matching the type we are looking for. */
1757 for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
1758 if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
1759 count++;
1760 }
1761 }
1762 return count;
1763 }
1764
1765 static const char* U_CALLCONV
1766 ucurr_nextCurrencyList(UEnumeration *enumerator,
1767 int32_t* resultLength,
1768 UErrorCode * /*pErrorCode*/)
1769 {
1770 UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
1771
1772 /* Find the next in the list that matches the type we are looking for. */
1773 while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) {
1774 const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
1775 if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
1776 {
1777 if (resultLength) {
1778 *resultLength = 3; /* Currency codes are only 3 chars long */
1779 }
1780 return currItem->currency;
1781 }
1782 }
1783 /* We enumerated too far. */
1784 if (resultLength) {
1785 *resultLength = 0;
1786 }
1787 return NULL;
1788 }
1789
1790 static void U_CALLCONV
1791 ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
1792 ((UCurrencyContext *)(enumerator->context))->listIdx = 0;
1793 }
1794
1795 static void U_CALLCONV
1796 ucurr_closeCurrencyList(UEnumeration *enumerator) {
1797 uprv_free(enumerator->context);
1798 uprv_free(enumerator);
1799 }
1800
1801 static const UEnumeration gEnumCurrencyList = {
1802 NULL,
1803 NULL,
1804 ucurr_closeCurrencyList,
1805 ucurr_countCurrencyList,
1806 uenum_unextDefault,
1807 ucurr_nextCurrencyList,
1808 ucurr_resetCurrencyList
1809 };
1810 U_CDECL_END
1811
1812 U_CAPI UEnumeration * U_EXPORT2
1813 ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
1814 UEnumeration *myEnum = NULL;
1815 UCurrencyContext *myContext;
1816
1817 myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
1818 if (myEnum == NULL) {
1819 *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
1820 return NULL;
1821 }
1822 uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
1823 myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
1824 if (myContext == NULL) {
1825 *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
1826 uprv_free(myEnum);
1827 return NULL;
1828 }
1829 myContext->currType = currType;
1830 myContext->listIdx = 0;
1831 myEnum->context = myContext;
1832 return myEnum;
1833 }
1834
1835 U_CAPI int32_t U_EXPORT2
1836 ucurr_countCurrencies(const char* locale,
1837 UDate date,
1838 UErrorCode* ec)
1839 {
1840 int32_t currCount = 0;
1841 int32_t resLen = 0;
1842
1843 if (ec != NULL && U_SUCCESS(*ec))
1844 {
1845 // local variables
1846 UErrorCode localStatus = U_ZERO_ERROR;
1847 char id[ULOC_FULLNAME_CAPACITY];
1848 resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
1849 // get country or country_variant in `id'
1850 /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
1851
1852 if (U_FAILURE(*ec))
1853 {
1854 return 0;
1855 }
1856
1857 // Remove variants, which is only needed for registration.
1858 char *idDelim = strchr(id, VAR_DELIM);
1859 if (idDelim)
1860 {
1861 idDelim[0] = 0;
1862 }
1863
1864 // Look up the CurrencyMap element in the root bundle.
1865 UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
1866 UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
1867
1868 // Using the id derived from the local, get the currency data
1869 UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
1870
1871 // process each currency to see which one is valid for the given date
1872 if (U_SUCCESS(localStatus))
1873 {
1874 for (int32_t i=0; i<ures_getSize(countryArray); i++)
1875 {
1876 // get the currency resource
1877 UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
1878
1879 // get the from date
1880 int32_t fromLength = 0;
1881 UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
1882 const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
1883
1884 int64_t currDate64 = (int64_t)fromArray[0] << 32;
1885 currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
1886 UDate fromDate = (UDate)currDate64;
1887
1888 if (ures_getSize(currencyRes)> 2)
1889 {
1890 int32_t toLength = 0;
1891 UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
1892 const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
1893
1894 currDate64 = (int64_t)toArray[0] << 32;
1895 currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
1896 UDate toDate = (UDate)currDate64;
1897
1898 if ((fromDate <= date) && (date < toDate))
1899 {
1900 currCount++;
1901 }
1902
1903 ures_close(toRes);
1904 }
1905 else
1906 {
1907 if (fromDate <= date)
1908 {
1909 currCount++;
1910 }
1911 }
1912
1913 // close open resources
1914 ures_close(currencyRes);
1915 ures_close(fromRes);
1916
1917 } // end For loop
1918 } // end if (U_SUCCESS(localStatus))
1919
1920 ures_close(countryArray);
1921
1922 // Check for errors
1923 if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
1924 {
1925 // There is nothing to fallback to.
1926 // Report the failure/warning if possible.
1927 *ec = localStatus;
1928 }
1929
1930 if (U_SUCCESS(*ec))
1931 {
1932 // no errors
1933 return currCount;
1934 }
1935
1936 }
1937
1938 // If we got here, either error code is invalid or
1939 // some argument passed is no good.
1940 return 0;
1941 }
1942
1943 U_CAPI int32_t U_EXPORT2
1944 ucurr_forLocaleAndDate(const char* locale,
1945 UDate date,
1946 int32_t index,
1947 UChar* buff,
1948 int32_t buffCapacity,
1949 UErrorCode* ec)
1950 {
1951 int32_t resLen = 0;
1952 int32_t currIndex = 0;
1953 const UChar* s = NULL;
1954
1955 if (ec != NULL && U_SUCCESS(*ec))
1956 {
1957 // check the arguments passed
1958 if ((buff && buffCapacity) || !buffCapacity )
1959 {
1960 // local variables
1961 UErrorCode localStatus = U_ZERO_ERROR;
1962 char id[ULOC_FULLNAME_CAPACITY];
1963 resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
1964
1965 // get country or country_variant in `id'
1966 /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
1967 if (U_FAILURE(*ec))
1968 {
1969 return 0;
1970 }
1971
1972 // Remove variants, which is only needed for registration.
1973 char *idDelim = strchr(id, VAR_DELIM);
1974 if (idDelim)
1975 {
1976 idDelim[0] = 0;
1977 }
1978
1979 // Look up the CurrencyMap element in the root bundle.
1980 UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
1981 UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
1982
1983 // Using the id derived from the local, get the currency data
1984 UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
1985
1986 // process each currency to see which one is valid for the given date
1987 bool matchFound = false;
1988 if (U_SUCCESS(localStatus))
1989 {
1990 if ((index <= 0) || (index> ures_getSize(countryArray)))
1991 {
1992 // requested index is out of bounds
1993 ures_close(countryArray);
1994 return 0;
1995 }
1996
1997 for (int32_t i=0; i<ures_getSize(countryArray); i++)
1998 {
1999 // get the currency resource
2000 UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
2001 s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
2002
2003 // get the from date
2004 int32_t fromLength = 0;
2005 UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
2006 const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
2007
2008 int64_t currDate64 = (int64_t)fromArray[0] << 32;
2009 currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2010 UDate fromDate = (UDate)currDate64;
2011
2012 if (ures_getSize(currencyRes)> 2)
2013 {
2014 int32_t toLength = 0;
2015 UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
2016 const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
2017
2018 currDate64 = (int64_t)toArray[0] << 32;
2019 currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2020 UDate toDate = (UDate)currDate64;
2021
2022 if ((fromDate <= date) && (date < toDate))
2023 {
2024 currIndex++;
2025 if (currIndex == index)
2026 {
2027 matchFound = true;
2028 }
2029 }
2030
2031 ures_close(toRes);
2032 }
2033 else
2034 {
2035 if (fromDate <= date)
2036 {
2037 currIndex++;
2038 if (currIndex == index)
2039 {
2040 matchFound = true;
2041 }
2042 }
2043 }
2044
2045 // close open resources
2046 ures_close(currencyRes);
2047 ures_close(fromRes);
2048
2049 // check for loop exit
2050 if (matchFound)
2051 {
2052 break;
2053 }
2054
2055 } // end For loop
2056 }
2057
2058 ures_close(countryArray);
2059
2060 // Check for errors
2061 if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
2062 {
2063 // There is nothing to fallback to.
2064 // Report the failure/warning if possible.
2065 *ec = localStatus;
2066 }
2067
2068 if (U_SUCCESS(*ec))
2069 {
2070 // no errors
2071 if((buffCapacity> resLen) && matchFound)
2072 {
2073 // write out the currency value
2074 u_strcpy(buff, s);
2075 }
2076 else
2077 {
2078 return 0;
2079 }
2080 }
2081
2082 // return null terminated currency string
2083 return u_terminateUChars(buff, buffCapacity, resLen, ec);
2084 }
2085 else
2086 {
2087 // illegal argument encountered
2088 *ec = U_ILLEGAL_ARGUMENT_ERROR;
2089 }
2090
2091 }
2092
2093 // If we got here, either error code is invalid or
2094 // some argument passed is no good.
2095 return resLen;
2096 }
2097
2098 static const UEnumeration defaultKeywordValues = {
2099 NULL,
2100 NULL,
2101 ulist_close_keyword_values_iterator,
2102 ulist_count_keyword_values,
2103 uenum_unextDefault,
2104 ulist_next_keyword_value,
2105 ulist_reset_keyword_values_iterator
2106 };
2107
2108 U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key, const char *locale, UBool commonlyUsed, UErrorCode* status) {
2109 // Resolve region
2110 char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
2111 int32_t prefRegionLength = 0;
2112 prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
2113 if (prefRegionLength == 0) {
2114 char loc[ULOC_FULLNAME_CAPACITY] = "";
2115 int32_t locLength = 0;
2116 locLength = uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
2117
2118 prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
2119 }
2120
2121 // Read value from supplementalData
2122 UList *values = ulist_createEmptyList(status);
2123 UList *otherValues = ulist_createEmptyList(status);
2124 UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
2125 if (U_FAILURE(*status) || en == NULL) {
2126 if (en == NULL) {
2127 *status = U_MEMORY_ALLOCATION_ERROR;
2128 } else {
2129 uprv_free(en);
2130 }
2131 ulist_deleteList(values);
2132 ulist_deleteList(otherValues);
2133 return NULL;
2134 }
2135 memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
2136 en->context = values;
2137
2138 UResourceBundle *bundle = ures_openDirect(U_ICUDATA_CURR, "supplementalData", status);
2139 ures_getByKey(bundle, "CurrencyMap", bundle, status);
2140 UResourceBundle bundlekey, regbndl, curbndl, to;
2141 ures_initStackObject(&bundlekey);
2142 ures_initStackObject(&regbndl);
2143 ures_initStackObject(&curbndl);
2144 ures_initStackObject(&to);
2145
2146 while (U_SUCCESS(*status) && ures_hasNext(bundle)) {
2147 ures_getNextResource(bundle, &bundlekey, status);
2148 if (U_FAILURE(*status)) {
2149 break;
2150 }
2151 const char *region = ures_getKey(&bundlekey);
2152 UBool isPrefRegion = uprv_strcmp(region, prefRegion) == 0 ? TRUE : FALSE;
2153 if (!isPrefRegion && commonlyUsed) {
2154 // With commonlyUsed=true, we do not put
2155 // currencies for other regions in the
2156 // result list.
2157 continue;
2158 }
2159 ures_getByKey(bundle, region, &regbndl, status);
2160 if (U_FAILURE(*status)) {
2161 break;
2162 }
2163 while (U_SUCCESS(*status) && ures_hasNext(&regbndl)) {
2164 ures_getNextResource(&regbndl, &curbndl, status);
2165 if (ures_getType(&curbndl) != URES_TABLE) {
2166 // Currently, an empty ARRAY is mixed in.
2167 continue;
2168 }
2169 char *curID = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
2170 int32_t curIDLength = ULOC_KEYWORDS_CAPACITY;
2171 if (curID == NULL) {
2172 *status = U_MEMORY_ALLOCATION_ERROR;
2173 break;
2174 }
2175
2176 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
2177 ures_getUTF8StringByKey(&curbndl, "id", curID, &curIDLength, TRUE, status);
2178 /* optimize - use the utf-8 string */
2179 #else
2180 {
2181 const UChar* defString = ures_getStringByKey(&curbndl, "id", &curIDLength, status);
2182 if(U_SUCCESS(*status)) {
2183 if(curIDLength+1 > ULOC_KEYWORDS_CAPACITY) {
2184 *status = U_BUFFER_OVERFLOW_ERROR;
2185 } else {
2186 u_UCharsToChars(defString, curID, curIDLength+1);
2187 }
2188 }
2189 }
2190 #endif
2191
2192 if (U_FAILURE(*status)) {
2193 break;
2194 }
2195 UBool hasTo = FALSE;
2196 ures_getByKey(&curbndl, "to", &to, status);
2197 if (U_FAILURE(*status)) {
2198 // Do nothing here...
2199 *status = U_ZERO_ERROR;
2200 } else {
2201 hasTo = TRUE;
2202 }
2203 if (isPrefRegion && !hasTo && !ulist_containsString(values, curID, (int32_t)uprv_strlen(curID))) {
2204 // Currently active currency for the target country
2205 ulist_addItemEndList(values, curID, TRUE, status);
2206 } else if (!ulist_containsString(otherValues, curID, (int32_t)uprv_strlen(curID)) && !commonlyUsed) {
2207 ulist_addItemEndList(otherValues, curID, TRUE, status);
2208 } else {
2209 uprv_free(curID);
2210 }
2211 }
2212
2213 }
2214 if (U_SUCCESS(*status)) {
2215 if (commonlyUsed) {
2216 if (ulist_getListSize(values) == 0) {
2217 // This could happen if no valid region is supplied in the input
2218 // locale. In this case, we use the CLDR's default.
2219 uenum_close(en);
2220 en = ucurr_getKeywordValuesForLocale(key, "und", TRUE, status);
2221 }
2222 } else {
2223 // Consolidate the list
2224 char *value = NULL;
2225 ulist_resetList(otherValues);
2226 while ((value = (char *)ulist_getNext(otherValues)) != NULL) {
2227 if (!ulist_containsString(values, value, (int32_t)uprv_strlen(value))) {
2228 char *tmpValue = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
2229 uprv_memcpy(tmpValue, value, uprv_strlen(value) + 1);
2230 ulist_addItemEndList(values, tmpValue, TRUE, status);
2231 if (U_FAILURE(*status)) {
2232 break;
2233 }
2234 }
2235 }
2236 }
2237
2238 ulist_resetList((UList *)(en->context));
2239 } else {
2240 ulist_deleteList(values);
2241 uprv_free(en);
2242 values = NULL;
2243 en = NULL;
2244 }
2245 ures_close(&to);
2246 ures_close(&curbndl);
2247 ures_close(&regbndl);
2248 ures_close(&bundlekey);
2249 ures_close(bundle);
2250
2251 ulist_deleteList(otherValues);
2252
2253 return en;
2254 }
2255
2256 #endif /* #if !UCONFIG_NO_FORMATTING */
2257
2258 //eof