blob: 3506fa51ea48e92de74e850ce151cecbf35b84e7 [file] [log] [blame]
/*
**********************************************************************
* Copyright (c) 2002-2008, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/ucurr.h"
#include "unicode/locid.h"
#include "unicode/ures.h"
#include "unicode/ustring.h"
#include "unicode/choicfmt.h"
#include "unicode/parsepos.h"
#include "ustr_imp.h"
#include "cmemory.h"
#include "cstring.h"
#include "uassert.h"
#include "umutex.h"
#include "ucln_in.h"
#include "uenumimp.h"
#include "uresimp.h"
//------------------------------------------------------------
// Constants
// Default currency meta data of last resort. We try to use the
// defaults encoded in the meta data resource bundle. If there is a
// configuration/build error and these are not available, we use these
// hard-coded defaults (which should be identical).
static const int32_t LAST_RESORT_DATA[] = { 2, 0 };
// POW10[i] = 10^i, i=0..MAX_POW10
static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
1000000, 10000000, 100000000, 1000000000 };
static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1;
#define ISO_COUNTRY_CODE_LENGTH 3
//------------------------------------------------------------
// Resource tags
//
static const char CURRENCY_DATA[] = "supplementalData";
// Tag for meta-data, in root.
static const char CURRENCY_META[] = "CurrencyMeta";
// Tag for map from countries to currencies, in root.
static const char CURRENCY_MAP[] = "CurrencyMap";
// Tag for default meta-data, in CURRENCY_META
static const char DEFAULT_META[] = "DEFAULT";
// Variant for legacy pre-euro mapping in CurrencyMap
static const char VAR_PRE_EURO[] = "PREEURO";
// Variant for legacy euro mapping in CurrencyMap
static const char VAR_EURO[] = "EURO";
// Variant delimiter
static const char VAR_DELIM = '_';
static const char VAR_DELIM_STR[] = "_";
// Variant for legacy euro mapping in CurrencyMap
//static const char VAR_DELIM_EURO[] = "_EURO";
#define VARIANT_IS_EMPTY 0
#define VARIANT_IS_EURO 0x1
#define VARIANT_IS_PREEURO 0x2
// Tag for localized display names (symbols) of currencies
static const char CURRENCIES[] = "Currencies";
// Marker character indicating that a display name is a ChoiceFormat
// pattern. Strings that start with one mark are ChoiceFormat
// patterns. Strings that start with 2 marks are static strings, and
// the first mark is deleted.
static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign
static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
//------------------------------------------------------------
// Code
/**
* Unfortunately, we have to convert the UChar* currency code to char*
* to use it as a resource key.
*/
static inline char*
myUCharsToChars(char* resultOfLen4, const UChar* currency) {
u_UCharsToChars(currency, resultOfLen4, ISO_COUNTRY_CODE_LENGTH);
resultOfLen4[ISO_COUNTRY_CODE_LENGTH] = 0;
return resultOfLen4;
}
/**
* Internal function to look up currency data. Result is an array of
* two integers. The first is the fraction digits. The second is the
* rounding increment, or 0 if none. The rounding increment is in
* units of 10^(-fraction_digits).
*/
static const int32_t*
_findMetaData(const UChar* currency, UErrorCode& ec) {
if (currency == 0 || *currency == 0) {
if (U_SUCCESS(ec)) {
ec = U_ILLEGAL_ARGUMENT_ERROR;
}
return LAST_RESORT_DATA;
}
// Get CurrencyMeta resource out of root locale file. [This may
// move out of the root locale file later; if it does, update this
// code.]
UResourceBundle* currencyData = ures_openDirect(NULL, CURRENCY_DATA, &ec);
UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec);
if (U_FAILURE(ec)) {
ures_close(currencyMeta);
// Config/build error; return hard-coded defaults
return LAST_RESORT_DATA;
}
// Look up our currency, or if that's not available, then DEFAULT
char buf[ISO_COUNTRY_CODE_LENGTH+1];
UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure
UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2);
if (U_FAILURE(ec2)) {
ures_close(rb);
rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec);
if (U_FAILURE(ec)) {
ures_close(currencyMeta);
ures_close(rb);
// Config/build error; return hard-coded defaults
return LAST_RESORT_DATA;
}
}
int32_t len;
const int32_t *data = ures_getIntVector(rb, &len, &ec);
if (U_FAILURE(ec) || len != 2) {
// Config/build error; return hard-coded defaults
if (U_SUCCESS(ec)) {
ec = U_INVALID_FORMAT_ERROR;
}
ures_close(currencyMeta);
ures_close(rb);
return LAST_RESORT_DATA;
}
ures_close(currencyMeta);
ures_close(rb);
return data;
}
// -------------------------------------
/**
* @see VARIANT_IS_EURO
* @see VARIANT_IS_PREEURO
*/
static uint32_t
idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec)
{
uint32_t variantType = 0;
// !!! this is internal only, assumes buffer is not null and capacity is sufficient
// Extract the country name and variant name. We only
// recognize two variant names, EURO and PREEURO.
char variant[ULOC_FULLNAME_CAPACITY];
uloc_getCountry(locale, countryAndVariant, capacity, ec);
uloc_getVariant(locale, variant, sizeof(variant), ec);
if (variant[0] != 0) {
variantType = (0 == uprv_strcmp(variant, VAR_EURO))
| ((0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1);
if (variantType)
{
uprv_strcat(countryAndVariant, VAR_DELIM_STR);
uprv_strcat(countryAndVariant, variant);
}
}
return variantType;
}
// ------------------------------------------
//
// Registration
//
//-------------------------------------------
// don't use ICUService since we don't need fallback
#if !UCONFIG_NO_SERVICE
U_CDECL_BEGIN
static UBool U_CALLCONV currency_cleanup(void);
U_CDECL_END
struct CReg;
/* Remember to call umtx_init(&gCRegLock) before using it! */
static UMTX gCRegLock = 0;
static CReg* gCRegHead = 0;
struct CReg : public U_NAMESPACE_QUALIFIER UMemory {
CReg *next;
UChar iso[ISO_COUNTRY_CODE_LENGTH+1];
char id[ULOC_FULLNAME_CAPACITY];
CReg(const UChar* _iso, const char* _id)
: next(0)
{
int32_t len = (int32_t)uprv_strlen(_id);
if (len > (int32_t)(sizeof(id)-1)) {
len = (sizeof(id)-1);
}
uprv_strncpy(id, _id, len);
id[len] = 0;
uprv_memcpy(iso, _iso, ISO_COUNTRY_CODE_LENGTH * sizeof(const UChar));
iso[ISO_COUNTRY_CODE_LENGTH] = 0;
}
static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status)
{
if (status && U_SUCCESS(*status) && _iso && _id) {
CReg* n = new CReg(_iso, _id);
if (n) {
umtx_init(&gCRegLock);
umtx_lock(&gCRegLock);
if (!gCRegHead) {
/* register for the first time */
ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
}
n->next = gCRegHead;
gCRegHead = n;
umtx_unlock(&gCRegLock);
return n;
}
*status = U_MEMORY_ALLOCATION_ERROR;
}
return 0;
}
static UBool unreg(UCurrRegistryKey key) {
UBool found = FALSE;
umtx_init(&gCRegLock);
umtx_lock(&gCRegLock);
CReg** p = &gCRegHead;
while (*p) {
if (*p == key) {
*p = ((CReg*)key)->next;
delete (CReg*)key;
found = TRUE;
break;
}
p = &((*p)->next);
}
umtx_unlock(&gCRegLock);
return found;
}
static const UChar* get(const char* id) {
const UChar* result = NULL;
umtx_init(&gCRegLock);
umtx_lock(&gCRegLock);
CReg* p = gCRegHead;
/* register cleanup of the mutex */
ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
while (p) {
if (uprv_strcmp(id, p->id) == 0) {
result = p->iso;
break;
}
p = p->next;
}
umtx_unlock(&gCRegLock);
return result;
}
/* This doesn't need to be thread safe. It's for u_cleanup only. */
static void cleanup(void) {
while (gCRegHead) {
CReg* n = gCRegHead;
gCRegHead = gCRegHead->next;
delete n;
}
umtx_destroy(&gCRegLock);
}
};
/**
* Release all static memory held by currency.
*/
U_CDECL_BEGIN
static UBool U_CALLCONV currency_cleanup(void) {
#if !UCONFIG_NO_SERVICE
CReg::cleanup();
#endif
return TRUE;
}
U_CDECL_END
// -------------------------------------
U_CAPI UCurrRegistryKey U_EXPORT2
ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
{
if (status && U_SUCCESS(*status)) {
char id[ULOC_FULLNAME_CAPACITY];
idForLocale(locale, id, sizeof(id), status);
return CReg::reg(isoCode, id, status);
}
return NULL;
}
// -------------------------------------
U_CAPI UBool U_EXPORT2
ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
{
if (status && U_SUCCESS(*status)) {
return CReg::unreg(key);
}
return FALSE;
}
#endif /* UCONFIG_NO_SERVICE */
// -------------------------------------
U_CAPI int32_t U_EXPORT2
ucurr_forLocale(const char* locale,
UChar* buff,
int32_t buffCapacity,
UErrorCode* ec)
{
int32_t resLen = 0;
const UChar* s = NULL;
if (ec != NULL && U_SUCCESS(*ec)) {
if ((buff && buffCapacity) || !buffCapacity) {
UErrorCode localStatus = U_ZERO_ERROR;
char id[ULOC_FULLNAME_CAPACITY];
if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) {
// there is a currency keyword. Try to see if it's valid
if(buffCapacity > resLen) {
u_charsToUChars(id, buff, resLen);
}
} else {
// get country or country_variant in `id'
uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
if (U_FAILURE(*ec)) {
return 0;
}
#if !UCONFIG_NO_SERVICE
const UChar* result = CReg::get(id);
if (result) {
if(buffCapacity > u_strlen(result)) {
u_strcpy(buff, result);
}
return u_strlen(result);
}
#endif
// Remove variants, which is only needed for registration.
char *idDelim = strchr(id, VAR_DELIM);
if (idDelim) {
idDelim[0] = 0;
}
// Look up the CurrencyMap element in the root bundle.
UResourceBundle *rb = ures_openDirect(NULL, CURRENCY_DATA, &localStatus);
UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus);
s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
/*
Get the second item when PREEURO is requested, and this is a known Euro country.
If the requested variant is PREEURO, and this isn't a Euro country, assume
that the country changed over to the Euro in the future. This is probably
an old version of ICU that hasn't been updated yet. The latest currency is
probably correct.
*/
if (U_SUCCESS(localStatus)) {
if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) {
currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus);
s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
}
else if ((variantType & VARIANT_IS_EURO)) {
s = EUR_STR;
}
}
ures_close(countryArray);
ures_close(currencyReq);
if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0)
{
// We don't know about it. Check to see if we support the variant.
uloc_getParent(locale, id, sizeof(id), ec);
*ec = U_USING_FALLBACK_WARNING;
return ucurr_forLocale(id, buff, buffCapacity, ec);
}
else if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) {
// There is nothing to fallback to. Report the failure/warning if possible.
*ec = localStatus;
}
if (U_SUCCESS(*ec)) {
if(buffCapacity > resLen) {
u_strcpy(buff, s);
}
}
}
return u_terminateUChars(buff, buffCapacity, resLen, ec);
} else {
*ec = U_ILLEGAL_ARGUMENT_ERROR;
}
}
return resLen;
}
// end registration
/**
* Modify the given locale name by removing the rightmost _-delimited
* element. If there is none, empty the string ("" == root).
* NOTE: The string "root" is not recognized; do not use it.
* @return TRUE if the fallback happened; FALSE if locale is already
* root ("").
*/
static UBool fallback(char *loc) {
if (!*loc) {
return FALSE;
}
UErrorCode status = U_ZERO_ERROR;
uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status);
/*
char *i = uprv_strrchr(loc, '_');
if (i == NULL) {
i = loc;
}
*i = 0;
*/
return TRUE;
}
U_CAPI const UChar* U_EXPORT2
ucurr_getName(const UChar* currency,
const char* locale,
UCurrNameStyle nameStyle,
UBool* isChoiceFormat, // fillin
int32_t* len, // fillin
UErrorCode* ec) {
// Look up the Currencies resource for the given locale. The
// Currencies locale data looks like this:
//|en {
//| Currencies {
//| USD { "US$", "US Dollar" }
//| CHF { "Sw F", "Swiss Franc" }
//| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
//| //...
//| }
//|}
if (U_FAILURE(*ec)) {
return 0;
}
int32_t choice = (int32_t) nameStyle;
if (choice < 0 || choice > 1) {
*ec = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
// In the future, resource bundles may implement multi-level
// fallback. That is, if a currency is not found in the en_US
// Currencies data, then the en Currencies data will be searched.
// Currently, if a Currencies datum exists in en_US and en, the
// en_US entry hides that in en.
// We want multi-level fallback for this resource, so we implement
// it manually.
// Use a separate UErrorCode here that does not propagate out of
// this function.
UErrorCode ec2 = U_ZERO_ERROR;
char loc[ULOC_FULLNAME_CAPACITY];
uloc_getName(locale, loc, sizeof(loc), &ec2);
if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
*ec = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
char buf[ISO_COUNTRY_CODE_LENGTH+1];
myUCharsToChars(buf, currency);
const UChar* s = NULL;
ec2 = U_ZERO_ERROR;
UResourceBundle* rb = ures_open(NULL, loc, &ec2);
rb = ures_getByKey(rb, CURRENCIES, rb, &ec2);
// Fetch resource with multi-level resource inheritance fallback
rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
s = ures_getStringByIndex(rb, choice, len, &ec2);
ures_close(rb);
// If we've succeeded we're done. Otherwise, try to fallback.
// If that fails (because we are already at root) then exit.
if (U_SUCCESS(ec2)) {
if (ec2 == U_USING_DEFAULT_WARNING
|| (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
*ec = ec2;
}
}
// Determine if this is a ChoiceFormat pattern. One leading mark
// indicates a ChoiceFormat. Two indicates a static string that
// starts with a mark. In either case, the first mark is ignored,
// if present. Marks in the rest of the string have no special
// meaning.
*isChoiceFormat = FALSE;
if (U_SUCCESS(ec2)) {
U_ASSERT(s != NULL);
int32_t i=0;
while (i < *len && s[i] == CHOICE_FORMAT_MARK && i < 2) {
++i;
}
*isChoiceFormat = (i == 1);
if (i != 0) ++s; // Skip over first mark
return s;
}
// If we fail to find a match, use the ISO 4217 code
*len = u_strlen(currency); // Should == ISO_COUNTRY_CODE_LENGTH, but maybe not...?
*ec = U_USING_DEFAULT_WARNING;
return currency;
}
U_CFUNC void
uprv_parseCurrency(const char* locale,
const U_NAMESPACE_QUALIFIER UnicodeString& text,
U_NAMESPACE_QUALIFIER ParsePosition& pos,
UChar* result,
UErrorCode& ec)
{
U_NAMESPACE_USE
// TODO: There is a slight problem with the pseudo-multi-level
// fallback implemented here. More-specific locales don't
// properly shield duplicate entries in less-specific locales.
// This problem will go away when real multi-level fallback is
// implemented. We could also fix this by recording (in a
// hash) which codes are used at each level of fallback, but
// this doesn't seem warranted.
if (U_FAILURE(ec)) {
return;
}
// Look up the Currencies resource for the given locale. The
// Currencies locale data looks like this:
//|en {
//| Currencies {
//| USD { "US$", "US Dollar" }
//| CHF { "Sw F", "Swiss Franc" }
//| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
//| //...
//| }
//|}
// In the future, resource bundles may implement multi-level
// fallback. That is, if a currency is not found in the en_US
// Currencies data, then the en Currencies data will be searched.
// Currently, if a Currencies datum exists in en_US and en, the
// en_US entry hides that in en.
// We want multi-level fallback for this resource, so we implement
// it manually.
// Use a separate UErrorCode here that does not propagate out of
// this function.
UErrorCode ec2 = U_ZERO_ERROR;
char loc[ULOC_FULLNAME_CAPACITY];
uloc_getName(locale, loc, sizeof(loc), &ec2);
if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
ec = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
int32_t start = pos.getIndex();
const UChar* s = NULL;
const char* iso = NULL;
int32_t max = 0;
// Multi-level resource inheritance fallback loop
for (;;) {
ec2 = U_ZERO_ERROR;
UResourceBundle* rb = ures_open(NULL, loc, &ec2);
UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
int32_t n = ures_getSize(curr);
for (int32_t i=0; i<n; ++i) {
UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
int32_t len;
s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
UBool isChoice = FALSE;
if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
++s;
--len;
if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
isChoice = TRUE;
}
}
if (isChoice) {
Formattable temp;
ChoiceFormat fmt(s, ec2);
fmt.parse(text, temp, pos);
len = pos.getIndex() - start;
pos.setIndex(start);
} else if (len > max &&
text.compare(pos.getIndex(), len, s) != 0) {
len = 0;
}
if (len > max) {
iso = ures_getKey(names);
max = len;
}
ures_close(names);
}
ures_close(curr);
ures_close(rb);
// Try to fallback. If that fails (because we are already at
// root) then exit.
if (!fallback(loc)) {
break;
}
}
if (iso != NULL) {
u_charsToUChars(iso, result, 4);
}
// If display name parse fails or if it matches fewer than 3
// characters, try to parse 3-letter ISO. Do this after the
// display name processing so 3-letter display names are
// preferred. Consider /[A-Z]{3}/ to be valid ISO, and parse
// it manually--UnicodeSet/regex are too slow and heavy.
if (max < 3 && (text.length() - start) >= 3) {
UBool valid = TRUE;
for (int32_t k=0; k<3; ++k) {
UChar ch = text.charAt(start + k); // 16-bit ok
if (ch < 0x41/*'A'*/ || ch > 0x5A/*'Z'*/) {
valid = FALSE;
break;
}
}
if (valid) {
text.extract(start, 3, result);
result[3] = 0;
max = 3;
}
}
pos.setIndex(start + max);
}
/**
* Internal method. Given a currency ISO code and a locale, return
* the "static" currency name. This is usually the same as the
* UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
* format is applied to the number 2.0 (to yield the more common
* plural) to return a static name.
*
* This is used for backward compatibility with old currency logic in
* DecimalFormat and DecimalFormatSymbols.
*/
U_CFUNC void
uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
U_NAMESPACE_QUALIFIER UnicodeString& result, UErrorCode& ec)
{
U_NAMESPACE_USE
UBool isChoiceFormat;
int32_t len;
const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec);
if (U_SUCCESS(ec)) {
// If this is a ChoiceFormat currency, then format an
// arbitrary value; pick something != 1; more common.
result.truncate(0);
if (isChoiceFormat) {
ChoiceFormat f(currname, ec);
if (U_SUCCESS(ec)) {
f.format(2.0, result);
} else {
result = iso;
}
} else {
result = currname;
}
}
}
U_CAPI int32_t U_EXPORT2
ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) {
return (_findMetaData(currency, *ec))[0];
}
U_CAPI double U_EXPORT2
ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) {
const int32_t *data = _findMetaData(currency, *ec);
// If the meta data is invalid, return 0.0.
if (data[0] < 0 || data[0] > MAX_POW10) {
if (U_SUCCESS(*ec)) {
*ec = U_INVALID_FORMAT_ERROR;
}
return 0.0;
}
// If there is no rounding, return 0.0 to indicate no rounding. A
// rounding value (data[1]) of 0 or 1 indicates no rounding.
if (data[1] < 2) {
return 0.0;
}
// Return data[1] / 10^(data[0]). The only actual rounding data,
// as of this writing, is CHF { 2, 5 }.
return double(data[1]) / POW10[data[0]];
}
U_CDECL_BEGIN
typedef struct UCurrencyContext {
uint32_t currType; /* UCurrCurrencyType */
uint32_t listIdx;
} UCurrencyContext;
/*
Please keep this list in alphabetical order.
You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
of these items.
ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
*/
static const struct CurrencyList {
const char *currency;
uint32_t currType;
} gCurrencyList[] = {
{"ADP", UCURR_COMMON|UCURR_DEPRECATED},
{"AED", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"AFA", UCURR_COMMON|UCURR_DEPRECATED},
{"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"AOK", UCURR_COMMON|UCURR_DEPRECATED},
{"AON", UCURR_COMMON|UCURR_DEPRECATED},
{"AOR", UCURR_COMMON|UCURR_DEPRECATED},
{"ARA", UCURR_COMMON|UCURR_DEPRECATED},
{"ARP", UCURR_COMMON|UCURR_DEPRECATED},
{"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"ATS", UCURR_COMMON|UCURR_DEPRECATED},
{"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"AZM", UCURR_COMMON|UCURR_DEPRECATED},
{"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BAD", UCURR_COMMON|UCURR_DEPRECATED},
{"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED},
{"BEF", UCURR_COMMON|UCURR_DEPRECATED},
{"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED},
{"BGL", UCURR_COMMON|UCURR_DEPRECATED},
{"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BND", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BOP", UCURR_COMMON|UCURR_DEPRECATED},
{"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"BRB", UCURR_COMMON|UCURR_DEPRECATED},
{"BRC", UCURR_COMMON|UCURR_DEPRECATED},
{"BRE", UCURR_COMMON|UCURR_DEPRECATED},
{"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BRN", UCURR_COMMON|UCURR_DEPRECATED},
{"BRR", UCURR_COMMON|UCURR_DEPRECATED},
{"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BUK", UCURR_COMMON|UCURR_DEPRECATED},
{"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BYB", UCURR_COMMON|UCURR_DEPRECATED},
{"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED},
{"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"COP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"CSD", UCURR_COMMON|UCURR_DEPRECATED},
{"CSK", UCURR_COMMON|UCURR_DEPRECATED},
{"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"CYP", UCURR_COMMON|UCURR_DEPRECATED},
{"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"DDM", UCURR_COMMON|UCURR_DEPRECATED},
{"DEM", UCURR_COMMON|UCURR_DEPRECATED},
{"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"ECS", UCURR_COMMON|UCURR_DEPRECATED},
{"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED},
{"EEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"EQE", UCURR_COMMON|UCURR_DEPRECATED},
{"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
{"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
{"ESP", UCURR_COMMON|UCURR_DEPRECATED},
{"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"FIM", UCURR_COMMON|UCURR_DEPRECATED},
{"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"FRF", UCURR_COMMON|UCURR_DEPRECATED},
{"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"GEK", UCURR_COMMON|UCURR_DEPRECATED},
{"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"GHC", UCURR_COMMON|UCURR_DEPRECATED},
{"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"GNS", UCURR_COMMON|UCURR_DEPRECATED},
{"GQE", UCURR_COMMON|UCURR_DEPRECATED},
{"GRD", UCURR_COMMON|UCURR_DEPRECATED},
{"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"GWE", UCURR_COMMON|UCURR_DEPRECATED},
{"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"HRD", UCURR_COMMON|UCURR_DEPRECATED},
{"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"IEP", UCURR_COMMON|UCURR_DEPRECATED},
{"ILP", UCURR_COMMON|UCURR_DEPRECATED},
{"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"INR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"ITL", UCURR_COMMON|UCURR_DEPRECATED},
{"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"KES", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"LSM", UCURR_COMMON|UCURR_DEPRECATED},
{"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"LTT", UCURR_COMMON|UCURR_DEPRECATED},
{"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED},
{"LUF", UCURR_COMMON|UCURR_DEPRECATED},
{"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED},
{"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"LVR", UCURR_COMMON|UCURR_DEPRECATED},
{"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MAF", UCURR_COMMON|UCURR_DEPRECATED},
{"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MGF", UCURR_COMMON|UCURR_DEPRECATED},
{"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MLF", UCURR_COMMON|UCURR_DEPRECATED},
{"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MTL", UCURR_COMMON|UCURR_DEPRECATED},
{"MTP", UCURR_COMMON|UCURR_DEPRECATED},
{"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MXP", UCURR_COMMON|UCURR_DEPRECATED},
{"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"MZM", UCURR_COMMON|UCURR_DEPRECATED},
{"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"NIC", UCURR_COMMON|UCURR_DEPRECATED},
{"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"NLG", UCURR_COMMON|UCURR_DEPRECATED},
{"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"PEI", UCURR_COMMON|UCURR_DEPRECATED},
{"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"PES", UCURR_COMMON|UCURR_DEPRECATED},
{"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"PLZ", UCURR_COMMON|UCURR_DEPRECATED},
{"PTE", UCURR_COMMON|UCURR_DEPRECATED},
{"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"RHD", UCURR_COMMON|UCURR_DEPRECATED},
{"ROL", UCURR_COMMON|UCURR_DEPRECATED},
{"RON", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"RUR", UCURR_COMMON|UCURR_DEPRECATED},
{"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SDD", UCURR_COMMON|UCURR_DEPRECATED},
{"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SDP", UCURR_COMMON|UCURR_DEPRECATED},
{"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SIT", UCURR_COMMON|UCURR_DEPRECATED},
{"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SRG", UCURR_COMMON|UCURR_DEPRECATED},
{"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SUR", UCURR_COMMON|UCURR_DEPRECATED},
{"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"TJR", UCURR_COMMON|UCURR_DEPRECATED},
{"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"TMM", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"TPE", UCURR_COMMON|UCURR_DEPRECATED},
{"TRL", UCURR_COMMON|UCURR_DEPRECATED},
{"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"UAK", UCURR_COMMON|UCURR_DEPRECATED},
{"UGS", UCURR_COMMON|UCURR_DEPRECATED},
{"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"UYP", UCURR_COMMON|UCURR_DEPRECATED},
{"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"VEB", UCURR_COMMON|UCURR_DEPRECATED},
{"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
{"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"YDD", UCURR_COMMON|UCURR_DEPRECATED},
{"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"YUD", UCURR_COMMON|UCURR_DEPRECATED},
{"YUM", UCURR_COMMON|UCURR_DEPRECATED},
{"YUN", UCURR_COMMON|UCURR_DEPRECATED},
{"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"ZMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
{"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
{"ZWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
{ NULL, 0 } // Leave here to denote the end of the list.
};
#define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
static int32_t U_CALLCONV
ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
uint32_t currType = myContext->currType;
int32_t count = 0;
/* Count the number of items matching the type we are looking for. */
for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
count++;
}
}
return count;
}
static const char* U_CALLCONV
ucurr_nextCurrencyList(UEnumeration *enumerator,
int32_t* resultLength,
UErrorCode * /*pErrorCode*/)
{
UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
/* Find the next in the list that matches the type we are looking for. */
while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) {
const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
{
if (resultLength) {
*resultLength = 3; /* Currency codes are only 3 chars long */
}
return currItem->currency;
}
}
/* We enumerated too far. */
if (resultLength) {
*resultLength = 0;
}
return NULL;
}
static void U_CALLCONV
ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
((UCurrencyContext *)(enumerator->context))->listIdx = 0;
}
static void U_CALLCONV
ucurr_closeCurrencyList(UEnumeration *enumerator) {
uprv_free(enumerator->context);
uprv_free(enumerator);
}
static const UEnumeration gEnumCurrencyList = {
NULL,
NULL,
ucurr_closeCurrencyList,
ucurr_countCurrencyList,
uenum_unextDefault,
ucurr_nextCurrencyList,
ucurr_resetCurrencyList
};
U_CDECL_END
U_CAPI UEnumeration * U_EXPORT2
ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
UEnumeration *myEnum = NULL;
UCurrencyContext *myContext;
myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
if (myEnum == NULL) {
*pErrorCode = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
if (myContext == NULL) {
*pErrorCode = U_MEMORY_ALLOCATION_ERROR;
uprv_free(myEnum);
return NULL;
}
myContext->currType = currType;
myContext->listIdx = 0;
myEnum->context = myContext;
return myEnum;
}
#endif /* #if !UCONFIG_NO_FORMATTING */
//eof