f1b9a527b7
X-SVN-Rev: 22098
1125 lines
39 KiB
C++
1125 lines
39 KiB
C++
/*
|
|
**********************************************************************
|
|
* Copyright (c) 2002-2007, 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_CAPI 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_CAPI 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
|