2 **********************************************************************
3 * Copyright (c) 2002-2012, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
8 #include "unicode/utypes.h"
10 #if !UCONFIG_NO_FORMATTING
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"
30 // #define UCURR_DEBUG 1
35 typedef struct IsoCodeEntry
{
36 const UChar
*isoCode
; /* const because it's a reference to a resource bundle string. */
41 //------------------------------------------------------------
44 // Default currency meta data of last resort. We try to use the
45 // defaults encoded in the meta data resource bundle. If there is a
46 // configuration/build error and these are not available, we use these
47 // hard-coded defaults (which should be identical).
48 static const int32_t LAST_RESORT_DATA
[] = { 2, 0 };
50 // POW10[i] = 10^i, i=0..MAX_POW10
51 static const int32_t POW10
[] = { 1, 10, 100, 1000, 10000, 100000,
52 1000000, 10000000, 100000000, 1000000000 };
54 static const int32_t MAX_POW10
= (sizeof(POW10
)/sizeof(POW10
[0])) - 1;
56 #define ISO_CURRENCY_CODE_LENGTH 3
58 //------------------------------------------------------------
62 static const char CURRENCY_DATA
[] = "supplementalData";
63 // Tag for meta-data, in root.
64 static const char CURRENCY_META
[] = "CurrencyMeta";
66 // Tag for map from countries to currencies, in root.
67 static const char CURRENCY_MAP
[] = "CurrencyMap";
69 // Tag for default meta-data, in CURRENCY_META
70 static const char DEFAULT_META
[] = "DEFAULT";
72 // Variant for legacy pre-euro mapping in CurrencyMap
73 static const char VAR_PRE_EURO
[] = "PREEURO";
75 // Variant for legacy euro mapping in CurrencyMap
76 static const char VAR_EURO
[] = "EURO";
79 static const char VAR_DELIM
= '_';
80 static const char VAR_DELIM_STR
[] = "_";
82 // Variant for legacy euro mapping in CurrencyMap
83 //static const char VAR_DELIM_EURO[] = "_EURO";
85 #define VARIANT_IS_EMPTY 0
86 #define VARIANT_IS_EURO 0x1
87 #define VARIANT_IS_PREEURO 0x2
89 // Tag for localized display names (symbols) of currencies
90 static const char CURRENCIES
[] = "Currencies";
91 static const char CURRENCYPLURALS
[] = "CurrencyPlurals";
93 // Marker character indicating that a display name is a ChoiceFormat
94 // pattern. Strings that start with one mark are ChoiceFormat
95 // patterns. Strings that start with 2 marks are static strings, and
96 // the first mark is deleted.
97 static const UChar CHOICE_FORMAT_MARK
= 0x003D; // Equals sign
99 static const UChar EUR_STR
[] = {0x0045,0x0055,0x0052,0};
101 // ISO codes mapping table
102 static UHashtable
* gIsoCodes
= NULL
;
103 static UBool gIsoCodesInitialized
= FALSE
;
105 static UMTX gIsoCodesLock
= NULL
;
107 //------------------------------------------------------------
111 * Cleanup callback func
113 static UBool U_CALLCONV
114 isoCodes_cleanup(void)
116 if (gIsoCodesLock
!= NULL
) {
117 umtx_destroy(&gIsoCodesLock
);
120 if (gIsoCodes
!= NULL
) {
121 uhash_close(gIsoCodes
);
124 gIsoCodesInitialized
= FALSE
;
130 * Deleter for OlsonToMetaMappingEntry
132 static void U_CALLCONV
133 deleteIsoCodeEntry(void *obj
) {
134 IsoCodeEntry
*entry
= (IsoCodeEntry
*)obj
;
139 * Unfortunately, we have to convert the UChar* currency code to char*
140 * to use it as a resource key.
143 myUCharsToChars(char* resultOfLen4
, const UChar
* currency
) {
144 u_UCharsToChars(currency
, resultOfLen4
, ISO_CURRENCY_CODE_LENGTH
);
145 resultOfLen4
[ISO_CURRENCY_CODE_LENGTH
] = 0;
150 * Internal function to look up currency data. Result is an array of
151 * two integers. The first is the fraction digits. The second is the
152 * rounding increment, or 0 if none. The rounding increment is in
153 * units of 10^(-fraction_digits).
155 static const int32_t*
156 _findMetaData(const UChar
* currency
, UErrorCode
& ec
) {
158 if (currency
== 0 || *currency
== 0) {
160 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
162 return LAST_RESORT_DATA
;
165 // Get CurrencyMeta resource out of root locale file. [This may
166 // move out of the root locale file later; if it does, update this
168 UResourceBundle
* currencyData
= ures_openDirect(U_ICUDATA_CURR
, CURRENCY_DATA
, &ec
);
169 UResourceBundle
* currencyMeta
= ures_getByKey(currencyData
, CURRENCY_META
, currencyData
, &ec
);
172 ures_close(currencyMeta
);
173 // Config/build error; return hard-coded defaults
174 return LAST_RESORT_DATA
;
177 // Look up our currency, or if that's not available, then DEFAULT
178 char buf
[ISO_CURRENCY_CODE_LENGTH
+1];
179 UErrorCode ec2
= U_ZERO_ERROR
; // local error code: soft failure
180 UResourceBundle
* rb
= ures_getByKey(currencyMeta
, myUCharsToChars(buf
, currency
), NULL
, &ec2
);
181 if (U_FAILURE(ec2
)) {
183 rb
= ures_getByKey(currencyMeta
,DEFAULT_META
, NULL
, &ec
);
185 ures_close(currencyMeta
);
187 // Config/build error; return hard-coded defaults
188 return LAST_RESORT_DATA
;
193 const int32_t *data
= ures_getIntVector(rb
, &len
, &ec
);
194 if (U_FAILURE(ec
) || len
!= 2) {
195 // Config/build error; return hard-coded defaults
197 ec
= U_INVALID_FORMAT_ERROR
;
199 ures_close(currencyMeta
);
201 return LAST_RESORT_DATA
;
204 ures_close(currencyMeta
);
209 // -------------------------------------
212 * @see VARIANT_IS_EURO
213 * @see VARIANT_IS_PREEURO
216 idForLocale(const char* locale
, char* countryAndVariant
, int capacity
, UErrorCode
* ec
)
218 uint32_t variantType
= 0;
219 // !!! this is internal only, assumes buffer is not null and capacity is sufficient
220 // Extract the country name and variant name. We only
221 // recognize two variant names, EURO and PREEURO.
222 char variant
[ULOC_FULLNAME_CAPACITY
];
223 uloc_getCountry(locale
, countryAndVariant
, capacity
, ec
);
224 uloc_getVariant(locale
, variant
, sizeof(variant
), ec
);
225 if (variant
[0] != 0) {
226 variantType
= (0 == uprv_strcmp(variant
, VAR_EURO
))
227 | ((0 == uprv_strcmp(variant
, VAR_PRE_EURO
)) << 1);
230 uprv_strcat(countryAndVariant
, VAR_DELIM_STR
);
231 uprv_strcat(countryAndVariant
, variant
);
237 // ------------------------------------------
241 //-------------------------------------------
243 // don't use ICUService since we don't need fallback
246 static UBool U_CALLCONV
currency_cleanup(void);
249 #if !UCONFIG_NO_SERVICE
252 static UMTX gCRegLock
= 0;
253 static CReg
* gCRegHead
= 0;
255 struct CReg
: public icu::UMemory
{
257 UChar iso
[ISO_CURRENCY_CODE_LENGTH
+1];
258 char id
[ULOC_FULLNAME_CAPACITY
];
260 CReg(const UChar
* _iso
, const char* _id
)
263 int32_t len
= (int32_t)uprv_strlen(_id
);
264 if (len
> (int32_t)(sizeof(id
)-1)) {
265 len
= (sizeof(id
)-1);
267 uprv_strncpy(id
, _id
, len
);
269 uprv_memcpy(iso
, _iso
, ISO_CURRENCY_CODE_LENGTH
* sizeof(const UChar
));
270 iso
[ISO_CURRENCY_CODE_LENGTH
] = 0;
273 static UCurrRegistryKey
reg(const UChar
* _iso
, const char* _id
, UErrorCode
* status
)
275 if (status
&& U_SUCCESS(*status
) && _iso
&& _id
) {
276 CReg
* n
= new CReg(_iso
, _id
);
278 umtx_lock(&gCRegLock
);
280 /* register for the first time */
281 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY
, currency_cleanup
);
285 umtx_unlock(&gCRegLock
);
288 *status
= U_MEMORY_ALLOCATION_ERROR
;
293 static UBool
unreg(UCurrRegistryKey key
) {
295 umtx_lock(&gCRegLock
);
297 CReg
** p
= &gCRegHead
;
300 *p
= ((CReg
*)key
)->next
;
308 umtx_unlock(&gCRegLock
);
312 static const UChar
* get(const char* id
) {
313 const UChar
* result
= NULL
;
314 umtx_lock(&gCRegLock
);
317 /* register cleanup of the mutex */
318 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY
, currency_cleanup
);
320 if (uprv_strcmp(id
, p
->id
) == 0) {
326 umtx_unlock(&gCRegLock
);
330 /* This doesn't need to be thread safe. It's for u_cleanup only. */
331 static void cleanup(void) {
334 gCRegHead
= gCRegHead
->next
;
337 umtx_destroy(&gCRegLock
);
341 // -------------------------------------
343 U_CAPI UCurrRegistryKey U_EXPORT2
344 ucurr_register(const UChar
* isoCode
, const char* locale
, UErrorCode
*status
)
346 if (status
&& U_SUCCESS(*status
)) {
347 char id
[ULOC_FULLNAME_CAPACITY
];
348 idForLocale(locale
, id
, sizeof(id
), status
);
349 return CReg::reg(isoCode
, id
, status
);
354 // -------------------------------------
356 U_CAPI UBool U_EXPORT2
357 ucurr_unregister(UCurrRegistryKey key
, UErrorCode
* status
)
359 if (status
&& U_SUCCESS(*status
)) {
360 return CReg::unreg(key
);
364 #endif /* UCONFIG_NO_SERVICE */
366 // -------------------------------------
369 * Release all static memory held by currency.
371 /*The declaration here is needed so currency_cleanup(void)
372 * can call this function.
374 static UBool U_CALLCONV
375 currency_cache_cleanup(void);
378 static UBool U_CALLCONV
currency_cleanup(void) {
379 #if !UCONFIG_NO_SERVICE
383 * There might be some cached currency data or isoCodes data.
385 currency_cache_cleanup();
392 // -------------------------------------
394 U_CAPI
int32_t U_EXPORT2
395 ucurr_forLocale(const char* locale
,
397 int32_t buffCapacity
,
401 const UChar
* s
= NULL
;
402 if (ec
!= NULL
&& U_SUCCESS(*ec
)) {
403 if ((buff
&& buffCapacity
) || !buffCapacity
) {
404 UErrorCode localStatus
= U_ZERO_ERROR
;
405 char id
[ULOC_FULLNAME_CAPACITY
];
406 if ((resLen
= uloc_getKeywordValue(locale
, "currency", id
, ULOC_FULLNAME_CAPACITY
, &localStatus
))) {
407 // there is a currency keyword. Try to see if it's valid
408 if(buffCapacity
> resLen
) {
409 /* Normalize the currency keyword value to upper case. */
410 T_CString_toUpperCase(id
);
411 u_charsToUChars(id
, buff
, resLen
);
414 // get country or country_variant in `id'
415 uint32_t variantType
= idForLocale(locale
, id
, sizeof(id
), ec
);
417 if (U_FAILURE(*ec
)) {
421 #if !UCONFIG_NO_SERVICE
422 const UChar
* result
= CReg::get(id
);
424 if(buffCapacity
> u_strlen(result
)) {
425 u_strcpy(buff
, result
);
427 return u_strlen(result
);
430 // Remove variants, which is only needed for registration.
431 char *idDelim
= strchr(id
, VAR_DELIM
);
436 // Look up the CurrencyMap element in the root bundle.
437 UResourceBundle
*rb
= ures_openDirect(U_ICUDATA_CURR
, CURRENCY_DATA
, &localStatus
);
438 UResourceBundle
*cm
= ures_getByKey(rb
, CURRENCY_MAP
, rb
, &localStatus
);
439 UResourceBundle
*countryArray
= ures_getByKey(rb
, id
, cm
, &localStatus
);
440 UResourceBundle
*currencyReq
= ures_getByIndex(countryArray
, 0, NULL
, &localStatus
);
441 s
= ures_getStringByKey(currencyReq
, "id", &resLen
, &localStatus
);
444 Get the second item when PREEURO is requested, and this is a known Euro country.
445 If the requested variant is PREEURO, and this isn't a Euro country, assume
446 that the country changed over to the Euro in the future. This is probably
447 an old version of ICU that hasn't been updated yet. The latest currency is
450 if (U_SUCCESS(localStatus
)) {
451 if ((variantType
& VARIANT_IS_PREEURO
) && u_strcmp(s
, EUR_STR
) == 0) {
452 currencyReq
= ures_getByIndex(countryArray
, 1, currencyReq
, &localStatus
);
453 s
= ures_getStringByKey(currencyReq
, "id", &resLen
, &localStatus
);
455 else if ((variantType
& VARIANT_IS_EURO
)) {
459 ures_close(countryArray
);
460 ures_close(currencyReq
);
462 if ((U_FAILURE(localStatus
)) && strchr(id
, '_') != 0)
464 // We don't know about it. Check to see if we support the variant.
465 uloc_getParent(locale
, id
, sizeof(id
), ec
);
466 *ec
= U_USING_FALLBACK_WARNING
;
467 return ucurr_forLocale(id
, buff
, buffCapacity
, ec
);
469 else if (*ec
== U_ZERO_ERROR
|| localStatus
!= U_ZERO_ERROR
) {
470 // There is nothing to fallback to. Report the failure/warning if possible.
473 if (U_SUCCESS(*ec
)) {
474 if(buffCapacity
> resLen
) {
479 return u_terminateUChars(buff
, buffCapacity
, resLen
, ec
);
481 *ec
= U_ILLEGAL_ARGUMENT_ERROR
;
490 * Modify the given locale name by removing the rightmost _-delimited
491 * element. If there is none, empty the string ("" == root).
492 * NOTE: The string "root" is not recognized; do not use it.
493 * @return TRUE if the fallback happened; FALSE if locale is already
496 static UBool
fallback(char *loc
) {
500 UErrorCode status
= U_ZERO_ERROR
;
501 uloc_getParent(loc
, loc
, (int32_t)uprv_strlen(loc
), &status
);
503 char *i = uprv_strrchr(loc, '_');
513 U_CAPI
const UChar
* U_EXPORT2
514 ucurr_getName(const UChar
* currency
,
516 UCurrNameStyle nameStyle
,
517 UBool
* isChoiceFormat
, // fillin
518 int32_t* len
, // fillin
521 // Look up the Currencies resource for the given locale. The
522 // Currencies locale data looks like this:
525 //| USD { "US$", "US Dollar" }
526 //| CHF { "Sw F", "Swiss Franc" }
527 //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
532 if (U_FAILURE(*ec
)) {
536 int32_t choice
= (int32_t) nameStyle
;
537 if (choice
< 0 || choice
> 1) {
538 *ec
= U_ILLEGAL_ARGUMENT_ERROR
;
542 // In the future, resource bundles may implement multi-level
543 // fallback. That is, if a currency is not found in the en_US
544 // Currencies data, then the en Currencies data will be searched.
545 // Currently, if a Currencies datum exists in en_US and en, the
546 // en_US entry hides that in en.
548 // We want multi-level fallback for this resource, so we implement
551 // Use a separate UErrorCode here that does not propagate out of
553 UErrorCode ec2
= U_ZERO_ERROR
;
555 char loc
[ULOC_FULLNAME_CAPACITY
];
556 uloc_getName(locale
, loc
, sizeof(loc
), &ec2
);
557 if (U_FAILURE(ec2
) || ec2
== U_STRING_NOT_TERMINATED_WARNING
) {
558 *ec
= U_ILLEGAL_ARGUMENT_ERROR
;
562 char buf
[ISO_CURRENCY_CODE_LENGTH
+1];
563 myUCharsToChars(buf
, currency
);
565 /* Normalize the keyword value to uppercase */
566 T_CString_toUpperCase(buf
);
568 const UChar
* s
= NULL
;
570 UResourceBundle
* rb
= ures_open(U_ICUDATA_CURR
, loc
, &ec2
);
572 rb
= ures_getByKey(rb
, CURRENCIES
, rb
, &ec2
);
574 // Fetch resource with multi-level resource inheritance fallback
575 rb
= ures_getByKeyWithFallback(rb
, buf
, rb
, &ec2
);
577 s
= ures_getStringByIndex(rb
, choice
, len
, &ec2
);
580 // If we've succeeded we're done. Otherwise, try to fallback.
581 // If that fails (because we are already at root) then exit.
582 if (U_SUCCESS(ec2
)) {
583 if (ec2
== U_USING_DEFAULT_WARNING
584 || (ec2
== U_USING_FALLBACK_WARNING
&& *ec
!= U_USING_DEFAULT_WARNING
)) {
589 // Determine if this is a ChoiceFormat pattern. One leading mark
590 // indicates a ChoiceFormat. Two indicates a static string that
591 // starts with a mark. In either case, the first mark is ignored,
592 // if present. Marks in the rest of the string have no special
594 *isChoiceFormat
= FALSE
;
595 if (U_SUCCESS(ec2
)) {
598 while (i
< *len
&& s
[i
] == CHOICE_FORMAT_MARK
&& i
< 2) {
601 *isChoiceFormat
= (i
== 1);
602 if (i
!= 0) ++s
; // Skip over first mark
606 // If we fail to find a match, use the ISO 4217 code
607 *len
= u_strlen(currency
); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
608 *ec
= U_USING_DEFAULT_WARNING
;
612 U_CAPI
const UChar
* U_EXPORT2
613 ucurr_getPluralName(const UChar
* currency
,
615 UBool
* isChoiceFormat
,
616 const char* pluralCount
,
617 int32_t* len
, // fillin
619 // Look up the Currencies resource for the given locale. The
620 // Currencies locale data looks like this:
622 //| CurrencyPlurals {
625 //| other{"US dollars"}
630 if (U_FAILURE(*ec
)) {
634 // Use a separate UErrorCode here that does not propagate out of
636 UErrorCode ec2
= U_ZERO_ERROR
;
638 char loc
[ULOC_FULLNAME_CAPACITY
];
639 uloc_getName(locale
, loc
, sizeof(loc
), &ec2
);
640 if (U_FAILURE(ec2
) || ec2
== U_STRING_NOT_TERMINATED_WARNING
) {
641 *ec
= U_ILLEGAL_ARGUMENT_ERROR
;
645 char buf
[ISO_CURRENCY_CODE_LENGTH
+1];
646 myUCharsToChars(buf
, currency
);
648 const UChar
* s
= NULL
;
650 UResourceBundle
* rb
= ures_open(U_ICUDATA_CURR
, loc
, &ec2
);
652 rb
= ures_getByKey(rb
, CURRENCYPLURALS
, rb
, &ec2
);
654 // Fetch resource with multi-level resource inheritance fallback
655 rb
= ures_getByKeyWithFallback(rb
, buf
, rb
, &ec2
);
657 s
= ures_getStringByKeyWithFallback(rb
, pluralCount
, len
, &ec2
);
658 if (U_FAILURE(ec2
)) {
659 // fall back to "other"
661 s
= ures_getStringByKeyWithFallback(rb
, "other", len
, &ec2
);
662 if (U_FAILURE(ec2
)) {
664 // fall back to long name in Currencies
665 return ucurr_getName(currency
, locale
, UCURR_LONG_NAME
,
666 isChoiceFormat
, len
, ec
);
671 // If we've succeeded we're done. Otherwise, try to fallback.
672 // If that fails (because we are already at root) then exit.
673 if (U_SUCCESS(ec2
)) {
674 if (ec2
== U_USING_DEFAULT_WARNING
675 || (ec2
== U_USING_FALLBACK_WARNING
&& *ec
!= U_USING_DEFAULT_WARNING
)) {
682 // If we fail to find a match, use the ISO 4217 code
683 *len
= u_strlen(currency
); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
684 *ec
= U_USING_DEFAULT_WARNING
;
689 //========================================================================
690 // Following are structure and function for parsing currency names
692 #define NEED_TO_BE_DELETED 0x1
694 // TODO: a better way to define this?
695 #define MAX_CURRENCY_NAME_LEN 100
698 const char* IsoCode
; // key
699 UChar
* currencyName
; // value
700 int32_t currencyNameLen
; // value length
701 int32_t flag
; // flags
702 } CurrencyNameStruct
;
706 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
710 #define MAX(a,b) (((a)<(b)) ? (b) : (a))
714 // Comparason function used in quick sort.
715 static int U_CALLCONV
currencyNameComparator(const void* a
, const void* b
) {
716 const CurrencyNameStruct
* currName_1
= (const CurrencyNameStruct
*)a
;
717 const CurrencyNameStruct
* currName_2
= (const CurrencyNameStruct
*)b
;
719 i
< MIN(currName_1
->currencyNameLen
, currName_2
->currencyNameLen
);
721 if (currName_1
->currencyName
[i
] < currName_2
->currencyName
[i
]) {
724 if (currName_1
->currencyName
[i
] > currName_2
->currencyName
[i
]) {
728 if (currName_1
->currencyNameLen
< currName_2
->currencyNameLen
) {
730 } else if (currName_1
->currencyNameLen
> currName_2
->currencyNameLen
) {
737 // Give a locale, return the maximum number of currency names associated with
739 // It gets currency names from resource bundles using fallback.
740 // It is the maximum number because in the fallback chain, some of the
741 // currency names are duplicated.
742 // For example, given locale as "en_US", the currency names get from resource
743 // bundle in "en_US" and "en" are duplicated. The fallback mechanism will count
744 // all currency names in "en_US" and "en".
746 getCurrencyNameCount(const char* loc
, int32_t* total_currency_name_count
, int32_t* total_currency_symbol_count
) {
748 *total_currency_name_count
= 0;
749 *total_currency_symbol_count
= 0;
750 const UChar
* s
= NULL
;
751 char locale
[ULOC_FULLNAME_CAPACITY
];
752 uprv_strcpy(locale
, loc
);
754 UErrorCode ec2
= U_ZERO_ERROR
;
755 // TODO: ures_openDirect?
756 UResourceBundle
* rb
= ures_open(U_ICUDATA_CURR
, locale
, &ec2
);
757 UResourceBundle
* curr
= ures_getByKey(rb
, CURRENCIES
, NULL
, &ec2
);
758 int32_t n
= ures_getSize(curr
);
759 for (int32_t i
=0; i
<n
; ++i
) {
760 UResourceBundle
* names
= ures_getByIndex(curr
, i
, NULL
, &ec2
);
762 s
= ures_getStringByIndex(names
, UCURR_SYMBOL_NAME
, &len
, &ec2
);
763 UBool isChoice
= FALSE
;
764 if (len
> 0 && s
[0] == CHOICE_FORMAT_MARK
) {
767 if (len
> 0 && s
[0] != CHOICE_FORMAT_MARK
) {
772 ChoiceFormat
fmt(UnicodeString(TRUE
, s
, len
), ec2
);
774 fmt
.getFormats(fmt_count
);
775 *total_currency_symbol_count
+= fmt_count
;
777 ++(*total_currency_symbol_count
); // currency symbol
780 ++(*total_currency_symbol_count
); // iso code
781 ++(*total_currency_name_count
); // long name
786 UErrorCode ec3
= U_ZERO_ERROR
;
787 UResourceBundle
* curr_p
= ures_getByKey(rb
, CURRENCYPLURALS
, NULL
, &ec3
);
788 n
= ures_getSize(curr_p
);
789 for (int32_t i
=0; i
<n
; ++i
) {
790 UResourceBundle
* names
= ures_getByIndex(curr_p
, i
, NULL
, &ec3
);
791 *total_currency_name_count
+= ures_getSize(names
);
798 if (!fallback(locale
)) {
805 toUpperCase(const UChar
* source
, int32_t len
, const char* locale
) {
807 UErrorCode ec
= U_ZERO_ERROR
;
808 int32_t destLen
= u_strToUpper(dest
, 0, source
, len
, locale
, &ec
);
811 dest
= (UChar
*)uprv_malloc(sizeof(UChar
) * MAX(destLen
, len
));
812 u_strToUpper(dest
, destLen
, source
, len
, locale
, &ec
);
814 uprv_memcpy(dest
, source
, sizeof(UChar
) * len
);
820 // Collect all available currency names associated with the given locale
821 // (enable fallback chain).
822 // Read currenc names defined in resource bundle "Currencies" and
823 // "CurrencyPlural", enable fallback chain.
824 // return the malloc-ed currency name arrays and the total number of currency
825 // names in the array.
827 collectCurrencyNames(const char* locale
,
828 CurrencyNameStruct
** currencyNames
,
829 int32_t* total_currency_name_count
,
830 CurrencyNameStruct
** currencySymbols
,
831 int32_t* total_currency_symbol_count
,
834 // Look up the Currencies resource for the given locale.
835 UErrorCode ec2
= U_ZERO_ERROR
;
837 char loc
[ULOC_FULLNAME_CAPACITY
];
838 uloc_getName(locale
, loc
, sizeof(loc
), &ec2
);
839 if (U_FAILURE(ec2
) || ec2
== U_STRING_NOT_TERMINATED_WARNING
) {
840 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
843 // Get maximum currency name count first.
844 getCurrencyNameCount(loc
, total_currency_name_count
, total_currency_symbol_count
);
846 *currencyNames
= (CurrencyNameStruct
*)uprv_malloc
847 (sizeof(CurrencyNameStruct
) * (*total_currency_name_count
));
848 *currencySymbols
= (CurrencyNameStruct
*)uprv_malloc
849 (sizeof(CurrencyNameStruct
) * (*total_currency_symbol_count
));
851 const UChar
* s
= NULL
; // currency name
852 char* iso
= NULL
; // currency ISO code
854 *total_currency_name_count
= 0;
855 *total_currency_symbol_count
= 0;
857 UErrorCode ec3
= U_ZERO_ERROR
;
858 UErrorCode ec4
= U_ZERO_ERROR
;
860 // Using hash to remove duplicates caused by locale fallback
861 UHashtable
* currencyIsoCodes
= uhash_open(uhash_hashChars
, uhash_compareChars
, NULL
, &ec3
);
862 UHashtable
* currencyPluralIsoCodes
= uhash_open(uhash_hashChars
, uhash_compareChars
, NULL
, &ec4
);
863 for (int32_t localeLevel
= 0; ; ++localeLevel
) {
865 // TODO: ures_openDirect
866 UResourceBundle
* rb
= ures_open(U_ICUDATA_CURR
, loc
, &ec2
);
867 UResourceBundle
* curr
= ures_getByKey(rb
, CURRENCIES
, NULL
, &ec2
);
868 int32_t n
= ures_getSize(curr
);
869 for (int32_t i
=0; i
<n
; ++i
) {
870 UResourceBundle
* names
= ures_getByIndex(curr
, i
, NULL
, &ec2
);
872 s
= ures_getStringByIndex(names
, UCURR_SYMBOL_NAME
, &len
, &ec2
);
873 // TODO: uhash_put wont change key/value?
874 iso
= (char*)ures_getKey(names
);
875 if (localeLevel
== 0) {
876 uhash_put(currencyIsoCodes
, iso
, iso
, &ec3
);
878 if (uhash_get(currencyIsoCodes
, iso
) != NULL
) {
882 uhash_put(currencyIsoCodes
, iso
, iso
, &ec3
);
885 UBool isChoice
= FALSE
;
886 if (len
> 0 && s
[0] == CHOICE_FORMAT_MARK
) {
889 if (len
> 0 && s
[0] != CHOICE_FORMAT_MARK
) {
894 ChoiceFormat
fmt(UnicodeString(TRUE
, s
, len
), ec2
);
896 const UnicodeString
* formats
= fmt
.getFormats(fmt_count
);
897 for (int i
= 0; i
< fmt_count
; ++i
) {
898 // put iso, formats[i]; into array
899 int32_t length
= formats
[i
].length();
900 UChar
* name
= (UChar
*)uprv_malloc(sizeof(UChar
)*length
);
901 formats
[i
].extract(0, length
, name
);
902 (*currencySymbols
)[*total_currency_symbol_count
].IsoCode
= iso
;
903 (*currencySymbols
)[*total_currency_symbol_count
].currencyName
= name
;
904 (*currencySymbols
)[*total_currency_symbol_count
].flag
= NEED_TO_BE_DELETED
;
905 (*currencySymbols
)[(*total_currency_symbol_count
)++].currencyNameLen
= length
;
908 // Add currency symbol.
909 (*currencySymbols
)[*total_currency_symbol_count
].IsoCode
= iso
;
910 (*currencySymbols
)[*total_currency_symbol_count
].currencyName
= (UChar
*)s
;
911 (*currencySymbols
)[*total_currency_symbol_count
].flag
= 0;
912 (*currencySymbols
)[(*total_currency_symbol_count
)++].currencyNameLen
= len
;
915 // Add currency long name.
916 s
= ures_getStringByIndex(names
, UCURR_LONG_NAME
, &len
, &ec2
);
917 (*currencyNames
)[*total_currency_name_count
].IsoCode
= iso
;
918 UChar
* upperName
= toUpperCase(s
, len
, locale
);
919 (*currencyNames
)[*total_currency_name_count
].currencyName
= upperName
;
920 (*currencyNames
)[*total_currency_name_count
].flag
= NEED_TO_BE_DELETED
;
921 (*currencyNames
)[(*total_currency_name_count
)++].currencyNameLen
= len
;
923 // put (iso, 3, and iso) in to array
924 // Add currency ISO code.
925 (*currencySymbols
)[*total_currency_symbol_count
].IsoCode
= iso
;
926 (*currencySymbols
)[*total_currency_symbol_count
].currencyName
= (UChar
*)uprv_malloc(sizeof(UChar
)*3);
927 // Must convert iso[] into Unicode
928 u_charsToUChars(iso
, (*currencySymbols
)[*total_currency_symbol_count
].currencyName
, 3);
929 (*currencySymbols
)[*total_currency_symbol_count
].flag
= NEED_TO_BE_DELETED
;
930 (*currencySymbols
)[(*total_currency_symbol_count
)++].currencyNameLen
= 3;
936 UErrorCode ec3
= U_ZERO_ERROR
;
937 UResourceBundle
* curr_p
= ures_getByKey(rb
, CURRENCYPLURALS
, NULL
, &ec3
);
938 n
= ures_getSize(curr_p
);
939 for (int32_t i
=0; i
<n
; ++i
) {
940 UResourceBundle
* names
= ures_getByIndex(curr_p
, i
, NULL
, &ec3
);
941 iso
= (char*)ures_getKey(names
);
942 // Using hash to remove duplicated ISO codes in fallback chain.
943 if (localeLevel
== 0) {
944 uhash_put(currencyPluralIsoCodes
, iso
, iso
, &ec4
);
946 if (uhash_get(currencyPluralIsoCodes
, iso
) != NULL
) {
950 uhash_put(currencyPluralIsoCodes
, iso
, iso
, &ec4
);
953 int32_t num
= ures_getSize(names
);
955 for (int32_t j
= 0; j
< num
; ++j
) {
956 // TODO: remove duplicates between singular name and
957 // currency long name?
958 s
= ures_getStringByIndex(names
, j
, &len
, &ec3
);
959 (*currencyNames
)[*total_currency_name_count
].IsoCode
= iso
;
960 UChar
* upperName
= toUpperCase(s
, len
, locale
);
961 (*currencyNames
)[*total_currency_name_count
].currencyName
= upperName
;
962 (*currencyNames
)[*total_currency_name_count
].flag
= NEED_TO_BE_DELETED
;
963 (*currencyNames
)[(*total_currency_name_count
)++].currencyNameLen
= len
;
971 if (!fallback(loc
)) {
976 uhash_close(currencyIsoCodes
);
977 uhash_close(currencyPluralIsoCodes
);
979 // quick sort the struct
980 qsort(*currencyNames
, *total_currency_name_count
,
981 sizeof(CurrencyNameStruct
), currencyNameComparator
);
982 qsort(*currencySymbols
, *total_currency_symbol_count
,
983 sizeof(CurrencyNameStruct
), currencyNameComparator
);
986 printf("currency name count: %d\n", *total_currency_name_count
);
987 for (int32_t index
= 0; index
< *total_currency_name_count
; ++index
) {
988 printf("index: %d\n", index
);
989 printf("iso: %s\n", (*currencyNames
)[index
].IsoCode
);
990 printf("currencyName:");
991 for (int32_t i
= 0; i
< (*currencyNames
)[index
].currencyNameLen
; ++i
) {
992 printf("%c", (unsigned char)(*currencyNames
)[index
].currencyName
[i
]);
995 printf("len: %d\n", (*currencyNames
)[index
].currencyNameLen
);
997 printf("currency symbol count: %d\n", *total_currency_symbol_count
);
998 for (int32_t index
= 0; index
< *total_currency_symbol_count
; ++index
) {
999 printf("index: %d\n", index
);
1000 printf("iso: %s\n", (*currencySymbols
)[index
].IsoCode
);
1001 printf("currencySymbol:");
1002 for (int32_t i
= 0; i
< (*currencySymbols
)[index
].currencyNameLen
; ++i
) {
1003 printf("%c", (unsigned char)(*currencySymbols
)[index
].currencyName
[i
]);
1006 printf("len: %d\n", (*currencySymbols
)[index
].currencyNameLen
);
1011 // @param currencyNames: currency names array
1012 // @param indexInCurrencyNames: the index of the character in currency names
1013 // array against which the comparison is done
1014 // @param key: input text char to compare against
1015 // @param begin(IN/OUT): the begin index of matching range in currency names array
1016 // @param end(IN/OUT): the end index of matching range in currency names array.
1018 binarySearch(const CurrencyNameStruct
* currencyNames
,
1019 int32_t indexInCurrencyNames
,
1021 int32_t* begin
, int32_t* end
) {
1023 printf("key = %x\n", key
);
1025 int32_t first
= *begin
;
1026 int32_t last
= *end
;
1027 while (first
<= last
) {
1028 int32_t mid
= (first
+ last
) / 2; // compute mid point.
1029 if (indexInCurrencyNames
>= currencyNames
[mid
].currencyNameLen
) {
1032 if (key
> currencyNames
[mid
].currencyName
[indexInCurrencyNames
]) {
1035 else if (key
< currencyNames
[mid
].currencyName
[indexInCurrencyNames
]) {
1039 // Find a match, and looking for ranges
1040 // Now do two more binary searches. First, on the left side for
1041 // the greatest L such that CurrencyNameStruct[L] < key.
1046 printf("mid = %d\n", mid
);
1049 int32_t M
= (L
+ R
) / 2;
1051 printf("L = %d, R = %d, M = %d\n", L
, R
, M
);
1053 if (indexInCurrencyNames
>= currencyNames
[M
].currencyNameLen
) {
1056 if (currencyNames
[M
].currencyName
[indexInCurrencyNames
] < key
) {
1060 U_ASSERT(currencyNames
[M
].currencyName
[indexInCurrencyNames
] == key
);
1071 printf("begin = %d\n", *begin
);
1072 U_ASSERT(currencyNames
[*begin
].currencyName
[indexInCurrencyNames
] == key
);
1075 // Now for the second search, finding the least R such that
1076 // key < CurrencyNameStruct[R].
1080 int32_t M
= (L
+ R
) / 2;
1082 printf("L = %d, R = %d, M = %d\n", L
, R
, M
);
1084 if (currencyNames
[M
].currencyNameLen
< indexInCurrencyNames
) {
1087 if (currencyNames
[M
].currencyName
[indexInCurrencyNames
] > key
) {
1091 U_ASSERT(currencyNames
[M
].currencyName
[indexInCurrencyNames
] == key
);
1100 if (currencyNames
[R
].currencyName
[indexInCurrencyNames
] > key
) {
1106 printf("end = %d\n", *end
);
1109 // now, found the range. check whether there is exact match
1110 if (currencyNames
[*begin
].currencyNameLen
== indexInCurrencyNames
+ 1) {
1111 return *begin
; // find range and exact match.
1113 return -1; // find range, but no exact match.
1119 return -1; // failed to find range.
1123 // Linear search "text" in "currencyNames".
1124 // @param begin, end: the begin and end index in currencyNames, within which
1125 // range should the search be performed.
1126 // @param textLen: the length of the text to be compared
1127 // @param maxMatchLen(IN/OUT): passing in the computed max matching length
1128 // pass out the new max matching length
1129 // @param maxMatchIndex: the index in currencyName which has the longest
1130 // match with input text.
1132 linearSearch(const CurrencyNameStruct
* currencyNames
,
1133 int32_t begin
, int32_t end
,
1134 const UChar
* text
, int32_t textLen
,
1135 int32_t *maxMatchLen
, int32_t* maxMatchIndex
) {
1136 for (int32_t index
= begin
; index
<= end
; ++index
) {
1137 int32_t len
= currencyNames
[index
].currencyNameLen
;
1138 if (len
> *maxMatchLen
&& len
<= textLen
&&
1139 uprv_memcmp(currencyNames
[index
].currencyName
, text
, len
* sizeof(UChar
)) == 0) {
1140 *maxMatchIndex
= index
;
1143 printf("maxMatchIndex = %d, maxMatchLen = %d\n",
1144 *maxMatchIndex
, *maxMatchLen
);
1150 #define LINEAR_SEARCH_THRESHOLD 10
1152 // Find longest match between "text" and currency names in "currencyNames".
1153 // @param total_currency_count: total number of currency names in CurrencyNames.
1154 // @param textLen: the length of the text to be compared
1155 // @param maxMatchLen: passing in the computed max matching length
1156 // pass out the new max matching length
1157 // @param maxMatchIndex: the index in currencyName which has the longest
1158 // match with input text.
1160 searchCurrencyName(const CurrencyNameStruct
* currencyNames
,
1161 int32_t total_currency_count
,
1162 const UChar
* text
, int32_t textLen
,
1163 int32_t* maxMatchLen
, int32_t* maxMatchIndex
) {
1164 *maxMatchIndex
= -1;
1166 int32_t matchIndex
= -1;
1167 int32_t binarySearchBegin
= 0;
1168 int32_t binarySearchEnd
= total_currency_count
- 1;
1169 // It is a variant of binary search.
1170 // For example, given the currency names in currencyNames array are:
1171 // A AB ABC AD AZ B BB BBEX BBEXYZ BS C D E....
1172 // and the input text is BBEXST
1173 // The first round binary search search "B" in the text against
1174 // the first char in currency names, and find the first char matching range
1175 // to be "B BB BBEX BBEXYZ BS" (and the maximum matching "B").
1176 // The 2nd round binary search search the second "B" in the text against
1177 // the 2nd char in currency names, and narrow the matching range to
1178 // "BB BBEX BBEXYZ" (and the maximum matching "BB").
1179 // The 3rd round returnes the range as "BBEX BBEXYZ" (without changing
1180 // maximum matching).
1181 // The 4th round returns the same range (the maximum matching is "BBEX").
1182 // The 5th round returns no matching range.
1183 for (int32_t index
= 0; index
< textLen
; ++index
) {
1184 // matchIndex saves the one with exact match till the current point.
1185 // [binarySearchBegin, binarySearchEnd] saves the matching range.
1186 matchIndex
= binarySearch(currencyNames
, index
,
1188 &binarySearchBegin
, &binarySearchEnd
);
1189 if (binarySearchBegin
== -1) { // did not find the range
1192 if (matchIndex
!= -1) {
1193 // find an exact match for text from text[0] to text[index]
1194 // in currencyNames array.
1195 *maxMatchLen
= index
+ 1;
1196 *maxMatchIndex
= matchIndex
;
1198 if (binarySearchEnd
- binarySearchBegin
< LINEAR_SEARCH_THRESHOLD
) {
1199 // linear search if within threshold.
1200 linearSearch(currencyNames
, binarySearchBegin
, binarySearchEnd
,
1202 maxMatchLen
, maxMatchIndex
);
1209 //========================= currency name cache =====================
1211 char locale
[ULOC_FULLNAME_CAPACITY
]; //key
1212 // currency names, case insensitive
1213 CurrencyNameStruct
* currencyNames
; // value
1214 int32_t totalCurrencyNameCount
; // currency name count
1215 // currency symbols and ISO code, case sensitive
1216 CurrencyNameStruct
* currencySymbols
; // value
1217 int32_t totalCurrencySymbolCount
; // count
1219 // reference count is set to 1 when an entry is put to cache.
1220 // it increases by 1 before accessing, and decreased by 1 after accessing.
1221 // The entry is deleted when ref count is zero, which means
1222 // the entry is replaced out of cache and no process is accessing it.
1224 } CurrencyNameCacheEntry
;
1227 #define CURRENCY_NAME_CACHE_NUM 10
1229 // Reserve 10 cache entries.
1230 static CurrencyNameCacheEntry
* currCache
[CURRENCY_NAME_CACHE_NUM
] = {NULL
};
1231 // Using an index to indicate which entry to be replaced when cache is full.
1232 // It is a simple round-robin replacement strategy.
1233 static int8_t currentCacheEntryIndex
= 0;
1237 deleteCurrencyNames(CurrencyNameStruct
* currencyNames
, int32_t count
) {
1238 for (int32_t index
= 0; index
< count
; ++index
) {
1239 if ( (currencyNames
[index
].flag
& NEED_TO_BE_DELETED
) ) {
1240 uprv_free(currencyNames
[index
].currencyName
);
1243 uprv_free(currencyNames
);
1248 deleteCacheEntry(CurrencyNameCacheEntry
* entry
) {
1249 deleteCurrencyNames(entry
->currencyNames
, entry
->totalCurrencyNameCount
);
1250 deleteCurrencyNames(entry
->currencySymbols
, entry
->totalCurrencySymbolCount
);
1256 static UBool U_CALLCONV
1257 currency_cache_cleanup(void) {
1258 for (int32_t i
= 0; i
< CURRENCY_NAME_CACHE_NUM
; ++i
) {
1260 deleteCacheEntry(currCache
[i
]);
1269 uprv_parseCurrency(const char* locale
,
1270 const icu::UnicodeString
& text
,
1271 icu::ParsePosition
& pos
,
1278 if (U_FAILURE(ec
)) {
1282 int32_t total_currency_name_count
= 0;
1283 CurrencyNameStruct
* currencyNames
= NULL
;
1284 int32_t total_currency_symbol_count
= 0;
1285 CurrencyNameStruct
* currencySymbols
= NULL
;
1286 CurrencyNameCacheEntry
* cacheEntry
= NULL
;
1289 // in order to handle racing correctly,
1290 // not putting 'search' in a separate function and using UMTX.
1292 for (int8_t i
= 0; i
< CURRENCY_NAME_CACHE_NUM
; ++i
) {
1293 if (currCache
[i
]!= NULL
&&
1294 uprv_strcmp(locale
, currCache
[i
]->locale
) == 0) {
1300 cacheEntry
= currCache
[found
];
1301 currencyNames
= cacheEntry
->currencyNames
;
1302 total_currency_name_count
= cacheEntry
->totalCurrencyNameCount
;
1303 currencySymbols
= cacheEntry
->currencySymbols
;
1304 total_currency_symbol_count
= cacheEntry
->totalCurrencySymbolCount
;
1305 ++(cacheEntry
->refCount
);
1309 collectCurrencyNames(locale
, ¤cyNames
, &total_currency_name_count
, ¤cySymbols
, &total_currency_symbol_count
, ec
);
1310 if (U_FAILURE(ec
)) {
1316 for (int8_t i
= 0; i
< CURRENCY_NAME_CACHE_NUM
; ++i
) {
1317 if (currCache
[i
]!= NULL
&&
1318 uprv_strcmp(locale
, currCache
[i
]->locale
) == 0) {
1324 // insert new entry to
1325 // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
1326 // and remove the existing entry
1327 // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
1329 cacheEntry
= currCache
[currentCacheEntryIndex
];
1331 --(cacheEntry
->refCount
);
1332 // delete if the ref count is zero
1333 if (cacheEntry
->refCount
== 0) {
1334 deleteCacheEntry(cacheEntry
);
1337 cacheEntry
= (CurrencyNameCacheEntry
*)uprv_malloc(sizeof(CurrencyNameCacheEntry
));
1338 currCache
[currentCacheEntryIndex
] = cacheEntry
;
1339 uprv_strcpy(cacheEntry
->locale
, locale
);
1340 cacheEntry
->currencyNames
= currencyNames
;
1341 cacheEntry
->totalCurrencyNameCount
= total_currency_name_count
;
1342 cacheEntry
->currencySymbols
= currencySymbols
;
1343 cacheEntry
->totalCurrencySymbolCount
= total_currency_symbol_count
;
1344 cacheEntry
->refCount
= 2; // one for cache, one for reference
1345 currentCacheEntryIndex
= (currentCacheEntryIndex
+ 1) % CURRENCY_NAME_CACHE_NUM
;
1346 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY
, currency_cache_cleanup
);
1349 deleteCurrencyNames(currencyNames
, total_currency_name_count
);
1350 deleteCurrencyNames(currencySymbols
, total_currency_symbol_count
);
1351 cacheEntry
= currCache
[found
];
1352 currencyNames
= cacheEntry
->currencyNames
;
1353 total_currency_name_count
= cacheEntry
->totalCurrencyNameCount
;
1354 currencySymbols
= cacheEntry
->currencySymbols
;
1355 total_currency_symbol_count
= cacheEntry
->totalCurrencySymbolCount
;
1356 ++(cacheEntry
->refCount
);
1361 int32_t start
= pos
.getIndex();
1363 UChar inputText
[MAX_CURRENCY_NAME_LEN
];
1364 UChar upperText
[MAX_CURRENCY_NAME_LEN
];
1365 int32_t textLen
= MIN(MAX_CURRENCY_NAME_LEN
, text
.length() - start
);
1366 text
.extract(start
, textLen
, inputText
);
1367 UErrorCode ec1
= U_ZERO_ERROR
;
1368 textLen
= u_strToUpper(upperText
, MAX_CURRENCY_NAME_LEN
, inputText
, textLen
, locale
, &ec1
);
1371 int32_t matchIndex
= -1;
1372 // case in-sensitive comparision against currency names
1373 searchCurrencyName(currencyNames
, total_currency_name_count
,
1374 upperText
, textLen
, &max
, &matchIndex
);
1377 printf("search in names, max = %d, matchIndex = %d\n", max
, matchIndex
);
1380 int32_t maxInSymbol
= 0;
1381 int32_t matchIndexInSymbol
= -1;
1382 if (type
!= UCURR_LONG_NAME
) { // not name only
1383 // case sensitive comparison against currency symbols and ISO code.
1384 searchCurrencyName(currencySymbols
, total_currency_symbol_count
,
1386 &maxInSymbol
, &matchIndexInSymbol
);
1390 printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol
, matchIndexInSymbol
);
1393 if (max
>= maxInSymbol
&& matchIndex
!= -1) {
1394 u_charsToUChars(currencyNames
[matchIndex
].IsoCode
, result
, 4);
1395 pos
.setIndex(start
+ max
);
1396 } else if (maxInSymbol
>= max
&& matchIndexInSymbol
!= -1) {
1397 u_charsToUChars(currencySymbols
[matchIndexInSymbol
].IsoCode
, result
, 4);
1398 pos
.setIndex(start
+ maxInSymbol
);
1401 // decrease reference count
1403 --(cacheEntry
->refCount
);
1404 if (cacheEntry
->refCount
== 0) { // remove
1405 deleteCacheEntry(cacheEntry
);
1412 * Internal method. Given a currency ISO code and a locale, return
1413 * the "static" currency name. This is usually the same as the
1414 * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
1415 * format is applied to the number 2.0 (to yield the more common
1416 * plural) to return a static name.
1418 * This is used for backward compatibility with old currency logic in
1419 * DecimalFormat and DecimalFormatSymbols.
1422 uprv_getStaticCurrencyName(const UChar
* iso
, const char* loc
,
1423 icu::UnicodeString
& result
, UErrorCode
& ec
)
1427 UBool isChoiceFormat
;
1429 const UChar
* currname
= ucurr_getName(iso
, loc
, UCURR_SYMBOL_NAME
,
1430 &isChoiceFormat
, &len
, &ec
);
1431 if (U_SUCCESS(ec
)) {
1432 // If this is a ChoiceFormat currency, then format an
1433 // arbitrary value; pick something != 1; more common.
1435 if (isChoiceFormat
) {
1436 ChoiceFormat
f(UnicodeString(TRUE
, currname
, len
), ec
);
1437 if (U_SUCCESS(ec
)) {
1438 f
.format(2.0, result
);
1440 result
.setTo(iso
, -1);
1443 result
.setTo(currname
, -1);
1448 U_CAPI
int32_t U_EXPORT2
1449 ucurr_getDefaultFractionDigits(const UChar
* currency
, UErrorCode
* ec
) {
1450 return (_findMetaData(currency
, *ec
))[0];
1453 U_CAPI
double U_EXPORT2
1454 ucurr_getRoundingIncrement(const UChar
* currency
, UErrorCode
* ec
) {
1455 const int32_t *data
= _findMetaData(currency
, *ec
);
1457 // If the meta data is invalid, return 0.0.
1458 if (data
[0] < 0 || data
[0] > MAX_POW10
) {
1459 if (U_SUCCESS(*ec
)) {
1460 *ec
= U_INVALID_FORMAT_ERROR
;
1465 // If there is no rounding, return 0.0 to indicate no rounding. A
1466 // rounding value (data[1]) of 0 or 1 indicates no rounding.
1471 // Return data[1] / 10^(data[0]). The only actual rounding data,
1472 // as of this writing, is CHF { 2, 5 }.
1473 return double(data
[1]) / POW10
[data
[0]];
1478 typedef struct UCurrencyContext
{
1479 uint32_t currType
; /* UCurrCurrencyType */
1484 Please keep this list in alphabetical order.
1485 You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
1487 ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
1489 static const struct CurrencyList
{
1490 const char *currency
;
1492 } gCurrencyList
[] = {
1493 {"ADP", UCURR_COMMON
|UCURR_DEPRECATED
},
1494 {"AED", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1495 {"AFA", UCURR_COMMON
|UCURR_DEPRECATED
},
1496 {"AFN", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1497 {"ALK", UCURR_COMMON
|UCURR_DEPRECATED
},
1498 {"ALL", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1499 {"AMD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1500 {"ANG", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1501 {"AOA", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1502 {"AOK", UCURR_COMMON
|UCURR_DEPRECATED
},
1503 {"AON", UCURR_COMMON
|UCURR_DEPRECATED
},
1504 {"AOR", UCURR_COMMON
|UCURR_DEPRECATED
},
1505 {"ARA", UCURR_COMMON
|UCURR_DEPRECATED
},
1506 {"ARL", UCURR_COMMON
|UCURR_DEPRECATED
},
1507 {"ARM", UCURR_COMMON
|UCURR_DEPRECATED
},
1508 {"ARP", UCURR_COMMON
|UCURR_DEPRECATED
},
1509 {"ARS", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1510 {"ATS", UCURR_COMMON
|UCURR_DEPRECATED
},
1511 {"AUD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1512 {"AWG", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1513 {"AZM", UCURR_COMMON
|UCURR_DEPRECATED
},
1514 {"AZN", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1515 {"BAD", UCURR_COMMON
|UCURR_DEPRECATED
},
1516 {"BAM", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1517 {"BAN", UCURR_COMMON
|UCURR_DEPRECATED
},
1518 {"BBD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1519 {"BDT", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1520 {"BEC", UCURR_UNCOMMON
|UCURR_DEPRECATED
},
1521 {"BEF", UCURR_COMMON
|UCURR_DEPRECATED
},
1522 {"BEL", UCURR_UNCOMMON
|UCURR_DEPRECATED
},
1523 {"BGL", UCURR_COMMON
|UCURR_DEPRECATED
},
1524 {"BGM", UCURR_COMMON
|UCURR_DEPRECATED
},
1525 {"BGN", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1526 {"BGO", UCURR_COMMON
|UCURR_DEPRECATED
},
1527 {"BHD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1528 {"BIF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1529 {"BMD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1530 {"BND", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1531 {"BOB", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1532 {"BOL", UCURR_COMMON
|UCURR_DEPRECATED
},
1533 {"BOP", UCURR_COMMON
|UCURR_DEPRECATED
},
1534 {"BOV", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1535 {"BRB", UCURR_COMMON
|UCURR_DEPRECATED
},
1536 {"BRC", UCURR_COMMON
|UCURR_DEPRECATED
},
1537 {"BRE", UCURR_COMMON
|UCURR_DEPRECATED
},
1538 {"BRL", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1539 {"BRN", UCURR_COMMON
|UCURR_DEPRECATED
},
1540 {"BRR", UCURR_COMMON
|UCURR_DEPRECATED
},
1541 {"BRZ", UCURR_COMMON
|UCURR_DEPRECATED
},
1542 {"BSD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1543 {"BTN", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1544 {"BUK", UCURR_COMMON
|UCURR_DEPRECATED
},
1545 {"BWP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1546 {"BYB", UCURR_COMMON
|UCURR_DEPRECATED
},
1547 {"BYR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1548 {"BZD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1549 {"CAD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1550 {"CDF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1551 {"CHE", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1552 {"CHF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1553 {"CHW", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1554 {"CLE", UCURR_COMMON
|UCURR_DEPRECATED
},
1555 {"CLF", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1556 {"CLP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1557 {"CNX", UCURR_UNCOMMON
|UCURR_DEPRECATED
},
1558 {"CNY", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1559 {"COP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1560 {"COU", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1561 {"CRC", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1562 {"CSD", UCURR_COMMON
|UCURR_DEPRECATED
},
1563 {"CSK", UCURR_COMMON
|UCURR_DEPRECATED
},
1564 {"CUC", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1565 {"CUP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1566 {"CVE", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1567 {"CYP", UCURR_COMMON
|UCURR_DEPRECATED
},
1568 {"CZK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1569 {"DDM", UCURR_COMMON
|UCURR_DEPRECATED
},
1570 {"DEM", UCURR_COMMON
|UCURR_DEPRECATED
},
1571 {"DJF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1572 {"DKK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1573 {"DOP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1574 {"DZD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1575 {"ECS", UCURR_COMMON
|UCURR_DEPRECATED
},
1576 {"ECV", UCURR_UNCOMMON
|UCURR_DEPRECATED
},
1577 {"EEK", UCURR_COMMON
|UCURR_DEPRECATED
},
1578 {"EGP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1579 {"EQE", UCURR_COMMON
|UCURR_DEPRECATED
},
1580 {"ERN", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1581 {"ESA", UCURR_UNCOMMON
|UCURR_DEPRECATED
},
1582 {"ESB", UCURR_UNCOMMON
|UCURR_DEPRECATED
},
1583 {"ESP", UCURR_COMMON
|UCURR_DEPRECATED
},
1584 {"ETB", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1585 {"EUR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1586 {"FIM", UCURR_COMMON
|UCURR_DEPRECATED
},
1587 {"FJD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1588 {"FKP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1589 {"FRF", UCURR_COMMON
|UCURR_DEPRECATED
},
1590 {"GBP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1591 {"GEK", UCURR_COMMON
|UCURR_DEPRECATED
},
1592 {"GEL", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1593 {"GHC", UCURR_COMMON
|UCURR_DEPRECATED
},
1594 {"GHS", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1595 {"GIP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1596 {"GMD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1597 {"GNF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1598 {"GNS", UCURR_COMMON
|UCURR_DEPRECATED
},
1599 {"GQE", UCURR_COMMON
|UCURR_DEPRECATED
},
1600 {"GRD", UCURR_COMMON
|UCURR_DEPRECATED
},
1601 {"GTQ", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1602 {"GWE", UCURR_COMMON
|UCURR_DEPRECATED
},
1603 {"GWP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1604 {"GYD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1605 {"HKD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1606 {"HNL", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1607 {"HRD", UCURR_COMMON
|UCURR_DEPRECATED
},
1608 {"HRK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1609 {"HTG", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1610 {"HUF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1611 {"IDR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1612 {"IEP", UCURR_COMMON
|UCURR_DEPRECATED
},
1613 {"ILP", UCURR_COMMON
|UCURR_DEPRECATED
},
1614 {"ILR", UCURR_COMMON
|UCURR_DEPRECATED
},
1615 {"ILS", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1616 {"INR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1617 {"IQD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1618 {"IRR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1619 {"ISJ", UCURR_COMMON
|UCURR_DEPRECATED
},
1620 {"ISK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1621 {"ITL", UCURR_COMMON
|UCURR_DEPRECATED
},
1622 {"JMD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1623 {"JOD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1624 {"JPY", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1625 {"KES", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1626 {"KGS", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1627 {"KHR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1628 {"KMF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1629 {"KPW", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1630 {"KRH", UCURR_COMMON
|UCURR_DEPRECATED
},
1631 {"KRO", UCURR_COMMON
|UCURR_DEPRECATED
},
1632 {"KRW", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1633 {"KWD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1634 {"KYD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1635 {"KZT", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1636 {"LAK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1637 {"LBP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1638 {"LKR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1639 {"LRD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1640 {"LSL", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1641 {"LSM", UCURR_COMMON
|UCURR_DEPRECATED
},
1642 {"LTL", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1643 {"LTT", UCURR_COMMON
|UCURR_DEPRECATED
},
1644 {"LUC", UCURR_UNCOMMON
|UCURR_DEPRECATED
},
1645 {"LUF", UCURR_COMMON
|UCURR_DEPRECATED
},
1646 {"LUL", UCURR_UNCOMMON
|UCURR_DEPRECATED
},
1647 {"LVL", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1648 {"LVR", UCURR_COMMON
|UCURR_DEPRECATED
},
1649 {"LYD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1650 {"MAD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1651 {"MAF", UCURR_COMMON
|UCURR_DEPRECATED
},
1652 {"MCF", UCURR_COMMON
|UCURR_DEPRECATED
},
1653 {"MDC", UCURR_COMMON
|UCURR_DEPRECATED
},
1654 {"MDL", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1655 {"MGA", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1656 {"MGF", UCURR_COMMON
|UCURR_DEPRECATED
},
1657 {"MKD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1658 {"MKN", UCURR_COMMON
|UCURR_DEPRECATED
},
1659 {"MLF", UCURR_COMMON
|UCURR_DEPRECATED
},
1660 {"MMK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1661 {"MNT", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1662 {"MOP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1663 {"MRO", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1664 {"MTL", UCURR_COMMON
|UCURR_DEPRECATED
},
1665 {"MTP", UCURR_COMMON
|UCURR_DEPRECATED
},
1666 {"MUR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1667 {"MVP", UCURR_COMMON
|UCURR_DEPRECATED
},
1668 {"MVR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1669 {"MWK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1670 {"MXN", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1671 {"MXP", UCURR_COMMON
|UCURR_DEPRECATED
},
1672 {"MXV", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1673 {"MYR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1674 {"MZE", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1675 {"MZM", UCURR_COMMON
|UCURR_DEPRECATED
},
1676 {"MZN", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1677 {"NAD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1678 {"NGN", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1679 {"NIC", UCURR_COMMON
|UCURR_DEPRECATED
},
1680 {"NIO", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1681 {"NLG", UCURR_COMMON
|UCURR_DEPRECATED
},
1682 {"NOK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1683 {"NPR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1684 {"NZD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1685 {"OMR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1686 {"PAB", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1687 {"PEI", UCURR_COMMON
|UCURR_DEPRECATED
},
1688 {"PEN", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1689 {"PES", UCURR_COMMON
|UCURR_DEPRECATED
},
1690 {"PGK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1691 {"PHP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1692 {"PKR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1693 {"PLN", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1694 {"PLZ", UCURR_COMMON
|UCURR_DEPRECATED
},
1695 {"PTE", UCURR_COMMON
|UCURR_DEPRECATED
},
1696 {"PYG", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1697 {"QAR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1698 {"RHD", UCURR_COMMON
|UCURR_DEPRECATED
},
1699 {"ROL", UCURR_COMMON
|UCURR_DEPRECATED
},
1700 {"RON", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1701 {"RSD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1702 {"RUB", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1703 {"RUR", UCURR_COMMON
|UCURR_DEPRECATED
},
1704 {"RWF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1705 {"SAR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1706 {"SBD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1707 {"SCR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1708 {"SDD", UCURR_COMMON
|UCURR_DEPRECATED
},
1709 {"SDG", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1710 {"SDP", UCURR_COMMON
|UCURR_DEPRECATED
},
1711 {"SEK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1712 {"SGD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1713 {"SHP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1714 {"SIT", UCURR_COMMON
|UCURR_DEPRECATED
},
1715 {"SKK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1716 {"SLL", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1717 {"SOS", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1718 {"SRD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1719 {"SRG", UCURR_COMMON
|UCURR_DEPRECATED
},
1720 {"STD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1721 {"SUR", UCURR_COMMON
|UCURR_DEPRECATED
},
1722 {"SVC", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1723 {"SYP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1724 {"SZL", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1725 {"THB", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1726 {"TJR", UCURR_COMMON
|UCURR_DEPRECATED
},
1727 {"TJS", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1728 {"TMM", UCURR_COMMON
|UCURR_DEPRECATED
},
1729 {"TMT", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1730 {"TND", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1731 {"TOP", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1732 {"TPE", UCURR_COMMON
|UCURR_DEPRECATED
},
1733 {"TRL", UCURR_COMMON
|UCURR_DEPRECATED
},
1734 {"TRY", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1735 {"TTD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1736 {"TWD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1737 {"TZS", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1738 {"UAH", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1739 {"UAK", UCURR_COMMON
|UCURR_DEPRECATED
},
1740 {"UGS", UCURR_COMMON
|UCURR_DEPRECATED
},
1741 {"UGX", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1742 {"USD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1743 {"USN", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1744 {"USS", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1745 {"UYI", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1746 {"UYP", UCURR_COMMON
|UCURR_DEPRECATED
},
1747 {"UYU", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1748 {"UZS", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1749 {"VEB", UCURR_COMMON
|UCURR_DEPRECATED
},
1750 {"VEF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1751 {"VND", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1752 {"VNN", UCURR_COMMON
|UCURR_DEPRECATED
},
1753 {"VUV", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1754 {"WST", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1755 {"XAF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1756 {"XAG", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1757 {"XAU", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1758 {"XBA", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1759 {"XBB", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1760 {"XBC", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1761 {"XBD", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1762 {"XCD", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1763 {"XDR", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1764 {"XEU", UCURR_UNCOMMON
|UCURR_DEPRECATED
},
1765 {"XFO", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1766 {"XFU", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1767 {"XOF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1768 {"XPD", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1769 {"XPF", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1770 {"XPT", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1771 {"XRE", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1772 {"XTS", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1773 {"XXX", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1774 {"YDD", UCURR_COMMON
|UCURR_DEPRECATED
},
1775 {"YER", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1776 {"YUD", UCURR_COMMON
|UCURR_DEPRECATED
},
1777 {"YUM", UCURR_COMMON
|UCURR_DEPRECATED
},
1778 {"YUN", UCURR_COMMON
|UCURR_DEPRECATED
},
1779 {"YUR", UCURR_COMMON
|UCURR_DEPRECATED
},
1780 {"ZAL", UCURR_UNCOMMON
|UCURR_NON_DEPRECATED
},
1781 {"ZAR", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1782 {"ZMK", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1783 {"ZRN", UCURR_COMMON
|UCURR_DEPRECATED
},
1784 {"ZRZ", UCURR_COMMON
|UCURR_DEPRECATED
},
1785 {"ZWL", UCURR_COMMON
|UCURR_NON_DEPRECATED
},
1786 {"ZWR", UCURR_COMMON
|UCURR_DEPRECATED
},
1787 {"ZWD", UCURR_COMMON
|UCURR_DEPRECATED
},
1788 { NULL
, 0 } // Leave here to denote the end of the list.
1791 #define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
1792 ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
1794 static int32_t U_CALLCONV
1795 ucurr_countCurrencyList(UEnumeration
*enumerator
, UErrorCode
* /*pErrorCode*/) {
1796 UCurrencyContext
*myContext
= (UCurrencyContext
*)(enumerator
->context
);
1797 uint32_t currType
= myContext
->currType
;
1800 /* Count the number of items matching the type we are looking for. */
1801 for (int32_t idx
= 0; gCurrencyList
[idx
].currency
!= NULL
; idx
++) {
1802 if (UCURR_MATCHES_BITMASK(gCurrencyList
[idx
].currType
, currType
)) {
1809 static const char* U_CALLCONV
1810 ucurr_nextCurrencyList(UEnumeration
*enumerator
,
1811 int32_t* resultLength
,
1812 UErrorCode
* /*pErrorCode*/)
1814 UCurrencyContext
*myContext
= (UCurrencyContext
*)(enumerator
->context
);
1816 /* Find the next in the list that matches the type we are looking for. */
1817 while (myContext
->listIdx
< (sizeof(gCurrencyList
)/sizeof(gCurrencyList
[0]))-1) {
1818 const struct CurrencyList
*currItem
= &gCurrencyList
[myContext
->listIdx
++];
1819 if (UCURR_MATCHES_BITMASK(currItem
->currType
, myContext
->currType
))
1822 *resultLength
= 3; /* Currency codes are only 3 chars long */
1824 return currItem
->currency
;
1827 /* We enumerated too far. */
1834 static void U_CALLCONV
1835 ucurr_resetCurrencyList(UEnumeration
*enumerator
, UErrorCode
* /*pErrorCode*/) {
1836 ((UCurrencyContext
*)(enumerator
->context
))->listIdx
= 0;
1839 static void U_CALLCONV
1840 ucurr_closeCurrencyList(UEnumeration
*enumerator
) {
1841 uprv_free(enumerator
->context
);
1842 uprv_free(enumerator
);
1845 static void U_CALLCONV
1846 ucurr_createCurrencyList(UErrorCode
* status
){
1847 UErrorCode localStatus
= U_ZERO_ERROR
;
1849 // Look up the CurrencyMap element in the root bundle.
1850 UResourceBundle
*rb
= ures_openDirect(U_ICUDATA_CURR
, CURRENCY_DATA
, &localStatus
);
1851 UResourceBundle
*currencyMapArray
= ures_getByKey(rb
, CURRENCY_MAP
, rb
, &localStatus
);
1853 if (U_SUCCESS(localStatus
)) {
1854 // process each entry in currency map
1855 for (int32_t i
=0; i
<ures_getSize(currencyMapArray
); i
++) {
1856 // get the currency resource
1857 UResourceBundle
*currencyArray
= ures_getByIndex(currencyMapArray
, i
, NULL
, &localStatus
);
1858 // process each currency
1859 if (U_SUCCESS(localStatus
)) {
1860 for (int32_t j
=0; j
<ures_getSize(currencyArray
); j
++) {
1861 // get the currency resource
1862 UResourceBundle
*currencyRes
= ures_getByIndex(currencyArray
, j
, NULL
, &localStatus
);
1863 IsoCodeEntry
*entry
= (IsoCodeEntry
*)uprv_malloc(sizeof(IsoCodeEntry
));
1864 if (entry
== NULL
) {
1865 *status
= U_MEMORY_ALLOCATION_ERROR
;
1870 int32_t isoLength
= 0;
1871 UResourceBundle
*idRes
= ures_getByKey(currencyRes
, "id", NULL
, &localStatus
);
1872 if (idRes
== NULL
) {
1875 const UChar
*isoCode
= ures_getString(idRes
, &isoLength
, &localStatus
);
1877 // get the from date
1878 int32_t fromLength
= 0;
1879 UResourceBundle
*fromRes
= ures_getByKey(currencyRes
, "from", NULL
, &localStatus
);
1880 const int32_t *fromArray
= ures_getIntVector(fromRes
, &fromLength
, &localStatus
);
1881 int64_t currDate64
= (int64_t)fromArray
[0] << 32;
1882 currDate64
|= ((int64_t)fromArray
[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
1883 UDate fromDate
= (UDate
)currDate64
;
1884 UDate toDate
= U_DATE_MAX
;
1886 if (ures_getSize(currencyRes
)> 2) {
1887 int32_t toLength
= 0;
1888 UResourceBundle
*toRes
= ures_getByKey(currencyRes
, "to", NULL
, &localStatus
);
1889 const int32_t *toArray
= ures_getIntVector(toRes
, &toLength
, &localStatus
);
1891 currDate64
= (int64_t)toArray
[0] << 32;
1892 currDate64
|= ((int64_t)toArray
[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
1893 toDate
= (UDate
)currDate64
;
1898 ures_close(fromRes
);
1900 ures_close(currencyRes
);
1902 entry
->isoCode
= isoCode
;
1903 entry
->from
= fromDate
;
1906 uhash_put(gIsoCodes
, (UChar
*)isoCode
, entry
, &localStatus
);
1909 *status
= localStatus
;
1911 ures_close(currencyArray
);
1914 *status
= localStatus
;
1917 ures_close(currencyMapArray
);
1920 static const UEnumeration gEnumCurrencyList
= {
1923 ucurr_closeCurrencyList
,
1924 ucurr_countCurrencyList
,
1926 ucurr_nextCurrencyList
,
1927 ucurr_resetCurrencyList
1931 U_CAPI UBool U_EXPORT2
1932 ucurr_isAvailable(const UChar
* isoCode
, UDate from
, UDate to
, UErrorCode
* eErrorCode
) {
1933 UErrorCode status
= U_ZERO_ERROR
;
1935 UMTX_CHECK(&gIsoCodesLock
, gIsoCodesInitialized
, initialized
);
1938 umtx_lock(&gIsoCodesLock
);
1939 gIsoCodes
= uhash_open(uhash_hashUChars
, uhash_compareUChars
, NULL
, &status
);
1940 if (U_FAILURE(status
)) {
1941 umtx_unlock(&gIsoCodesLock
);
1944 uhash_setValueDeleter(gIsoCodes
, deleteIsoCodeEntry
);
1946 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY
, currency_cleanup
);
1948 ucurr_createCurrencyList(&status
);
1949 if (U_FAILURE(status
)) {
1950 umtx_unlock(&gIsoCodesLock
);
1954 gIsoCodesInitialized
= TRUE
;
1955 umtx_unlock(&gIsoCodesLock
);
1958 umtx_lock(&gIsoCodesLock
);
1959 IsoCodeEntry
* result
= (IsoCodeEntry
*) uhash_get(gIsoCodes
, isoCode
);
1960 umtx_unlock(&gIsoCodesLock
);
1962 if (result
== NULL
) {
1964 } else if (from
> to
) {
1965 *eErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1967 } else if ((from
> result
->to
) || (to
< result
->from
)) {
1974 U_CAPI UEnumeration
* U_EXPORT2
1975 ucurr_openISOCurrencies(uint32_t currType
, UErrorCode
*pErrorCode
) {
1976 UEnumeration
*myEnum
= NULL
;
1977 UCurrencyContext
*myContext
;
1979 myEnum
= (UEnumeration
*)uprv_malloc(sizeof(UEnumeration
));
1980 if (myEnum
== NULL
) {
1981 *pErrorCode
= U_MEMORY_ALLOCATION_ERROR
;
1984 uprv_memcpy(myEnum
, &gEnumCurrencyList
, sizeof(UEnumeration
));
1985 myContext
= (UCurrencyContext
*)uprv_malloc(sizeof(UCurrencyContext
));
1986 if (myContext
== NULL
) {
1987 *pErrorCode
= U_MEMORY_ALLOCATION_ERROR
;
1991 myContext
->currType
= currType
;
1992 myContext
->listIdx
= 0;
1993 myEnum
->context
= myContext
;
1997 U_CAPI
int32_t U_EXPORT2
1998 ucurr_countCurrencies(const char* locale
,
2002 int32_t currCount
= 0;
2004 if (ec
!= NULL
&& U_SUCCESS(*ec
))
2007 UErrorCode localStatus
= U_ZERO_ERROR
;
2008 char id
[ULOC_FULLNAME_CAPACITY
];
2009 uloc_getKeywordValue(locale
, "currency", id
, ULOC_FULLNAME_CAPACITY
, &localStatus
);
2010 // get country or country_variant in `id'
2011 /*uint32_t variantType =*/ idForLocale(locale
, id
, sizeof(id
), ec
);
2018 // Remove variants, which is only needed for registration.
2019 char *idDelim
= strchr(id
, VAR_DELIM
);
2025 // Look up the CurrencyMap element in the root bundle.
2026 UResourceBundle
*rb
= ures_openDirect(U_ICUDATA_CURR
, CURRENCY_DATA
, &localStatus
);
2027 UResourceBundle
*cm
= ures_getByKey(rb
, CURRENCY_MAP
, rb
, &localStatus
);
2029 // Using the id derived from the local, get the currency data
2030 UResourceBundle
*countryArray
= ures_getByKey(rb
, id
, cm
, &localStatus
);
2032 // process each currency to see which one is valid for the given date
2033 if (U_SUCCESS(localStatus
))
2035 for (int32_t i
=0; i
<ures_getSize(countryArray
); i
++)
2037 // get the currency resource
2038 UResourceBundle
*currencyRes
= ures_getByIndex(countryArray
, i
, NULL
, &localStatus
);
2040 // get the from date
2041 int32_t fromLength
= 0;
2042 UResourceBundle
*fromRes
= ures_getByKey(currencyRes
, "from", NULL
, &localStatus
);
2043 const int32_t *fromArray
= ures_getIntVector(fromRes
, &fromLength
, &localStatus
);
2045 int64_t currDate64
= (int64_t)fromArray
[0] << 32;
2046 currDate64
|= ((int64_t)fromArray
[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2047 UDate fromDate
= (UDate
)currDate64
;
2049 if (ures_getSize(currencyRes
)> 2)
2051 int32_t toLength
= 0;
2052 UResourceBundle
*toRes
= ures_getByKey(currencyRes
, "to", NULL
, &localStatus
);
2053 const int32_t *toArray
= ures_getIntVector(toRes
, &toLength
, &localStatus
);
2055 currDate64
= (int64_t)toArray
[0] << 32;
2056 currDate64
|= ((int64_t)toArray
[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2057 UDate toDate
= (UDate
)currDate64
;
2059 if ((fromDate
<= date
) && (date
< toDate
))
2068 if (fromDate
<= date
)
2074 // close open resources
2075 ures_close(currencyRes
);
2076 ures_close(fromRes
);
2079 } // end if (U_SUCCESS(localStatus))
2081 ures_close(countryArray
);
2084 if (*ec
== U_ZERO_ERROR
|| localStatus
!= U_ZERO_ERROR
)
2086 // There is nothing to fallback to.
2087 // Report the failure/warning if possible.
2099 // If we got here, either error code is invalid or
2100 // some argument passed is no good.
2104 U_CAPI
int32_t U_EXPORT2
2105 ucurr_forLocaleAndDate(const char* locale
,
2109 int32_t buffCapacity
,
2113 int32_t currIndex
= 0;
2114 const UChar
* s
= NULL
;
2116 if (ec
!= NULL
&& U_SUCCESS(*ec
))
2118 // check the arguments passed
2119 if ((buff
&& buffCapacity
) || !buffCapacity
)
2122 UErrorCode localStatus
= U_ZERO_ERROR
;
2123 char id
[ULOC_FULLNAME_CAPACITY
];
2124 resLen
= uloc_getKeywordValue(locale
, "currency", id
, ULOC_FULLNAME_CAPACITY
, &localStatus
);
2126 // get country or country_variant in `id'
2127 /*uint32_t variantType =*/ idForLocale(locale
, id
, sizeof(id
), ec
);
2133 // Remove variants, which is only needed for registration.
2134 char *idDelim
= strchr(id
, VAR_DELIM
);
2140 // Look up the CurrencyMap element in the root bundle.
2141 UResourceBundle
*rb
= ures_openDirect(U_ICUDATA_CURR
, CURRENCY_DATA
, &localStatus
);
2142 UResourceBundle
*cm
= ures_getByKey(rb
, CURRENCY_MAP
, rb
, &localStatus
);
2144 // Using the id derived from the local, get the currency data
2145 UResourceBundle
*countryArray
= ures_getByKey(rb
, id
, cm
, &localStatus
);
2147 // process each currency to see which one is valid for the given date
2148 bool matchFound
= false;
2149 if (U_SUCCESS(localStatus
))
2151 if ((index
<= 0) || (index
> ures_getSize(countryArray
)))
2153 // requested index is out of bounds
2154 ures_close(countryArray
);
2158 for (int32_t i
=0; i
<ures_getSize(countryArray
); i
++)
2160 // get the currency resource
2161 UResourceBundle
*currencyRes
= ures_getByIndex(countryArray
, i
, NULL
, &localStatus
);
2162 s
= ures_getStringByKey(currencyRes
, "id", &resLen
, &localStatus
);
2164 // get the from date
2165 int32_t fromLength
= 0;
2166 UResourceBundle
*fromRes
= ures_getByKey(currencyRes
, "from", NULL
, &localStatus
);
2167 const int32_t *fromArray
= ures_getIntVector(fromRes
, &fromLength
, &localStatus
);
2169 int64_t currDate64
= (int64_t)fromArray
[0] << 32;
2170 currDate64
|= ((int64_t)fromArray
[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2171 UDate fromDate
= (UDate
)currDate64
;
2173 if (ures_getSize(currencyRes
)> 2)
2175 int32_t toLength
= 0;
2176 UResourceBundle
*toRes
= ures_getByKey(currencyRes
, "to", NULL
, &localStatus
);
2177 const int32_t *toArray
= ures_getIntVector(toRes
, &toLength
, &localStatus
);
2179 currDate64
= (int64_t)toArray
[0] << 32;
2180 currDate64
|= ((int64_t)toArray
[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2181 UDate toDate
= (UDate
)currDate64
;
2183 if ((fromDate
<= date
) && (date
< toDate
))
2186 if (currIndex
== index
)
2196 if (fromDate
<= date
)
2199 if (currIndex
== index
)
2206 // close open resources
2207 ures_close(currencyRes
);
2208 ures_close(fromRes
);
2210 // check for loop exit
2219 ures_close(countryArray
);
2222 if (*ec
== U_ZERO_ERROR
|| localStatus
!= U_ZERO_ERROR
)
2224 // There is nothing to fallback to.
2225 // Report the failure/warning if possible.
2232 if((buffCapacity
> resLen
) && matchFound
)
2234 // write out the currency value
2243 // return null terminated currency string
2244 return u_terminateUChars(buff
, buffCapacity
, resLen
, ec
);
2248 // illegal argument encountered
2249 *ec
= U_ILLEGAL_ARGUMENT_ERROR
;
2254 // If we got here, either error code is invalid or
2255 // some argument passed is no good.
2259 static const UEnumeration defaultKeywordValues
= {
2262 ulist_close_keyword_values_iterator
,
2263 ulist_count_keyword_values
,
2265 ulist_next_keyword_value
,
2266 ulist_reset_keyword_values_iterator
2269 U_CAPI UEnumeration
*U_EXPORT2
ucurr_getKeywordValuesForLocale(const char *key
, const char *locale
, UBool commonlyUsed
, UErrorCode
* status
) {
2271 char prefRegion
[ULOC_FULLNAME_CAPACITY
] = "";
2272 int32_t prefRegionLength
= 0;
2273 prefRegionLength
= uloc_getCountry(locale
, prefRegion
, sizeof(prefRegion
), status
);
2274 if (prefRegionLength
== 0) {
2275 char loc
[ULOC_FULLNAME_CAPACITY
] = "";
2276 uloc_addLikelySubtags(locale
, loc
, sizeof(loc
), status
);
2278 prefRegionLength
= uloc_getCountry(loc
, prefRegion
, sizeof(prefRegion
), status
);
2281 // Read value from supplementalData
2282 UList
*values
= ulist_createEmptyList(status
);
2283 UList
*otherValues
= ulist_createEmptyList(status
);
2284 UEnumeration
*en
= (UEnumeration
*)uprv_malloc(sizeof(UEnumeration
));
2285 if (U_FAILURE(*status
) || en
== NULL
) {
2287 *status
= U_MEMORY_ALLOCATION_ERROR
;
2291 ulist_deleteList(values
);
2292 ulist_deleteList(otherValues
);
2295 memcpy(en
, &defaultKeywordValues
, sizeof(UEnumeration
));
2296 en
->context
= values
;
2298 UResourceBundle
*bundle
= ures_openDirect(U_ICUDATA_CURR
, "supplementalData", status
);
2299 ures_getByKey(bundle
, "CurrencyMap", bundle
, status
);
2300 UResourceBundle bundlekey
, regbndl
, curbndl
, to
;
2301 ures_initStackObject(&bundlekey
);
2302 ures_initStackObject(®bndl
);
2303 ures_initStackObject(&curbndl
);
2304 ures_initStackObject(&to
);
2306 while (U_SUCCESS(*status
) && ures_hasNext(bundle
)) {
2307 ures_getNextResource(bundle
, &bundlekey
, status
);
2308 if (U_FAILURE(*status
)) {
2311 const char *region
= ures_getKey(&bundlekey
);
2312 UBool isPrefRegion
= uprv_strcmp(region
, prefRegion
) == 0 ? TRUE
: FALSE
;
2313 if (!isPrefRegion
&& commonlyUsed
) {
2314 // With commonlyUsed=true, we do not put
2315 // currencies for other regions in the
2319 ures_getByKey(bundle
, region
, ®bndl
, status
);
2320 if (U_FAILURE(*status
)) {
2323 while (U_SUCCESS(*status
) && ures_hasNext(®bndl
)) {
2324 ures_getNextResource(®bndl
, &curbndl
, status
);
2325 if (ures_getType(&curbndl
) != URES_TABLE
) {
2326 // Currently, an empty ARRAY is mixed in.
2329 char *curID
= (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY
);
2330 int32_t curIDLength
= ULOC_KEYWORDS_CAPACITY
;
2331 if (curID
== NULL
) {
2332 *status
= U_MEMORY_ALLOCATION_ERROR
;
2336 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
2337 ures_getUTF8StringByKey(&curbndl
, "id", curID
, &curIDLength
, TRUE
, status
);
2338 /* optimize - use the utf-8 string */
2341 const UChar
* defString
= ures_getStringByKey(&curbndl
, "id", &curIDLength
, status
);
2342 if(U_SUCCESS(*status
)) {
2343 if(curIDLength
+1 > ULOC_KEYWORDS_CAPACITY
) {
2344 *status
= U_BUFFER_OVERFLOW_ERROR
;
2346 u_UCharsToChars(defString
, curID
, curIDLength
+1);
2352 if (U_FAILURE(*status
)) {
2355 UBool hasTo
= FALSE
;
2356 ures_getByKey(&curbndl
, "to", &to
, status
);
2357 if (U_FAILURE(*status
)) {
2358 // Do nothing here...
2359 *status
= U_ZERO_ERROR
;
2363 if (isPrefRegion
&& !hasTo
&& !ulist_containsString(values
, curID
, (int32_t)uprv_strlen(curID
))) {
2364 // Currently active currency for the target country
2365 ulist_addItemEndList(values
, curID
, TRUE
, status
);
2366 } else if (!ulist_containsString(otherValues
, curID
, (int32_t)uprv_strlen(curID
)) && !commonlyUsed
) {
2367 ulist_addItemEndList(otherValues
, curID
, TRUE
, status
);
2374 if (U_SUCCESS(*status
)) {
2376 if (ulist_getListSize(values
) == 0) {
2377 // This could happen if no valid region is supplied in the input
2378 // locale. In this case, we use the CLDR's default.
2380 en
= ucurr_getKeywordValuesForLocale(key
, "und", TRUE
, status
);
2383 // Consolidate the list
2385 ulist_resetList(otherValues
);
2386 while ((value
= (char *)ulist_getNext(otherValues
)) != NULL
) {
2387 if (!ulist_containsString(values
, value
, (int32_t)uprv_strlen(value
))) {
2388 char *tmpValue
= (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY
);
2389 uprv_memcpy(tmpValue
, value
, uprv_strlen(value
) + 1);
2390 ulist_addItemEndList(values
, tmpValue
, TRUE
, status
);
2391 if (U_FAILURE(*status
)) {
2398 ulist_resetList((UList
*)(en
->context
));
2400 ulist_deleteList(values
);
2406 ures_close(&curbndl
);
2407 ures_close(®bndl
);
2408 ures_close(&bundlekey
);
2411 ulist_deleteList(otherValues
);
2417 U_CAPI
int32_t U_EXPORT2
2418 ucurr_getNumericCode(const UChar
* currency
) {
2420 if (currency
&& u_strlen(currency
) == ISO_CURRENCY_CODE_LENGTH
) {
2421 UErrorCode status
= U_ZERO_ERROR
;
2423 UResourceBundle
*bundle
= ures_openDirect(0, "currencyNumericCodes", &status
);
2424 ures_getByKey(bundle
, "codeMap", bundle
, &status
);
2425 if (U_SUCCESS(status
)) {
2426 char alphaCode
[ISO_CURRENCY_CODE_LENGTH
+1];
2427 myUCharsToChars(alphaCode
, currency
);
2428 T_CString_toUpperCase(alphaCode
);
2429 ures_getByKey(bundle
, alphaCode
, bundle
, &status
);
2430 int tmpCode
= ures_getInt(bundle
, &status
);
2431 if (U_SUCCESS(status
)) {
2439 #endif /* #if !UCONFIG_NO_FORMATTING */