2 **********************************************************************
3 * Copyright (c) 2002-2010, 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 //------------------------------------------------------------
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 };
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 };
48 static const int32_t MAX_POW10
= (sizeof(POW10
)/sizeof(POW10
[0])) - 1;
50 #define ISO_COUNTRY_CODE_LENGTH 3
52 //------------------------------------------------------------
56 static const char CURRENCY_DATA
[] = "supplementalData";
57 // Tag for meta-data, in root.
58 static const char CURRENCY_META
[] = "CurrencyMeta";
60 // Tag for map from countries to currencies, in root.
61 static const char CURRENCY_MAP
[] = "CurrencyMap";
63 // Tag for default meta-data, in CURRENCY_META
64 static const char DEFAULT_META
[] = "DEFAULT";
66 // Variant for legacy pre-euro mapping in CurrencyMap
67 static const char VAR_PRE_EURO
[] = "PREEURO";
69 // Variant for legacy euro mapping in CurrencyMap
70 static const char VAR_EURO
[] = "EURO";
73 static const char VAR_DELIM
= '_';
74 static const char VAR_DELIM_STR
[] = "_";
76 // Variant for legacy euro mapping in CurrencyMap
77 //static const char VAR_DELIM_EURO[] = "_EURO";
79 #define VARIANT_IS_EMPTY 0
80 #define VARIANT_IS_EURO 0x1
81 #define VARIANT_IS_PREEURO 0x2
83 // Tag for localized display names (symbols) of currencies
84 static const char CURRENCIES
[] = "Currencies";
85 static const char CURRENCYPLURALS
[] = "CurrencyPlurals";
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
93 static const UChar EUR_STR
[] = {0x0045,0x0055,0x0052,0};
95 //------------------------------------------------------------
99 * Unfortunately, we have to convert the UChar* currency code to char*
100 * to use it as a resource key.
103 myUCharsToChars(char* resultOfLen4
, const UChar
* currency
) {
104 u_UCharsToChars(currency
, resultOfLen4
, ISO_COUNTRY_CODE_LENGTH
);
105 resultOfLen4
[ISO_COUNTRY_CODE_LENGTH
] = 0;
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).
115 static const int32_t*
116 _findMetaData(const UChar
* currency
, UErrorCode
& ec
) {
118 if (currency
== 0 || *currency
== 0) {
120 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
122 return LAST_RESORT_DATA
;
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
128 UResourceBundle
* currencyData
= ures_openDirect(U_ICUDATA_CURR
, CURRENCY_DATA
, &ec
);
129 UResourceBundle
* currencyMeta
= ures_getByKey(currencyData
, CURRENCY_META
, currencyData
, &ec
);
132 ures_close(currencyMeta
);
133 // Config/build error; return hard-coded defaults
134 return LAST_RESORT_DATA
;
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
)) {
143 rb
= ures_getByKey(currencyMeta
,DEFAULT_META
, NULL
, &ec
);
145 ures_close(currencyMeta
);
147 // Config/build error; return hard-coded defaults
148 return LAST_RESORT_DATA
;
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
157 ec
= U_INVALID_FORMAT_ERROR
;
159 ures_close(currencyMeta
);
161 return LAST_RESORT_DATA
;
164 ures_close(currencyMeta
);
169 // -------------------------------------
172 * @see VARIANT_IS_EURO
173 * @see VARIANT_IS_PREEURO
176 idForLocale(const char* locale
, char* countryAndVariant
, int capacity
, UErrorCode
* ec
)
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);
190 uprv_strcat(countryAndVariant
, VAR_DELIM_STR
);
191 uprv_strcat(countryAndVariant
, variant
);
197 // ------------------------------------------
201 //-------------------------------------------
203 // don't use ICUService since we don't need fallback
205 #if !UCONFIG_NO_SERVICE
207 static UBool U_CALLCONV
currency_cleanup(void);
211 static UMTX gCRegLock
= 0;
212 static CReg
* gCRegHead
= 0;
214 struct CReg
: public U_NAMESPACE_QUALIFIER UMemory
{
216 UChar iso
[ISO_COUNTRY_CODE_LENGTH
+1];
217 char id
[ULOC_FULLNAME_CAPACITY
];
219 CReg(const UChar
* _iso
, const char* _id
)
222 int32_t len
= (int32_t)uprv_strlen(_id
);
223 if (len
> (int32_t)(sizeof(id
)-1)) {
224 len
= (sizeof(id
)-1);
226 uprv_strncpy(id
, _id
, len
);
228 uprv_memcpy(iso
, _iso
, ISO_COUNTRY_CODE_LENGTH
* sizeof(const UChar
));
229 iso
[ISO_COUNTRY_CODE_LENGTH
] = 0;
232 static UCurrRegistryKey
reg(const UChar
* _iso
, const char* _id
, UErrorCode
* status
)
234 if (status
&& U_SUCCESS(*status
) && _iso
&& _id
) {
235 CReg
* n
= new CReg(_iso
, _id
);
237 umtx_lock(&gCRegLock
);
239 /* register for the first time */
240 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY
, currency_cleanup
);
244 umtx_unlock(&gCRegLock
);
247 *status
= U_MEMORY_ALLOCATION_ERROR
;
252 static UBool
unreg(UCurrRegistryKey key
) {
254 umtx_lock(&gCRegLock
);
256 CReg
** p
= &gCRegHead
;
259 *p
= ((CReg
*)key
)->next
;
267 umtx_unlock(&gCRegLock
);
271 static const UChar
* get(const char* id
) {
272 const UChar
* result
= NULL
;
273 umtx_lock(&gCRegLock
);
276 /* register cleanup of the mutex */
277 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY
, currency_cleanup
);
279 if (uprv_strcmp(id
, p
->id
) == 0) {
285 umtx_unlock(&gCRegLock
);
289 /* This doesn't need to be thread safe. It's for u_cleanup only. */
290 static void cleanup(void) {
293 gCRegHead
= gCRegHead
->next
;
296 umtx_destroy(&gCRegLock
);
301 * Release all static memory held by currency.
303 /*The declaration here is needed so currency_cleanup(void)
304 * can call this function.
306 static UBool U_CALLCONV
307 currency_cache_cleanup(void);
310 static UBool U_CALLCONV
currency_cleanup(void) {
311 #if !UCONFIG_NO_SERVICE
315 * There might be some cached currency data.
317 currency_cache_cleanup();
322 // -------------------------------------
324 U_CAPI UCurrRegistryKey U_EXPORT2
325 ucurr_register(const UChar
* isoCode
, const char* locale
, UErrorCode
*status
)
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
);
335 // -------------------------------------
337 U_CAPI UBool U_EXPORT2
338 ucurr_unregister(UCurrRegistryKey key
, UErrorCode
* status
)
340 if (status
&& U_SUCCESS(*status
)) {
341 return CReg::unreg(key
);
345 #endif /* UCONFIG_NO_SERVICE */
347 // -------------------------------------
349 U_CAPI
int32_t U_EXPORT2
350 ucurr_forLocale(const char* locale
,
352 int32_t buffCapacity
,
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
);
369 // get country or country_variant in `id'
370 uint32_t variantType
= idForLocale(locale
, id
, sizeof(id
), ec
);
372 if (U_FAILURE(*ec
)) {
376 #if !UCONFIG_NO_SERVICE
377 const UChar
* result
= CReg::get(id
);
379 if(buffCapacity
> u_strlen(result
)) {
380 u_strcpy(buff
, result
);
382 return u_strlen(result
);
385 // Remove variants, which is only needed for registration.
386 char *idDelim
= strchr(id
, VAR_DELIM
);
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
);
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
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
);
410 else if ((variantType
& VARIANT_IS_EURO
)) {
414 ures_close(countryArray
);
415 ures_close(currencyReq
);
417 if ((U_FAILURE(localStatus
)) && strchr(id
, '_') != 0)
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
);
424 else if (*ec
== U_ZERO_ERROR
|| localStatus
!= U_ZERO_ERROR
) {
425 // There is nothing to fallback to. Report the failure/warning if possible.
428 if (U_SUCCESS(*ec
)) {
429 if(buffCapacity
> resLen
) {
434 return u_terminateUChars(buff
, buffCapacity
, resLen
, ec
);
436 *ec
= U_ILLEGAL_ARGUMENT_ERROR
;
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
451 static UBool
fallback(char *loc
) {
455 UErrorCode status
= U_ZERO_ERROR
;
456 uloc_getParent(loc
, loc
, (int32_t)uprv_strlen(loc
), &status
);
458 char *i = uprv_strrchr(loc, '_');
468 U_CAPI
const UChar
* U_EXPORT2
469 ucurr_getName(const UChar
* currency
,
471 UCurrNameStyle nameStyle
,
472 UBool
* isChoiceFormat
, // fillin
473 int32_t* len
, // fillin
476 // Look up the Currencies resource for the given locale. The
477 // Currencies locale data looks like this:
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" }
487 if (U_FAILURE(*ec
)) {
491 int32_t choice
= (int32_t) nameStyle
;
492 if (choice
< 0 || choice
> 1) {
493 *ec
= U_ILLEGAL_ARGUMENT_ERROR
;
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.
503 // We want multi-level fallback for this resource, so we implement
506 // Use a separate UErrorCode here that does not propagate out of
508 UErrorCode ec2
= U_ZERO_ERROR
;
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
;
517 char buf
[ISO_COUNTRY_CODE_LENGTH
+1];
518 myUCharsToChars(buf
, currency
);
520 /* Normalize the keyword value to uppercase */
521 T_CString_toUpperCase(buf
);
523 const UChar
* s
= NULL
;
525 UResourceBundle
* rb
= ures_open(U_ICUDATA_CURR
, loc
, &ec2
);
527 rb
= ures_getByKey(rb
, CURRENCIES
, rb
, &ec2
);
529 // Fetch resource with multi-level resource inheritance fallback
530 rb
= ures_getByKeyWithFallback(rb
, buf
, rb
, &ec2
);
532 s
= ures_getStringByIndex(rb
, choice
, len
, &ec2
);
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
)) {
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
549 *isChoiceFormat
= FALSE
;
550 if (U_SUCCESS(ec2
)) {
553 while (i
< *len
&& s
[i
] == CHOICE_FORMAT_MARK
&& i
< 2) {
556 *isChoiceFormat
= (i
== 1);
557 if (i
!= 0) ++s
; // Skip over first mark
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
;
567 U_CAPI
const UChar
* U_EXPORT2
568 ucurr_getPluralName(const UChar
* currency
,
570 UBool
* isChoiceFormat
,
571 const char* pluralCount
,
572 int32_t* len
, // fillin
574 // Look up the Currencies resource for the given locale. The
575 // Currencies locale data looks like this:
577 //| CurrencyPlurals {
580 //| other{"US dollars"}
585 if (U_FAILURE(*ec
)) {
589 // Use a separate UErrorCode here that does not propagate out of
591 UErrorCode ec2
= U_ZERO_ERROR
;
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
;
600 char buf
[ISO_COUNTRY_CODE_LENGTH
+1];
601 myUCharsToChars(buf
, currency
);
603 const UChar
* s
= NULL
;
605 UResourceBundle
* rb
= ures_open(U_ICUDATA_CURR
, loc
, &ec2
);
607 rb
= ures_getByKey(rb
, CURRENCYPLURALS
, rb
, &ec2
);
609 // Fetch resource with multi-level resource inheritance fallback
610 rb
= ures_getByKeyWithFallback(rb
, buf
, rb
, &ec2
);
612 s
= ures_getStringByKeyWithFallback(rb
, pluralCount
, len
, &ec2
);
613 if (U_FAILURE(ec2
)) {
614 // fall back to "other"
616 s
= ures_getStringByKeyWithFallback(rb
, "other", len
, &ec2
);
617 if (U_FAILURE(ec2
)) {
619 // fall back to long name in Currencies
620 return ucurr_getName(currency
, locale
, UCURR_LONG_NAME
,
621 isChoiceFormat
, len
, ec
);
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
)) {
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
;
644 //========================================================================
645 // Following are structure and function for parsing currency names
647 #define NEED_TO_BE_DELETED 0x1
649 // TODO: a better way to define this?
650 #define MAX_CURRENCY_NAME_LEN 100
653 const char* IsoCode
; // key
654 UChar
* currencyName
; // value
655 int32_t currencyNameLen
; // value length
656 int32_t flag
; // flags
657 } CurrencyNameStruct
;
661 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
665 #define MAX(a,b) (((a)<(b)) ? (b) : (a))
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
;
674 i
< MIN(currName_1
->currencyNameLen
, currName_2
->currencyNameLen
);
676 if (currName_1
->currencyName
[i
] < currName_2
->currencyName
[i
]) {
679 if (currName_1
->currencyName
[i
] > currName_2
->currencyName
[i
]) {
683 if (currName_1
->currencyNameLen
< currName_2
->currencyNameLen
) {
685 } else if (currName_1
->currencyNameLen
> currName_2
->currencyNameLen
) {
692 // Give a locale, return the maximum number of currency names associated with
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".
701 getCurrencyNameCount(const char* loc
, int32_t* total_currency_name_count
, int32_t* total_currency_symbol_count
) {
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
);
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
);
717 s
= ures_getStringByIndex(names
, UCURR_SYMBOL_NAME
, &len
, &ec2
);
718 UBool isChoice
= FALSE
;
719 if (len
> 0 && s
[0] == CHOICE_FORMAT_MARK
) {
722 if (len
> 0 && s
[0] != CHOICE_FORMAT_MARK
) {
727 ChoiceFormat
fmt(s
, ec2
);
729 fmt
.getFormats(fmt_count
);
730 *total_currency_symbol_count
+= fmt_count
;
732 ++(*total_currency_symbol_count
); // currency symbol
735 ++(*total_currency_symbol_count
); // iso code
736 ++(*total_currency_name_count
); // long name
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
);
753 if (!fallback(locale
)) {
759 // TODO: locale dependent
761 toUpperCase(const UChar
* source
, int32_t len
) {
763 UErrorCode ec
= U_ZERO_ERROR
;
764 int32_t destLen
= u_strToUpper(dest
, 0, source
, len
, NULL
, &ec
);
767 dest
= (UChar
*)uprv_malloc(sizeof(UChar
) * MAX(destLen
, len
));
768 u_strToUpper(dest
, destLen
, source
, len
, NULL
, &ec
);
770 uprv_memcpy(dest
, source
, sizeof(UChar
) * len
);
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.
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
,
790 // Look up the Currencies resource for the given locale.
791 UErrorCode ec2
= U_ZERO_ERROR
;
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
;
799 // Get maximum currency name count first.
800 getCurrencyNameCount(loc
, total_currency_name_count
, total_currency_symbol_count
);
802 *currencyNames
= (CurrencyNameStruct
*)uprv_malloc
803 (sizeof(CurrencyNameStruct
) * (*total_currency_name_count
));
804 *currencySymbols
= (CurrencyNameStruct
*)uprv_malloc
805 (sizeof(CurrencyNameStruct
) * (*total_currency_symbol_count
));
807 const UChar
* s
= NULL
; // currency name
808 char* iso
= NULL
; // currency ISO code
810 *total_currency_name_count
= 0;
811 *total_currency_symbol_count
= 0;
813 UErrorCode ec3
= U_ZERO_ERROR
;
814 UErrorCode ec4
= U_ZERO_ERROR
;
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
) {
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
);
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
);
834 if (uhash_get(currencyIsoCodes
, iso
) != NULL
) {
838 uhash_put(currencyIsoCodes
, iso
, iso
, &ec3
);
841 UBool isChoice
= FALSE
;
842 if (len
> 0 && s
[0] == CHOICE_FORMAT_MARK
) {
845 if (len
> 0 && s
[0] != CHOICE_FORMAT_MARK
) {
850 ChoiceFormat
fmt(s
, ec2
);
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
;
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
;
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
;
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;
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
);
902 if (uhash_get(currencyPluralIsoCodes
, iso
) != NULL
) {
906 uhash_put(currencyPluralIsoCodes
, iso
, iso
, &ec4
);
909 int32_t num
= ures_getSize(names
);
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
;
927 if (!fallback(loc
)) {
932 uhash_close(currencyIsoCodes
);
933 uhash_close(currencyPluralIsoCodes
);
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
);
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
]);
951 printf("len: %d\n", (*currencyNames
)[index
].currencyNameLen
);
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
]);
962 printf("len: %d\n", (*currencySymbols
)[index
].currencyNameLen
);
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.
974 binarySearch(const CurrencyNameStruct
* currencyNames
,
975 int32_t indexInCurrencyNames
,
977 int32_t* begin
, int32_t* end
) {
979 printf("key = %x\n", key
);
981 int32_t first
= *begin
;
983 while (first
<= last
) {
984 int32_t mid
= (first
+ last
) / 2; // compute mid point.
985 if (indexInCurrencyNames
>= currencyNames
[mid
].currencyNameLen
) {
988 if (key
> currencyNames
[mid
].currencyName
[indexInCurrencyNames
]) {
991 else if (key
< currencyNames
[mid
].currencyName
[indexInCurrencyNames
]) {
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.
1002 printf("mid = %d\n", mid
);
1005 int32_t M
= (L
+ R
) / 2;
1007 printf("L = %d, R = %d, M = %d\n", L
, R
, M
);
1009 if (indexInCurrencyNames
>= currencyNames
[M
].currencyNameLen
) {
1012 if (currencyNames
[M
].currencyName
[indexInCurrencyNames
] < key
) {
1016 U_ASSERT(currencyNames
[M
].currencyName
[indexInCurrencyNames
] == key
);
1027 printf("begin = %d\n", *begin
);
1028 U_ASSERT(currencyNames
[*begin
].currencyName
[indexInCurrencyNames
] == key
);
1031 // Now for the second search, finding the least R such that
1032 // key < CurrencyNameStruct[R].
1036 int32_t M
= (L
+ R
) / 2;
1038 printf("L = %d, R = %d, M = %d\n", L
, R
, M
);
1040 if (currencyNames
[M
].currencyNameLen
< indexInCurrencyNames
) {
1043 if (currencyNames
[M
].currencyName
[indexInCurrencyNames
] > key
) {
1047 U_ASSERT(currencyNames
[M
].currencyName
[indexInCurrencyNames
] == key
);
1056 if (currencyNames
[R
].currencyName
[indexInCurrencyNames
] > key
) {
1062 printf("end = %d\n", *end
);
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.
1069 return -1; // find range, but no exact match.
1075 return -1; // failed to find range.
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.
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
;
1099 printf("maxMatchIndex = %d, maxMatchLen = %d\n",
1100 *maxMatchIndex
, *maxMatchLen
);
1106 #define LINEAR_SEARCH_THRESHOLD 10
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.
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;
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
,
1144 &binarySearchBegin
, &binarySearchEnd
);
1145 if (binarySearchBegin
== -1) { // did not find the range
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
;
1154 if (binarySearchEnd
- binarySearchBegin
< LINEAR_SEARCH_THRESHOLD
) {
1155 // linear search if within threshold.
1156 linearSearch(currencyNames
, binarySearchBegin
, binarySearchEnd
,
1158 maxMatchLen
, maxMatchIndex
);
1165 //========================= currency name cache =====================
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
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.
1180 } CurrencyNameCacheEntry
;
1183 #define CURRENCY_NAME_CACHE_NUM 10
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;
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
);
1199 uprv_free(currencyNames
);
1204 deleteCacheEntry(CurrencyNameCacheEntry
* entry
) {
1205 deleteCurrencyNames(entry
->currencyNames
, entry
->totalCurrencyNameCount
);
1206 deleteCurrencyNames(entry
->currencySymbols
, entry
->totalCurrencySymbolCount
);
1212 static UBool U_CALLCONV
1213 currency_cache_cleanup(void) {
1214 for (int32_t i
= 0; i
< CURRENCY_NAME_CACHE_NUM
; ++i
) {
1216 deleteCacheEntry(currCache
[i
]);
1225 uprv_parseCurrency(const char* locale
,
1226 const U_NAMESPACE_QUALIFIER UnicodeString
& text
,
1227 U_NAMESPACE_QUALIFIER ParsePosition
& pos
,
1234 if (U_FAILURE(ec
)) {
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
;
1245 // in order to handle racing correctly,
1246 // not putting 'search' in a separate function and using UMTX.
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) {
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
);
1265 collectCurrencyNames(locale
, ¤cyNames
, &total_currency_name_count
, ¤cySymbols
, &total_currency_symbol_count
, ec
);
1266 if (U_FAILURE(ec
)) {
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) {
1280 // insert new entry to
1281 // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
1282 // and remove the existing entry
1283 // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
1285 cacheEntry
= currCache
[currentCacheEntryIndex
];
1287 --(cacheEntry
->refCount
);
1288 // delete if the ref count is zero
1289 if (cacheEntry
->refCount
== 0) {
1290 deleteCacheEntry(cacheEntry
);
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
);
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
);
1317 int32_t start
= pos
.getIndex();
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
);
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
);
1333 printf("search in names, max = %d, matchIndex = %d\n", max
, matchIndex
);
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
,
1342 &maxInSymbol
, &matchIndexInSymbol
);
1346 printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol
, matchIndexInSymbol
);
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
);
1357 // decrease reference count
1359 --(cacheEntry
->refCount
);
1360 if (cacheEntry
->refCount
== 0) { // remove
1361 deleteCacheEntry(cacheEntry
);
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.
1374 * This is used for backward compatibility with old currency logic in
1375 * DecimalFormat and DecimalFormatSymbols.
1378 uprv_getStaticCurrencyName(const UChar
* iso
, const char* loc
,
1379 U_NAMESPACE_QUALIFIER UnicodeString
& result
, UErrorCode
& ec
)
1383 UBool isChoiceFormat
;
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.
1391 if (isChoiceFormat
) {
1392 ChoiceFormat
f(currname
, ec
);
1393 if (U_SUCCESS(ec
)) {
1394 f
.format(2.0, result
);
1404 U_CAPI
int32_t U_EXPORT2
1405 ucurr_getDefaultFractionDigits(const UChar
* currency
, UErrorCode
* ec
) {
1406 return (_findMetaData(currency
, *ec
))[0];
1409 U_CAPI
double U_EXPORT2
1410 ucurr_getRoundingIncrement(const UChar
* currency
, UErrorCode
* ec
) {
1411 const int32_t *data
= _findMetaData(currency
, *ec
);
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
;
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.
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]];
1434 typedef struct UCurrencyContext
{
1435 uint32_t currType
; /* UCurrCurrencyType */
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
1443 ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
1445 static const struct CurrencyList
{
1446 const char *currency
;
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.
1747 #define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
1748 ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
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
;
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
)) {
1765 static const char* U_CALLCONV
1766 ucurr_nextCurrencyList(UEnumeration
*enumerator
,
1767 int32_t* resultLength
,
1768 UErrorCode
* /*pErrorCode*/)
1770 UCurrencyContext
*myContext
= (UCurrencyContext
*)(enumerator
->context
);
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
))
1778 *resultLength
= 3; /* Currency codes are only 3 chars long */
1780 return currItem
->currency
;
1783 /* We enumerated too far. */
1790 static void U_CALLCONV
1791 ucurr_resetCurrencyList(UEnumeration
*enumerator
, UErrorCode
* /*pErrorCode*/) {
1792 ((UCurrencyContext
*)(enumerator
->context
))->listIdx
= 0;
1795 static void U_CALLCONV
1796 ucurr_closeCurrencyList(UEnumeration
*enumerator
) {
1797 uprv_free(enumerator
->context
);
1798 uprv_free(enumerator
);
1801 static const UEnumeration gEnumCurrencyList
= {
1804 ucurr_closeCurrencyList
,
1805 ucurr_countCurrencyList
,
1807 ucurr_nextCurrencyList
,
1808 ucurr_resetCurrencyList
1812 U_CAPI UEnumeration
* U_EXPORT2
1813 ucurr_openISOCurrencies(uint32_t currType
, UErrorCode
*pErrorCode
) {
1814 UEnumeration
*myEnum
= NULL
;
1815 UCurrencyContext
*myContext
;
1817 myEnum
= (UEnumeration
*)uprv_malloc(sizeof(UEnumeration
));
1818 if (myEnum
== NULL
) {
1819 *pErrorCode
= U_MEMORY_ALLOCATION_ERROR
;
1822 uprv_memcpy(myEnum
, &gEnumCurrencyList
, sizeof(UEnumeration
));
1823 myContext
= (UCurrencyContext
*)uprv_malloc(sizeof(UCurrencyContext
));
1824 if (myContext
== NULL
) {
1825 *pErrorCode
= U_MEMORY_ALLOCATION_ERROR
;
1829 myContext
->currType
= currType
;
1830 myContext
->listIdx
= 0;
1831 myEnum
->context
= myContext
;
1835 U_CAPI
int32_t U_EXPORT2
1836 ucurr_countCurrencies(const char* locale
,
1840 int32_t currCount
= 0;
1843 if (ec
!= NULL
&& U_SUCCESS(*ec
))
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
);
1857 // Remove variants, which is only needed for registration.
1858 char *idDelim
= strchr(id
, VAR_DELIM
);
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
);
1868 // Using the id derived from the local, get the currency data
1869 UResourceBundle
*countryArray
= ures_getByKey(rb
, id
, cm
, &localStatus
);
1871 // process each currency to see which one is valid for the given date
1872 if (U_SUCCESS(localStatus
))
1874 for (int32_t i
=0; i
<ures_getSize(countryArray
); i
++)
1876 // get the currency resource
1877 UResourceBundle
*currencyRes
= ures_getByIndex(countryArray
, i
, NULL
, &localStatus
);
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
);
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
;
1888 if (ures_getSize(currencyRes
)> 2)
1890 int32_t toLength
= 0;
1891 UResourceBundle
*toRes
= ures_getByKey(currencyRes
, "to", NULL
, &localStatus
);
1892 const int32_t *toArray
= ures_getIntVector(toRes
, &toLength
, &localStatus
);
1894 currDate64
= (int64_t)toArray
[0] << 32;
1895 currDate64
|= ((int64_t)toArray
[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
1896 UDate toDate
= (UDate
)currDate64
;
1898 if ((fromDate
<= date
) && (date
< toDate
))
1907 if (fromDate
<= date
)
1913 // close open resources
1914 ures_close(currencyRes
);
1915 ures_close(fromRes
);
1918 } // end if (U_SUCCESS(localStatus))
1920 ures_close(countryArray
);
1923 if (*ec
== U_ZERO_ERROR
|| localStatus
!= U_ZERO_ERROR
)
1925 // There is nothing to fallback to.
1926 // Report the failure/warning if possible.
1938 // If we got here, either error code is invalid or
1939 // some argument passed is no good.
1943 U_CAPI
int32_t U_EXPORT2
1944 ucurr_forLocaleAndDate(const char* locale
,
1948 int32_t buffCapacity
,
1952 int32_t currIndex
= 0;
1953 const UChar
* s
= NULL
;
1955 if (ec
!= NULL
&& U_SUCCESS(*ec
))
1957 // check the arguments passed
1958 if ((buff
&& buffCapacity
) || !buffCapacity
)
1961 UErrorCode localStatus
= U_ZERO_ERROR
;
1962 char id
[ULOC_FULLNAME_CAPACITY
];
1963 resLen
= uloc_getKeywordValue(locale
, "currency", id
, ULOC_FULLNAME_CAPACITY
, &localStatus
);
1965 // get country or country_variant in `id'
1966 /*uint32_t variantType =*/ idForLocale(locale
, id
, sizeof(id
), ec
);
1972 // Remove variants, which is only needed for registration.
1973 char *idDelim
= strchr(id
, VAR_DELIM
);
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
);
1983 // Using the id derived from the local, get the currency data
1984 UResourceBundle
*countryArray
= ures_getByKey(rb
, id
, cm
, &localStatus
);
1986 // process each currency to see which one is valid for the given date
1987 bool matchFound
= false;
1988 if (U_SUCCESS(localStatus
))
1990 if ((index
<= 0) || (index
> ures_getSize(countryArray
)))
1992 // requested index is out of bounds
1993 ures_close(countryArray
);
1997 for (int32_t i
=0; i
<ures_getSize(countryArray
); i
++)
1999 // get the currency resource
2000 UResourceBundle
*currencyRes
= ures_getByIndex(countryArray
, i
, NULL
, &localStatus
);
2001 s
= ures_getStringByKey(currencyRes
, "id", &resLen
, &localStatus
);
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
);
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
;
2012 if (ures_getSize(currencyRes
)> 2)
2014 int32_t toLength
= 0;
2015 UResourceBundle
*toRes
= ures_getByKey(currencyRes
, "to", NULL
, &localStatus
);
2016 const int32_t *toArray
= ures_getIntVector(toRes
, &toLength
, &localStatus
);
2018 currDate64
= (int64_t)toArray
[0] << 32;
2019 currDate64
|= ((int64_t)toArray
[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2020 UDate toDate
= (UDate
)currDate64
;
2022 if ((fromDate
<= date
) && (date
< toDate
))
2025 if (currIndex
== index
)
2035 if (fromDate
<= date
)
2038 if (currIndex
== index
)
2045 // close open resources
2046 ures_close(currencyRes
);
2047 ures_close(fromRes
);
2049 // check for loop exit
2058 ures_close(countryArray
);
2061 if (*ec
== U_ZERO_ERROR
|| localStatus
!= U_ZERO_ERROR
)
2063 // There is nothing to fallback to.
2064 // Report the failure/warning if possible.
2071 if((buffCapacity
> resLen
) && matchFound
)
2073 // write out the currency value
2082 // return null terminated currency string
2083 return u_terminateUChars(buff
, buffCapacity
, resLen
, ec
);
2087 // illegal argument encountered
2088 *ec
= U_ILLEGAL_ARGUMENT_ERROR
;
2093 // If we got here, either error code is invalid or
2094 // some argument passed is no good.
2098 static const UEnumeration defaultKeywordValues
= {
2101 ulist_close_keyword_values_iterator
,
2102 ulist_count_keyword_values
,
2104 ulist_next_keyword_value
,
2105 ulist_reset_keyword_values_iterator
2108 U_CAPI UEnumeration
*U_EXPORT2
ucurr_getKeywordValuesForLocale(const char *key
, const char *locale
, UBool commonlyUsed
, UErrorCode
* status
) {
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
);
2118 prefRegionLength
= uloc_getCountry(loc
, prefRegion
, sizeof(prefRegion
), status
);
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
) {
2127 *status
= U_MEMORY_ALLOCATION_ERROR
;
2131 ulist_deleteList(values
);
2132 ulist_deleteList(otherValues
);
2135 memcpy(en
, &defaultKeywordValues
, sizeof(UEnumeration
));
2136 en
->context
= values
;
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(®bndl
);
2143 ures_initStackObject(&curbndl
);
2144 ures_initStackObject(&to
);
2146 while (U_SUCCESS(*status
) && ures_hasNext(bundle
)) {
2147 ures_getNextResource(bundle
, &bundlekey
, status
);
2148 if (U_FAILURE(*status
)) {
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
2159 ures_getByKey(bundle
, region
, ®bndl
, status
);
2160 if (U_FAILURE(*status
)) {
2163 while (U_SUCCESS(*status
) && ures_hasNext(®bndl
)) {
2164 ures_getNextResource(®bndl
, &curbndl
, status
);
2165 if (ures_getType(&curbndl
) != URES_TABLE
) {
2166 // Currently, an empty ARRAY is mixed in.
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
;
2176 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
2177 ures_getUTF8StringByKey(&curbndl
, "id", curID
, &curIDLength
, TRUE
, status
);
2178 /* optimize - use the utf-8 string */
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
;
2186 u_UCharsToChars(defString
, curID
, curIDLength
+1);
2192 if (U_FAILURE(*status
)) {
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
;
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
);
2214 if (U_SUCCESS(*status
)) {
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.
2220 en
= ucurr_getKeywordValuesForLocale(key
, "und", TRUE
, status
);
2223 // Consolidate the list
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
)) {
2238 ulist_resetList((UList
*)(en
->context
));
2240 ulist_deleteList(values
);
2246 ures_close(&curbndl
);
2247 ures_close(®bndl
);
2248 ures_close(&bundlekey
);
2251 ulist_deleteList(otherValues
);
2256 #endif /* #if !UCONFIG_NO_FORMATTING */