/* ********************************************************************** * Copyright (c) 2002-2006, 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 "mutex.h" #include "ucln_in.h" #include "uenumimp.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[] = "CurrencyData"; // 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[] = "_"; // 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 //------------------------------------------------------------ // 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); 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 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); Mutex mutex(&gCRegLock); if (!gCRegHead) { /* register for the first time */ ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup); } n->next = gCRegHead; gCRegHead = n; return n; } *status = U_MEMORY_ALLOCATION_ERROR; } return 0; } static UBool unreg(UCurrRegistryKey key) { umtx_init(&gCRegLock); Mutex mutex(&gCRegLock); if (gCRegHead == key) { gCRegHead = gCRegHead->next; delete (CReg*)key; return TRUE; } CReg* p = gCRegHead; while (p) { if (p->next == key) { p->next = ((CReg*)key)->next; delete (CReg*)key; return TRUE; } p = p->next; } return FALSE; } static const UChar* get(const char* id) { umtx_init(&gCRegLock); Mutex mutex(&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) { return p->iso; } p = p->next; } return NULL; } /* 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 // 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); s = ures_getStringByKey(cm, id, &resLen, &localStatus); if ((s == NULL || U_FAILURE(localStatus)) && variantType != VARIANT_IS_EMPTY && (id[0] != 0)) { // We don't know about it. Check to see if we support the variant. if (variantType & VARIANT_IS_EURO) { s = ures_getStringByKey(cm, VAR_DELIM_EURO, &resLen, ec); } else { uloc_getParent(locale, id, sizeof(id), ec); *ec = U_USING_FALLBACK_WARNING; ures_close(cm); 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); } } ures_close(cm); } 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 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; // Multi-level resource inheritance fallback loop for (;;) { ec2 = U_ZERO_ERROR; UResourceBundle* rb = ures_open(NULL, loc, &ec2); rb = ures_getByKey(rb, CURRENCIES, rb, &ec2); rb = ures_getByKey(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) || !fallback(loc)) { if (ec2 == U_USING_DEFAULT_WARNING || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) { *ec = ec2; } break; } else if (strlen(loc) == 0) { *ec = U_USING_DEFAULT_WARNING; } else if (*ec != U_USING_DEFAULT_WARNING) { *ec = U_USING_FALLBACK_WARNING; } } // 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_NAMESPACE_BEGIN void uprv_parseCurrency(const char* locale, const UnicodeString& text, ParsePosition& pos, UChar* result, UErrorCode& ec) { // 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 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); } U_NAMESPACE_END /** * 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, UnicodeString& result, UErrorCode& ec) { 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_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_NON_DEPRECATED}, {"CSK", UCURR_COMMON|UCURR_DEPRECATED}, {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"CYP", UCURR_COMMON|UCURR_NON_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_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_NON_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_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}, {"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_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_NON_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}, {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"VEB", 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. */ *pErrorCode = U_INDEX_OUTOFBOUNDS_ERROR; 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