intl/icu/source/i18n/ucurr.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/i18n/ucurr.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2657 @@
     1.4 +/*
     1.5 +**********************************************************************
     1.6 +* Copyright (c) 2002-2013, International Business Machines
     1.7 +* Corporation and others.  All Rights Reserved.
     1.8 +**********************************************************************
     1.9 +*/
    1.10 +
    1.11 +#include "unicode/utypes.h"
    1.12 +
    1.13 +#if !UCONFIG_NO_FORMATTING
    1.14 +
    1.15 +#include "unicode/ucurr.h"
    1.16 +#include "unicode/locid.h"
    1.17 +#include "unicode/ures.h"
    1.18 +#include "unicode/ustring.h"
    1.19 +#include "unicode/choicfmt.h"
    1.20 +#include "unicode/parsepos.h"
    1.21 +#include "ustr_imp.h"
    1.22 +#include "cmemory.h"
    1.23 +#include "cstring.h"
    1.24 +#include "uassert.h"
    1.25 +#include "umutex.h"
    1.26 +#include "ucln_in.h"
    1.27 +#include "uenumimp.h"
    1.28 +#include "uhash.h"
    1.29 +#include "hash.h"
    1.30 +#include "uresimp.h"
    1.31 +#include "ulist.h"
    1.32 +#include "ureslocs.h"
    1.33 +
    1.34 +//#define UCURR_DEBUG_EQUIV 1
    1.35 +#ifdef UCURR_DEBUG_EQUIV
    1.36 +#include "stdio.h"
    1.37 +#endif
    1.38 +//#define UCURR_DEBUG 1
    1.39 +#ifdef UCURR_DEBUG
    1.40 +#include "stdio.h"
    1.41 +#endif
    1.42 +
    1.43 +typedef struct IsoCodeEntry {
    1.44 +    const UChar *isoCode; /* const because it's a reference to a resource bundle string. */
    1.45 +    UDate from;
    1.46 +    UDate to;
    1.47 +} IsoCodeEntry;
    1.48 +
    1.49 +//------------------------------------------------------------
    1.50 +// Constants
    1.51 +
    1.52 +// Default currency meta data of last resort.  We try to use the
    1.53 +// defaults encoded in the meta data resource bundle.  If there is a
    1.54 +// configuration/build error and these are not available, we use these
    1.55 +// hard-coded defaults (which should be identical).
    1.56 +static const int32_t LAST_RESORT_DATA[] = { 2, 0, 2, 0 };
    1.57 +
    1.58 +// POW10[i] = 10^i, i=0..MAX_POW10
    1.59 +static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
    1.60 +                                 1000000, 10000000, 100000000, 1000000000 };
    1.61 +
    1.62 +static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1;
    1.63 +
    1.64 +// Defines equivalent currency symbols.
    1.65 +static const char *EQUIV_CURRENCY_SYMBOLS[][2] = {
    1.66 +    {"\\u00a5", "\\uffe5"},
    1.67 +    {"$", "\\ufe69"},
    1.68 +    {"$", "\\uff04"},
    1.69 +    {"\\u20a8", "\\u20b9"},
    1.70 +    {"\\u00a3", "\\u20a4"}};
    1.71 +
    1.72 +#define ISO_CURRENCY_CODE_LENGTH 3
    1.73 +
    1.74 +//------------------------------------------------------------
    1.75 +// Resource tags
    1.76 +//
    1.77 +
    1.78 +static const char CURRENCY_DATA[] = "supplementalData";
    1.79 +// Tag for meta-data, in root.
    1.80 +static const char CURRENCY_META[] = "CurrencyMeta";
    1.81 +
    1.82 +// Tag for map from countries to currencies, in root.
    1.83 +static const char CURRENCY_MAP[] = "CurrencyMap";
    1.84 +
    1.85 +// Tag for default meta-data, in CURRENCY_META
    1.86 +static const char DEFAULT_META[] = "DEFAULT";
    1.87 +
    1.88 +// Variant for legacy pre-euro mapping in CurrencyMap
    1.89 +static const char VAR_PRE_EURO[] = "PREEURO";
    1.90 +
    1.91 +// Variant for legacy euro mapping in CurrencyMap
    1.92 +static const char VAR_EURO[] = "EURO";
    1.93 +
    1.94 +// Variant delimiter
    1.95 +static const char VAR_DELIM = '_';
    1.96 +static const char VAR_DELIM_STR[] = "_";
    1.97 +
    1.98 +// Variant for legacy euro mapping in CurrencyMap
    1.99 +//static const char VAR_DELIM_EURO[] = "_EURO";
   1.100 +
   1.101 +#define VARIANT_IS_EMPTY    0
   1.102 +#define VARIANT_IS_EURO     0x1
   1.103 +#define VARIANT_IS_PREEURO  0x2
   1.104 +
   1.105 +// Tag for localized display names (symbols) of currencies
   1.106 +static const char CURRENCIES[] = "Currencies";
   1.107 +static const char CURRENCYPLURALS[] = "CurrencyPlurals";
   1.108 +
   1.109 +// Marker character indicating that a display name is a ChoiceFormat
   1.110 +// pattern.  Strings that start with one mark are ChoiceFormat
   1.111 +// patterns.  Strings that start with 2 marks are static strings, and
   1.112 +// the first mark is deleted.
   1.113 +static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign
   1.114 +
   1.115 +static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
   1.116 +
   1.117 +// ISO codes mapping table
   1.118 +static const UHashtable* gIsoCodes = NULL;
   1.119 +static icu::UInitOnce gIsoCodesInitOnce = U_INITONCE_INITIALIZER;
   1.120 +
   1.121 +// Currency symbol equivalances
   1.122 +static const icu::Hashtable* gCurrSymbolsEquiv = NULL;
   1.123 +static icu::UInitOnce gCurrSymbolsEquivInitOnce = U_INITONCE_INITIALIZER;
   1.124 +
   1.125 +// EquivIterator iterates over all strings that are equivalent to a given
   1.126 +// string, s. Note that EquivIterator will never yield s itself.
   1.127 +class EquivIterator : icu::UMemory {
   1.128 +public:
   1.129 +    // Constructor. hash stores the equivalence relationships; s is the string
   1.130 +    // for which we find equivalent strings.
   1.131 +    inline EquivIterator(const icu::Hashtable& hash, const icu::UnicodeString& s)
   1.132 +        : _hash(hash) { 
   1.133 +        _start = _current = &s;
   1.134 +    }
   1.135 +    inline ~EquivIterator() { }
   1.136 +
   1.137 +    // next returns the next equivalent string or NULL if there are no more.
   1.138 +    // If s has no equivalent strings, next returns NULL on the first call.
   1.139 +    const icu::UnicodeString *next();
   1.140 +private:
   1.141 +    const icu::Hashtable& _hash;
   1.142 +    const icu::UnicodeString* _start;
   1.143 +    const icu::UnicodeString* _current;
   1.144 +};
   1.145 +
   1.146 +const icu::UnicodeString *
   1.147 +EquivIterator::next() {
   1.148 +    const icu::UnicodeString* _next = (const icu::UnicodeString*) _hash.get(*_current);
   1.149 +    if (_next == NULL) {
   1.150 +        U_ASSERT(_current == _start);
   1.151 +        return NULL;
   1.152 +    }
   1.153 +    if (*_next == *_start) {
   1.154 +        return NULL;
   1.155 +    }
   1.156 +    _current = _next;
   1.157 +    return _next;
   1.158 +}
   1.159 +
   1.160 +// makeEquivalent makes lhs and rhs equivalent by updating the equivalence
   1.161 +// relations in hash accordingly.
   1.162 +static void makeEquivalent(
   1.163 +    const icu::UnicodeString &lhs,
   1.164 +    const icu::UnicodeString &rhs,
   1.165 +    icu::Hashtable* hash, UErrorCode &status) {
   1.166 +    if (U_FAILURE(status)) {
   1.167 +        return;
   1.168 +    }
   1.169 +    if (lhs == rhs) {
   1.170 +        // already equivalent
   1.171 +        return;
   1.172 +    }
   1.173 +    EquivIterator leftIter(*hash, lhs);
   1.174 +    EquivIterator rightIter(*hash, rhs);
   1.175 +    const icu::UnicodeString *firstLeft = leftIter.next();
   1.176 +    const icu::UnicodeString *firstRight = rightIter.next();
   1.177 +    const icu::UnicodeString *nextLeft = firstLeft;
   1.178 +    const icu::UnicodeString *nextRight = firstRight;
   1.179 +    while (nextLeft != NULL && nextRight != NULL) {
   1.180 +        if (*nextLeft == rhs || *nextRight == lhs) {
   1.181 +            // Already equivalent
   1.182 +            return;
   1.183 +        }
   1.184 +        nextLeft = leftIter.next();
   1.185 +        nextRight = rightIter.next();
   1.186 +    }
   1.187 +    // Not equivalent. Must join.
   1.188 +    icu::UnicodeString *newFirstLeft;
   1.189 +    icu::UnicodeString *newFirstRight;
   1.190 +    if (firstRight == NULL && firstLeft == NULL) {
   1.191 +        // Neither lhs or rhs belong to an equivalence circle, so we form
   1.192 +        // a new equivalnce circle of just lhs and rhs.
   1.193 +        newFirstLeft = new icu::UnicodeString(rhs);
   1.194 +        newFirstRight = new icu::UnicodeString(lhs);
   1.195 +    } else if (firstRight == NULL) {
   1.196 +        // lhs belongs to an equivalence circle, but rhs does not, so we link
   1.197 +        // rhs into lhs' circle.
   1.198 +        newFirstLeft = new icu::UnicodeString(rhs);
   1.199 +        newFirstRight = new icu::UnicodeString(*firstLeft);
   1.200 +    } else if (firstLeft == NULL) {
   1.201 +        // rhs belongs to an equivlance circle, but lhs does not, so we link
   1.202 +        // lhs into rhs' circle.
   1.203 +        newFirstLeft = new icu::UnicodeString(*firstRight);
   1.204 +        newFirstRight = new icu::UnicodeString(lhs);
   1.205 +    } else {
   1.206 +        // Both lhs and rhs belong to different equivalnce circles. We link
   1.207 +        // them together to form one single, larger equivalnce circle.
   1.208 +        newFirstLeft = new icu::UnicodeString(*firstRight);
   1.209 +        newFirstRight = new icu::UnicodeString(*firstLeft);
   1.210 +    }
   1.211 +    if (newFirstLeft == NULL || newFirstRight == NULL) {
   1.212 +        delete newFirstLeft;
   1.213 +        delete newFirstRight;
   1.214 +        status = U_MEMORY_ALLOCATION_ERROR;
   1.215 +        return;
   1.216 +    }
   1.217 +    hash->put(lhs, (void *) newFirstLeft, status);
   1.218 +    hash->put(rhs, (void *) newFirstRight, status);
   1.219 +}
   1.220 +
   1.221 +// countEquivalent counts how many strings are equivalent to s.
   1.222 +// hash stores all the equivalnce relations.
   1.223 +// countEquivalent does not include s itself in the count.
   1.224 +static int32_t countEquivalent(const icu::Hashtable &hash, const icu::UnicodeString &s) {
   1.225 +    int32_t result = 0;
   1.226 +    EquivIterator iter(hash, s);
   1.227 +    while (iter.next() != NULL) {
   1.228 +        ++result;
   1.229 +    }
   1.230 +#ifdef UCURR_DEBUG_EQUIV
   1.231 + {
   1.232 +   char tmp[200];
   1.233 +   s.extract(0,s.length(),tmp, "UTF-8");
   1.234 +   printf("CountEquivalent('%s') = %d\n", tmp, result);
   1.235 + }
   1.236 +#endif
   1.237 +    return result;
   1.238 +}
   1.239 +
   1.240 +static const icu::Hashtable* getCurrSymbolsEquiv();
   1.241 +
   1.242 +//------------------------------------------------------------
   1.243 +// Code
   1.244 +
   1.245 +/**
   1.246 + * Cleanup callback func
   1.247 + */
   1.248 +static UBool U_CALLCONV 
   1.249 +isoCodes_cleanup(void)
   1.250 +{
   1.251 +    if (gIsoCodes != NULL) {
   1.252 +        uhash_close(const_cast<UHashtable *>(gIsoCodes));
   1.253 +        gIsoCodes = NULL;
   1.254 +    }
   1.255 +    gIsoCodesInitOnce.reset();
   1.256 +    return TRUE;
   1.257 +}
   1.258 +
   1.259 +/**
   1.260 + * Cleanup callback func
   1.261 + */
   1.262 +static UBool U_CALLCONV 
   1.263 +currSymbolsEquiv_cleanup(void)
   1.264 +{
   1.265 +    delete const_cast<icu::Hashtable *>(gCurrSymbolsEquiv);
   1.266 +    gCurrSymbolsEquiv = NULL;
   1.267 +    gCurrSymbolsEquivInitOnce.reset();
   1.268 +    return TRUE;
   1.269 +}
   1.270 +
   1.271 +/**
   1.272 + * Deleter for OlsonToMetaMappingEntry
   1.273 + */
   1.274 +static void U_CALLCONV
   1.275 +deleteIsoCodeEntry(void *obj) {
   1.276 +    IsoCodeEntry *entry = (IsoCodeEntry*)obj;
   1.277 +    uprv_free(entry);
   1.278 +}
   1.279 +
   1.280 +/**
   1.281 + * Deleter for gCurrSymbolsEquiv.
   1.282 + */
   1.283 +static void U_CALLCONV
   1.284 +deleteUnicode(void *obj) {
   1.285 +    icu::UnicodeString *entry = (icu::UnicodeString*)obj;
   1.286 +    delete entry;
   1.287 +}
   1.288 +
   1.289 +/**
   1.290 + * Unfortunately, we have to convert the UChar* currency code to char*
   1.291 + * to use it as a resource key.
   1.292 + */
   1.293 +static inline char*
   1.294 +myUCharsToChars(char* resultOfLen4, const UChar* currency) {
   1.295 +    u_UCharsToChars(currency, resultOfLen4, ISO_CURRENCY_CODE_LENGTH);
   1.296 +    resultOfLen4[ISO_CURRENCY_CODE_LENGTH] = 0;
   1.297 +    return resultOfLen4;
   1.298 +}
   1.299 +
   1.300 +/**
   1.301 + * Internal function to look up currency data.  Result is an array of
   1.302 + * four integers.  The first is the fraction digits.  The second is the
   1.303 + * rounding increment, or 0 if none.  The rounding increment is in
   1.304 + * units of 10^(-fraction_digits).  The third and fourth are the same
   1.305 + * except that they are those used in cash transations ( cashDigits
   1.306 + * and cashRounding ).
   1.307 + */
   1.308 +static const int32_t*
   1.309 +_findMetaData(const UChar* currency, UErrorCode& ec) {
   1.310 +
   1.311 +    if (currency == 0 || *currency == 0) {
   1.312 +        if (U_SUCCESS(ec)) {
   1.313 +            ec = U_ILLEGAL_ARGUMENT_ERROR;
   1.314 +        }
   1.315 +        return LAST_RESORT_DATA;
   1.316 +    }
   1.317 +
   1.318 +    // Get CurrencyMeta resource out of root locale file.  [This may
   1.319 +    // move out of the root locale file later; if it does, update this
   1.320 +    // code.]
   1.321 +    UResourceBundle* currencyData = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &ec);
   1.322 +    UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec);
   1.323 +
   1.324 +    if (U_FAILURE(ec)) {
   1.325 +        ures_close(currencyMeta);
   1.326 +        // Config/build error; return hard-coded defaults
   1.327 +        return LAST_RESORT_DATA;
   1.328 +    }
   1.329 +
   1.330 +    // Look up our currency, or if that's not available, then DEFAULT
   1.331 +    char buf[ISO_CURRENCY_CODE_LENGTH+1];
   1.332 +    UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure
   1.333 +    UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2);
   1.334 +      if (U_FAILURE(ec2)) {
   1.335 +        ures_close(rb);
   1.336 +        rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec);
   1.337 +        if (U_FAILURE(ec)) {
   1.338 +            ures_close(currencyMeta);
   1.339 +            ures_close(rb);
   1.340 +            // Config/build error; return hard-coded defaults
   1.341 +            return LAST_RESORT_DATA;
   1.342 +        }
   1.343 +    }
   1.344 +
   1.345 +    int32_t len;
   1.346 +    const int32_t *data = ures_getIntVector(rb, &len, &ec);
   1.347 +    if (U_FAILURE(ec) || len != 4) {
   1.348 +        // Config/build error; return hard-coded defaults
   1.349 +        if (U_SUCCESS(ec)) {
   1.350 +            ec = U_INVALID_FORMAT_ERROR;
   1.351 +        }
   1.352 +        ures_close(currencyMeta);
   1.353 +        ures_close(rb);
   1.354 +        return LAST_RESORT_DATA;
   1.355 +    }
   1.356 +
   1.357 +    ures_close(currencyMeta);
   1.358 +    ures_close(rb);
   1.359 +    return data;
   1.360 +}
   1.361 +
   1.362 +// -------------------------------------
   1.363 +
   1.364 +/**
   1.365 + * @see VARIANT_IS_EURO
   1.366 + * @see VARIANT_IS_PREEURO
   1.367 + */
   1.368 +static uint32_t
   1.369 +idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec)
   1.370 +{
   1.371 +    uint32_t variantType = 0;
   1.372 +    // !!! this is internal only, assumes buffer is not null and capacity is sufficient
   1.373 +    // Extract the country name and variant name.  We only
   1.374 +    // recognize two variant names, EURO and PREEURO.
   1.375 +    char variant[ULOC_FULLNAME_CAPACITY];
   1.376 +    uloc_getCountry(locale, countryAndVariant, capacity, ec);
   1.377 +    uloc_getVariant(locale, variant, sizeof(variant), ec);
   1.378 +    if (variant[0] != 0) {
   1.379 +        variantType = (uint32_t)(0 == uprv_strcmp(variant, VAR_EURO))
   1.380 +                   | ((uint32_t)(0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1);
   1.381 +        if (variantType)
   1.382 +        {
   1.383 +            uprv_strcat(countryAndVariant, VAR_DELIM_STR);
   1.384 +            uprv_strcat(countryAndVariant, variant);
   1.385 +        }
   1.386 +    }
   1.387 +    return variantType;
   1.388 +}
   1.389 +
   1.390 +// ------------------------------------------
   1.391 +//
   1.392 +// Registration
   1.393 +//
   1.394 +//-------------------------------------------
   1.395 +
   1.396 +// don't use ICUService since we don't need fallback
   1.397 +
   1.398 +U_CDECL_BEGIN
   1.399 +static UBool U_CALLCONV currency_cleanup(void);
   1.400 +U_CDECL_END
   1.401 +
   1.402 +#if !UCONFIG_NO_SERVICE
   1.403 +struct CReg;
   1.404 +
   1.405 +static UMutex gCRegLock = U_MUTEX_INITIALIZER;
   1.406 +static CReg* gCRegHead = 0;
   1.407 +
   1.408 +struct CReg : public icu::UMemory {
   1.409 +    CReg *next;
   1.410 +    UChar iso[ISO_CURRENCY_CODE_LENGTH+1];
   1.411 +    char  id[ULOC_FULLNAME_CAPACITY];
   1.412 +
   1.413 +    CReg(const UChar* _iso, const char* _id)
   1.414 +        : next(0)
   1.415 +    {
   1.416 +        int32_t len = (int32_t)uprv_strlen(_id);
   1.417 +        if (len > (int32_t)(sizeof(id)-1)) {
   1.418 +            len = (sizeof(id)-1);
   1.419 +        }
   1.420 +        uprv_strncpy(id, _id, len);
   1.421 +        id[len] = 0;
   1.422 +        uprv_memcpy(iso, _iso, ISO_CURRENCY_CODE_LENGTH * sizeof(const UChar));
   1.423 +        iso[ISO_CURRENCY_CODE_LENGTH] = 0;
   1.424 +    }
   1.425 +
   1.426 +    static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status)
   1.427 +    {
   1.428 +        if (status && U_SUCCESS(*status) && _iso && _id) {
   1.429 +            CReg* n = new CReg(_iso, _id);
   1.430 +            if (n) {
   1.431 +                umtx_lock(&gCRegLock);
   1.432 +                if (!gCRegHead) {
   1.433 +                    /* register for the first time */
   1.434 +                    ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
   1.435 +                }
   1.436 +                n->next = gCRegHead;
   1.437 +                gCRegHead = n;
   1.438 +                umtx_unlock(&gCRegLock);
   1.439 +                return n;
   1.440 +            }
   1.441 +            *status = U_MEMORY_ALLOCATION_ERROR;
   1.442 +        }
   1.443 +        return 0;
   1.444 +    }
   1.445 +
   1.446 +    static UBool unreg(UCurrRegistryKey key) {
   1.447 +        UBool found = FALSE;
   1.448 +        umtx_lock(&gCRegLock);
   1.449 +
   1.450 +        CReg** p = &gCRegHead;
   1.451 +        while (*p) {
   1.452 +            if (*p == key) {
   1.453 +                *p = ((CReg*)key)->next;
   1.454 +                delete (CReg*)key;
   1.455 +                found = TRUE;
   1.456 +                break;
   1.457 +            }
   1.458 +            p = &((*p)->next);
   1.459 +        }
   1.460 +
   1.461 +        umtx_unlock(&gCRegLock);
   1.462 +        return found;
   1.463 +    }
   1.464 +
   1.465 +    static const UChar* get(const char* id) {
   1.466 +        const UChar* result = NULL;
   1.467 +        umtx_lock(&gCRegLock);
   1.468 +        CReg* p = gCRegHead;
   1.469 +
   1.470 +        /* register cleanup of the mutex */
   1.471 +        ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
   1.472 +        while (p) {
   1.473 +            if (uprv_strcmp(id, p->id) == 0) {
   1.474 +                result = p->iso;
   1.475 +                break;
   1.476 +            }
   1.477 +            p = p->next;
   1.478 +        }
   1.479 +        umtx_unlock(&gCRegLock);
   1.480 +        return result;
   1.481 +    }
   1.482 +
   1.483 +    /* This doesn't need to be thread safe. It's for u_cleanup only. */
   1.484 +    static void cleanup(void) {
   1.485 +        while (gCRegHead) {
   1.486 +            CReg* n = gCRegHead;
   1.487 +            gCRegHead = gCRegHead->next;
   1.488 +            delete n;
   1.489 +        }
   1.490 +    }
   1.491 +};
   1.492 +
   1.493 +// -------------------------------------
   1.494 +
   1.495 +U_CAPI UCurrRegistryKey U_EXPORT2
   1.496 +ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
   1.497 +{
   1.498 +    if (status && U_SUCCESS(*status)) {
   1.499 +        char id[ULOC_FULLNAME_CAPACITY];
   1.500 +        idForLocale(locale, id, sizeof(id), status);
   1.501 +        return CReg::reg(isoCode, id, status);
   1.502 +    }
   1.503 +    return NULL;
   1.504 +}
   1.505 +
   1.506 +// -------------------------------------
   1.507 +
   1.508 +U_CAPI UBool U_EXPORT2
   1.509 +ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
   1.510 +{
   1.511 +    if (status && U_SUCCESS(*status)) {
   1.512 +        return CReg::unreg(key);
   1.513 +    }
   1.514 +    return FALSE;
   1.515 +}
   1.516 +#endif /* UCONFIG_NO_SERVICE */
   1.517 +
   1.518 +// -------------------------------------
   1.519 +
   1.520 +/**
   1.521 + * Release all static memory held by currency.
   1.522 + */
   1.523 +/*The declaration here is needed so currency_cleanup(void)
   1.524 + * can call this function.
   1.525 + */
   1.526 +static UBool U_CALLCONV
   1.527 +currency_cache_cleanup(void);
   1.528 +
   1.529 +U_CDECL_BEGIN
   1.530 +static UBool U_CALLCONV currency_cleanup(void) {
   1.531 +#if !UCONFIG_NO_SERVICE
   1.532 +    CReg::cleanup();
   1.533 +#endif
   1.534 +    /*
   1.535 +     * There might be some cached currency data or isoCodes data.
   1.536 +     */
   1.537 +    currency_cache_cleanup();
   1.538 +    isoCodes_cleanup();
   1.539 +    currSymbolsEquiv_cleanup();
   1.540 +
   1.541 +    return TRUE;
   1.542 +}
   1.543 +U_CDECL_END
   1.544 +
   1.545 +// -------------------------------------
   1.546 +
   1.547 +U_CAPI int32_t U_EXPORT2
   1.548 +ucurr_forLocale(const char* locale,
   1.549 +                UChar* buff,
   1.550 +                int32_t buffCapacity,
   1.551 +                UErrorCode* ec)
   1.552 +{
   1.553 +    int32_t resLen = 0;
   1.554 +    const UChar* s = NULL;
   1.555 +    if (ec != NULL && U_SUCCESS(*ec)) {
   1.556 +        if ((buff && buffCapacity) || !buffCapacity) {
   1.557 +            UErrorCode localStatus = U_ZERO_ERROR;
   1.558 +            char id[ULOC_FULLNAME_CAPACITY];
   1.559 +            if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) {
   1.560 +                // there is a currency keyword. Try to see if it's valid
   1.561 +                if(buffCapacity > resLen) {
   1.562 +                    /* Normalize the currency keyword value to upper case. */
   1.563 +                    T_CString_toUpperCase(id);
   1.564 +                    u_charsToUChars(id, buff, resLen);
   1.565 +                }
   1.566 +            } else {
   1.567 +                // get country or country_variant in `id'
   1.568 +                uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
   1.569 +
   1.570 +                if (U_FAILURE(*ec)) {
   1.571 +                    return 0;
   1.572 +                }
   1.573 +
   1.574 +#if !UCONFIG_NO_SERVICE
   1.575 +                const UChar* result = CReg::get(id);
   1.576 +                if (result) {
   1.577 +                    if(buffCapacity > u_strlen(result)) {
   1.578 +                        u_strcpy(buff, result);
   1.579 +                    }
   1.580 +                    return u_strlen(result);
   1.581 +                }
   1.582 +#endif
   1.583 +                // Remove variants, which is only needed for registration.
   1.584 +                char *idDelim = strchr(id, VAR_DELIM);
   1.585 +                if (idDelim) {
   1.586 +                    idDelim[0] = 0;
   1.587 +                }
   1.588 +
   1.589 +                // Look up the CurrencyMap element in the root bundle.
   1.590 +                UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
   1.591 +                UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
   1.592 +                UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
   1.593 +                UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus);
   1.594 +                s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
   1.595 +
   1.596 +                /*
   1.597 +                Get the second item when PREEURO is requested, and this is a known Euro country.
   1.598 +                If the requested variant is PREEURO, and this isn't a Euro country, assume
   1.599 +                that the country changed over to the Euro in the future. This is probably
   1.600 +                an old version of ICU that hasn't been updated yet. The latest currency is
   1.601 +                probably correct.
   1.602 +                */
   1.603 +                if (U_SUCCESS(localStatus)) {
   1.604 +                    if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) {
   1.605 +                        currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus);
   1.606 +                        s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
   1.607 +                    }
   1.608 +                    else if ((variantType & VARIANT_IS_EURO)) {
   1.609 +                        s = EUR_STR;
   1.610 +                    }
   1.611 +                }
   1.612 +                ures_close(countryArray);
   1.613 +                ures_close(currencyReq);
   1.614 +
   1.615 +                if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0)
   1.616 +                {
   1.617 +                    // We don't know about it.  Check to see if we support the variant.
   1.618 +                    uloc_getParent(locale, id, sizeof(id), ec);
   1.619 +                    *ec = U_USING_FALLBACK_WARNING;
   1.620 +                    return ucurr_forLocale(id, buff, buffCapacity, ec);
   1.621 +                }
   1.622 +                else if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) {
   1.623 +                    // There is nothing to fallback to. Report the failure/warning if possible.
   1.624 +                    *ec = localStatus;
   1.625 +                }
   1.626 +                if (U_SUCCESS(*ec)) {
   1.627 +                    if(buffCapacity > resLen) {
   1.628 +                        u_strcpy(buff, s);
   1.629 +                    }
   1.630 +                }
   1.631 +            }
   1.632 +            return u_terminateUChars(buff, buffCapacity, resLen, ec);
   1.633 +        } else {
   1.634 +            *ec = U_ILLEGAL_ARGUMENT_ERROR;
   1.635 +        }
   1.636 +    }
   1.637 +    return resLen;
   1.638 +}
   1.639 +
   1.640 +// end registration
   1.641 +
   1.642 +/**
   1.643 + * Modify the given locale name by removing the rightmost _-delimited
   1.644 + * element.  If there is none, empty the string ("" == root).
   1.645 + * NOTE: The string "root" is not recognized; do not use it.
   1.646 + * @return TRUE if the fallback happened; FALSE if locale is already
   1.647 + * root ("").
   1.648 + */
   1.649 +static UBool fallback(char *loc) {
   1.650 +    if (!*loc) {
   1.651 +        return FALSE;
   1.652 +    }
   1.653 +    UErrorCode status = U_ZERO_ERROR;
   1.654 +    uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status);
   1.655 + /*
   1.656 +    char *i = uprv_strrchr(loc, '_');
   1.657 +    if (i == NULL) {
   1.658 +        i = loc;
   1.659 +    }
   1.660 +    *i = 0;
   1.661 + */
   1.662 +    return TRUE;
   1.663 +}
   1.664 +
   1.665 +
   1.666 +U_CAPI const UChar* U_EXPORT2
   1.667 +ucurr_getName(const UChar* currency,
   1.668 +              const char* locale,
   1.669 +              UCurrNameStyle nameStyle,
   1.670 +              UBool* isChoiceFormat, // fillin
   1.671 +              int32_t* len, // fillin
   1.672 +              UErrorCode* ec) {
   1.673 +
   1.674 +    // Look up the Currencies resource for the given locale.  The
   1.675 +    // Currencies locale data looks like this:
   1.676 +    //|en {
   1.677 +    //|  Currencies {
   1.678 +    //|    USD { "US$", "US Dollar" }
   1.679 +    //|    CHF { "Sw F", "Swiss Franc" }
   1.680 +    //|    INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
   1.681 +    //|    //...
   1.682 +    //|  }
   1.683 +    //|}
   1.684 +
   1.685 +    if (U_FAILURE(*ec)) {
   1.686 +        return 0;
   1.687 +    }
   1.688 +
   1.689 +    int32_t choice = (int32_t) nameStyle;
   1.690 +    if (choice < 0 || choice > 1) {
   1.691 +        *ec = U_ILLEGAL_ARGUMENT_ERROR;
   1.692 +        return 0;
   1.693 +    }
   1.694 +
   1.695 +    // In the future, resource bundles may implement multi-level
   1.696 +    // fallback.  That is, if a currency is not found in the en_US
   1.697 +    // Currencies data, then the en Currencies data will be searched.
   1.698 +    // Currently, if a Currencies datum exists in en_US and en, the
   1.699 +    // en_US entry hides that in en.
   1.700 +
   1.701 +    // We want multi-level fallback for this resource, so we implement
   1.702 +    // it manually.
   1.703 +
   1.704 +    // Use a separate UErrorCode here that does not propagate out of
   1.705 +    // this function.
   1.706 +    UErrorCode ec2 = U_ZERO_ERROR;
   1.707 +
   1.708 +    char loc[ULOC_FULLNAME_CAPACITY];
   1.709 +    uloc_getName(locale, loc, sizeof(loc), &ec2);
   1.710 +    if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
   1.711 +        *ec = U_ILLEGAL_ARGUMENT_ERROR;
   1.712 +        return 0;
   1.713 +    }
   1.714 +
   1.715 +    char buf[ISO_CURRENCY_CODE_LENGTH+1];
   1.716 +    myUCharsToChars(buf, currency);
   1.717 +    
   1.718 +    /* Normalize the keyword value to uppercase */
   1.719 +    T_CString_toUpperCase(buf);
   1.720 +    
   1.721 +    const UChar* s = NULL;
   1.722 +    ec2 = U_ZERO_ERROR;
   1.723 +    UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
   1.724 +
   1.725 +    rb = ures_getByKey(rb, CURRENCIES, rb, &ec2);
   1.726 +
   1.727 +    // Fetch resource with multi-level resource inheritance fallback
   1.728 +    rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
   1.729 +
   1.730 +    s = ures_getStringByIndex(rb, choice, len, &ec2);
   1.731 +    ures_close(rb);
   1.732 +
   1.733 +    // If we've succeeded we're done.  Otherwise, try to fallback.
   1.734 +    // If that fails (because we are already at root) then exit.
   1.735 +    if (U_SUCCESS(ec2)) {
   1.736 +        if (ec2 == U_USING_DEFAULT_WARNING
   1.737 +            || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
   1.738 +            *ec = ec2;
   1.739 +        }
   1.740 +    }
   1.741 +
   1.742 +    // Determine if this is a ChoiceFormat pattern.  One leading mark
   1.743 +    // indicates a ChoiceFormat.  Two indicates a static string that
   1.744 +    // starts with a mark.  In either case, the first mark is ignored,
   1.745 +    // if present.  Marks in the rest of the string have no special
   1.746 +    // meaning.
   1.747 +    *isChoiceFormat = FALSE;
   1.748 +    if (U_SUCCESS(ec2)) {
   1.749 +        U_ASSERT(s != NULL);
   1.750 +        int32_t i=0;
   1.751 +        while (i < *len && s[i] == CHOICE_FORMAT_MARK && i < 2) {
   1.752 +            ++i;
   1.753 +        }
   1.754 +        *isChoiceFormat = (i == 1);
   1.755 +        if (i != 0) ++s; // Skip over first mark
   1.756 +        return s;
   1.757 +    }
   1.758 +
   1.759 +    // If we fail to find a match, use the ISO 4217 code
   1.760 +    *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
   1.761 +    *ec = U_USING_DEFAULT_WARNING;
   1.762 +    return currency;
   1.763 +}
   1.764 +
   1.765 +U_CAPI const UChar* U_EXPORT2
   1.766 +ucurr_getPluralName(const UChar* currency,
   1.767 +                    const char* locale,
   1.768 +                    UBool* isChoiceFormat,
   1.769 +                    const char* pluralCount,
   1.770 +                    int32_t* len, // fillin
   1.771 +                    UErrorCode* ec) {
   1.772 +    // Look up the Currencies resource for the given locale.  The
   1.773 +    // Currencies locale data looks like this:
   1.774 +    //|en {
   1.775 +    //|  CurrencyPlurals {
   1.776 +    //|    USD{
   1.777 +    //|      one{"US dollar"}
   1.778 +    //|      other{"US dollars"}
   1.779 +    //|    }
   1.780 +    //|  }
   1.781 +    //|}
   1.782 +
   1.783 +    if (U_FAILURE(*ec)) {
   1.784 +        return 0;
   1.785 +    }
   1.786 +
   1.787 +    // Use a separate UErrorCode here that does not propagate out of
   1.788 +    // this function.
   1.789 +    UErrorCode ec2 = U_ZERO_ERROR;
   1.790 +
   1.791 +    char loc[ULOC_FULLNAME_CAPACITY];
   1.792 +    uloc_getName(locale, loc, sizeof(loc), &ec2);
   1.793 +    if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
   1.794 +        *ec = U_ILLEGAL_ARGUMENT_ERROR;
   1.795 +        return 0;
   1.796 +    }
   1.797 +
   1.798 +    char buf[ISO_CURRENCY_CODE_LENGTH+1];
   1.799 +    myUCharsToChars(buf, currency);
   1.800 +
   1.801 +    const UChar* s = NULL;
   1.802 +    ec2 = U_ZERO_ERROR;
   1.803 +    UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
   1.804 +
   1.805 +    rb = ures_getByKey(rb, CURRENCYPLURALS, rb, &ec2);
   1.806 +
   1.807 +    // Fetch resource with multi-level resource inheritance fallback
   1.808 +    rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
   1.809 +
   1.810 +    s = ures_getStringByKeyWithFallback(rb, pluralCount, len, &ec2);
   1.811 +    if (U_FAILURE(ec2)) {
   1.812 +        //  fall back to "other"
   1.813 +        ec2 = U_ZERO_ERROR;
   1.814 +        s = ures_getStringByKeyWithFallback(rb, "other", len, &ec2);     
   1.815 +        if (U_FAILURE(ec2)) {
   1.816 +            ures_close(rb);
   1.817 +            // fall back to long name in Currencies
   1.818 +            return ucurr_getName(currency, locale, UCURR_LONG_NAME, 
   1.819 +                                 isChoiceFormat, len, ec);
   1.820 +        }
   1.821 +    }
   1.822 +    ures_close(rb);
   1.823 +
   1.824 +    // If we've succeeded we're done.  Otherwise, try to fallback.
   1.825 +    // If that fails (because we are already at root) then exit.
   1.826 +    if (U_SUCCESS(ec2)) {
   1.827 +        if (ec2 == U_USING_DEFAULT_WARNING
   1.828 +            || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
   1.829 +            *ec = ec2;
   1.830 +        }
   1.831 +        U_ASSERT(s != NULL);
   1.832 +        return s;
   1.833 +    }
   1.834 +
   1.835 +    // If we fail to find a match, use the ISO 4217 code
   1.836 +    *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
   1.837 +    *ec = U_USING_DEFAULT_WARNING;
   1.838 +    return currency;
   1.839 +}
   1.840 +
   1.841 +
   1.842 +//========================================================================
   1.843 +// Following are structure and function for parsing currency names
   1.844 +
   1.845 +#define NEED_TO_BE_DELETED 0x1
   1.846 +
   1.847 +// TODO: a better way to define this?
   1.848 +#define MAX_CURRENCY_NAME_LEN 100
   1.849 +
   1.850 +typedef struct {
   1.851 +    const char* IsoCode;  // key
   1.852 +    UChar* currencyName;  // value
   1.853 +    int32_t currencyNameLen;  // value length
   1.854 +    int32_t flag;  // flags
   1.855 +} CurrencyNameStruct;
   1.856 +
   1.857 +
   1.858 +#ifndef MIN
   1.859 +#define MIN(a,b) (((a)<(b)) ? (a) : (b))
   1.860 +#endif
   1.861 +
   1.862 +#ifndef MAX
   1.863 +#define MAX(a,b) (((a)<(b)) ? (b) : (a))
   1.864 +#endif
   1.865 +
   1.866 +
   1.867 +// Comparason function used in quick sort.
   1.868 +static int U_CALLCONV currencyNameComparator(const void* a, const void* b) {
   1.869 +    const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
   1.870 +    const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b;
   1.871 +    for (int32_t i = 0; 
   1.872 +         i < MIN(currName_1->currencyNameLen, currName_2->currencyNameLen);
   1.873 +         ++i) {
   1.874 +        if (currName_1->currencyName[i] < currName_2->currencyName[i]) {
   1.875 +            return -1;
   1.876 +        }
   1.877 +        if (currName_1->currencyName[i] > currName_2->currencyName[i]) {
   1.878 +            return 1;
   1.879 +        }
   1.880 +    }
   1.881 +    if (currName_1->currencyNameLen < currName_2->currencyNameLen) {
   1.882 +        return -1;
   1.883 +    } else if (currName_1->currencyNameLen > currName_2->currencyNameLen) {
   1.884 +        return 1;
   1.885 +    }
   1.886 +    return 0;
   1.887 +}
   1.888 +
   1.889 +
   1.890 +// Give a locale, return the maximum number of currency names associated with
   1.891 +// this locale.
   1.892 +// It gets currency names from resource bundles using fallback.
   1.893 +// It is the maximum number because in the fallback chain, some of the 
   1.894 +// currency names are duplicated.
   1.895 +// For example, given locale as "en_US", the currency names get from resource
   1.896 +// bundle in "en_US" and "en" are duplicated. The fallback mechanism will count
   1.897 +// all currency names in "en_US" and "en".
   1.898 +static void
   1.899 +getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_t* total_currency_symbol_count) {
   1.900 +    U_NAMESPACE_USE
   1.901 +    *total_currency_name_count = 0;
   1.902 +    *total_currency_symbol_count = 0;
   1.903 +    const UChar* s = NULL;
   1.904 +    char locale[ULOC_FULLNAME_CAPACITY];
   1.905 +    uprv_strcpy(locale, loc);
   1.906 +    const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv();
   1.907 +    for (;;) {
   1.908 +        UErrorCode ec2 = U_ZERO_ERROR;
   1.909 +        // TODO: ures_openDirect?
   1.910 +        UResourceBundle* rb = ures_open(U_ICUDATA_CURR, locale, &ec2);
   1.911 +        UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
   1.912 +        int32_t n = ures_getSize(curr);
   1.913 +        for (int32_t i=0; i<n; ++i) {
   1.914 +            UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
   1.915 +            int32_t len;
   1.916 +            s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
   1.917 +            UBool isChoice = FALSE;
   1.918 +            if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
   1.919 +                ++s;
   1.920 +                --len;
   1.921 +                if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
   1.922 +                    isChoice = TRUE;
   1.923 +                }
   1.924 +            }
   1.925 +            if (isChoice) {
   1.926 +                ChoiceFormat fmt(UnicodeString(TRUE, s, len), ec2);
   1.927 +                int32_t fmt_count;
   1.928 +                fmt.getFormats(fmt_count);
   1.929 +                *total_currency_symbol_count += fmt_count;
   1.930 +            } else {
   1.931 +                ++(*total_currency_symbol_count);  // currency symbol
   1.932 +                if (currencySymbolsEquiv != NULL) {
   1.933 +                    *total_currency_symbol_count += countEquivalent(*currencySymbolsEquiv, UnicodeString(TRUE, s, len));
   1.934 +                }
   1.935 +            }
   1.936 +
   1.937 +            ++(*total_currency_symbol_count); // iso code
   1.938 +            ++(*total_currency_name_count); // long name
   1.939 +            ures_close(names);
   1.940 +        }
   1.941 +
   1.942 +        // currency plurals
   1.943 +        UErrorCode ec3 = U_ZERO_ERROR;
   1.944 +        UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
   1.945 +        n = ures_getSize(curr_p);
   1.946 +        for (int32_t i=0; i<n; ++i) {
   1.947 +            UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
   1.948 +            *total_currency_name_count += ures_getSize(names);
   1.949 +            ures_close(names);
   1.950 +        }
   1.951 +        ures_close(curr_p);
   1.952 +        ures_close(curr);
   1.953 +        ures_close(rb);
   1.954 +
   1.955 +        if (!fallback(locale)) {
   1.956 +            break;
   1.957 +        }
   1.958 +    }
   1.959 +}
   1.960 +
   1.961 +static UChar* 
   1.962 +toUpperCase(const UChar* source, int32_t len, const char* locale) {
   1.963 +    UChar* dest = NULL;
   1.964 +    UErrorCode ec = U_ZERO_ERROR;
   1.965 +    int32_t destLen = u_strToUpper(dest, 0, source, len, locale, &ec);
   1.966 +
   1.967 +    ec = U_ZERO_ERROR;
   1.968 +    dest = (UChar*)uprv_malloc(sizeof(UChar) * MAX(destLen, len));
   1.969 +    u_strToUpper(dest, destLen, source, len, locale, &ec);
   1.970 +    if (U_FAILURE(ec)) {
   1.971 +        uprv_memcpy(dest, source, sizeof(UChar) * len);
   1.972 +    } 
   1.973 +    return dest;
   1.974 +}
   1.975 +
   1.976 +
   1.977 +// Collect all available currency names associated with the given locale
   1.978 +// (enable fallback chain).
   1.979 +// Read currenc names defined in resource bundle "Currencies" and
   1.980 +// "CurrencyPlural", enable fallback chain.
   1.981 +// return the malloc-ed currency name arrays and the total number of currency
   1.982 +// names in the array.
   1.983 +static void
   1.984 +collectCurrencyNames(const char* locale, 
   1.985 +                     CurrencyNameStruct** currencyNames, 
   1.986 +                     int32_t* total_currency_name_count, 
   1.987 +                     CurrencyNameStruct** currencySymbols, 
   1.988 +                     int32_t* total_currency_symbol_count, 
   1.989 +                     UErrorCode& ec) {
   1.990 +    U_NAMESPACE_USE
   1.991 +    const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv();
   1.992 +    // Look up the Currencies resource for the given locale.
   1.993 +    UErrorCode ec2 = U_ZERO_ERROR;
   1.994 +
   1.995 +    char loc[ULOC_FULLNAME_CAPACITY];
   1.996 +    uloc_getName(locale, loc, sizeof(loc), &ec2);
   1.997 +    if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
   1.998 +        ec = U_ILLEGAL_ARGUMENT_ERROR;
   1.999 +    }
  1.1000 +
  1.1001 +    // Get maximum currency name count first.
  1.1002 +    getCurrencyNameCount(loc, total_currency_name_count, total_currency_symbol_count);
  1.1003 +
  1.1004 +    *currencyNames = (CurrencyNameStruct*)uprv_malloc
  1.1005 +        (sizeof(CurrencyNameStruct) * (*total_currency_name_count));
  1.1006 +    *currencySymbols = (CurrencyNameStruct*)uprv_malloc
  1.1007 +        (sizeof(CurrencyNameStruct) * (*total_currency_symbol_count));
  1.1008 +
  1.1009 +    const UChar* s = NULL;  // currency name
  1.1010 +    char* iso = NULL;  // currency ISO code
  1.1011 +
  1.1012 +    *total_currency_name_count = 0;
  1.1013 +    *total_currency_symbol_count = 0;
  1.1014 +
  1.1015 +    UErrorCode ec3 = U_ZERO_ERROR;
  1.1016 +    UErrorCode ec4 = U_ZERO_ERROR;
  1.1017 +
  1.1018 +    // Using hash to remove duplicates caused by locale fallback
  1.1019 +    UHashtable* currencyIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec3);
  1.1020 +    UHashtable* currencyPluralIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec4);
  1.1021 +    for (int32_t localeLevel = 0; ; ++localeLevel) {
  1.1022 +        ec2 = U_ZERO_ERROR;
  1.1023 +        // TODO: ures_openDirect
  1.1024 +        UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
  1.1025 +        UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
  1.1026 +        int32_t n = ures_getSize(curr);
  1.1027 +        for (int32_t i=0; i<n; ++i) {
  1.1028 +            UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
  1.1029 +            int32_t len;
  1.1030 +            s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
  1.1031 +            // TODO: uhash_put wont change key/value?
  1.1032 +            iso = (char*)ures_getKey(names);
  1.1033 +            if (localeLevel == 0) {
  1.1034 +                uhash_put(currencyIsoCodes, iso, iso, &ec3); 
  1.1035 +            } else {
  1.1036 +                if (uhash_get(currencyIsoCodes, iso) != NULL) {
  1.1037 +                    ures_close(names);
  1.1038 +                    continue;
  1.1039 +                } else {
  1.1040 +                    uhash_put(currencyIsoCodes, iso, iso, &ec3); 
  1.1041 +                }
  1.1042 +            }
  1.1043 +            UBool isChoice = FALSE;
  1.1044 +            if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
  1.1045 +                ++s;
  1.1046 +                --len;
  1.1047 +                if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
  1.1048 +                    isChoice = TRUE;
  1.1049 +                }
  1.1050 +            }
  1.1051 +            if (isChoice) {
  1.1052 +                ChoiceFormat fmt(UnicodeString(TRUE, s, len), ec2);
  1.1053 +                int32_t fmt_count;
  1.1054 +                const UnicodeString* formats = fmt.getFormats(fmt_count);
  1.1055 +                for (int i = 0; i < fmt_count; ++i) {
  1.1056 +                    // put iso, formats[i]; into array
  1.1057 +                    int32_t length = formats[i].length();
  1.1058 +                    UChar* name = (UChar*)uprv_malloc(sizeof(UChar)*length);
  1.1059 +                    formats[i].extract(0, length, name);
  1.1060 +                    (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
  1.1061 +                    (*currencySymbols)[*total_currency_symbol_count].currencyName = name;
  1.1062 +                    (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
  1.1063 +                    (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = length;
  1.1064 +                }
  1.1065 +            } else {
  1.1066 +                // Add currency symbol.
  1.1067 +                (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
  1.1068 +                (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s;
  1.1069 +                (*currencySymbols)[*total_currency_symbol_count].flag = 0;
  1.1070 +                (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
  1.1071 +                // Add equivalent symbols
  1.1072 +                if (currencySymbolsEquiv != NULL) {
  1.1073 +                    EquivIterator iter(*currencySymbolsEquiv, UnicodeString(TRUE, s, len));
  1.1074 +                    const UnicodeString *symbol;
  1.1075 +                    while ((symbol = iter.next()) != NULL) {
  1.1076 +                        (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
  1.1077 +                        (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*) symbol->getBuffer();
  1.1078 +                        (*currencySymbols)[*total_currency_symbol_count].flag = 0;
  1.1079 +                        (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = symbol->length();
  1.1080 +                    }
  1.1081 +                }
  1.1082 +            }
  1.1083 +
  1.1084 +            // Add currency long name.
  1.1085 +            s = ures_getStringByIndex(names, UCURR_LONG_NAME, &len, &ec2);
  1.1086 +            (*currencyNames)[*total_currency_name_count].IsoCode = iso;
  1.1087 +            UChar* upperName = toUpperCase(s, len, locale);
  1.1088 +            (*currencyNames)[*total_currency_name_count].currencyName = upperName;
  1.1089 +            (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
  1.1090 +            (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
  1.1091 +
  1.1092 +            // put (iso, 3, and iso) in to array
  1.1093 +            // Add currency ISO code.
  1.1094 +            (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
  1.1095 +            (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
  1.1096 +            // Must convert iso[] into Unicode
  1.1097 +            u_charsToUChars(iso, (*currencySymbols)[*total_currency_symbol_count].currencyName, 3);
  1.1098 +            (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
  1.1099 +            (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = 3;
  1.1100 +
  1.1101 +            ures_close(names);
  1.1102 +        }
  1.1103 +
  1.1104 +        // currency plurals
  1.1105 +        UErrorCode ec3 = U_ZERO_ERROR;
  1.1106 +        UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
  1.1107 +        n = ures_getSize(curr_p);
  1.1108 +        for (int32_t i=0; i<n; ++i) {
  1.1109 +            UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
  1.1110 +            iso = (char*)ures_getKey(names);
  1.1111 +            // Using hash to remove duplicated ISO codes in fallback chain.
  1.1112 +            if (localeLevel == 0) {
  1.1113 +                uhash_put(currencyPluralIsoCodes, iso, iso, &ec4); 
  1.1114 +            } else {
  1.1115 +                if (uhash_get(currencyPluralIsoCodes, iso) != NULL) {
  1.1116 +                    ures_close(names);
  1.1117 +                    continue;
  1.1118 +                } else {
  1.1119 +                    uhash_put(currencyPluralIsoCodes, iso, iso, &ec4); 
  1.1120 +                }
  1.1121 +            }
  1.1122 +            int32_t num = ures_getSize(names);
  1.1123 +            int32_t len;
  1.1124 +            for (int32_t j = 0; j < num; ++j) {
  1.1125 +                // TODO: remove duplicates between singular name and 
  1.1126 +                // currency long name?
  1.1127 +                s = ures_getStringByIndex(names, j, &len, &ec3);
  1.1128 +                (*currencyNames)[*total_currency_name_count].IsoCode = iso;
  1.1129 +                UChar* upperName = toUpperCase(s, len, locale);
  1.1130 +                (*currencyNames)[*total_currency_name_count].currencyName = upperName;
  1.1131 +                (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
  1.1132 +                (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
  1.1133 +            }
  1.1134 +            ures_close(names);
  1.1135 +        }
  1.1136 +        ures_close(curr_p);
  1.1137 +        ures_close(curr);
  1.1138 +        ures_close(rb);
  1.1139 +
  1.1140 +        if (!fallback(loc)) {
  1.1141 +            break;
  1.1142 +        }
  1.1143 +    }
  1.1144 +
  1.1145 +    uhash_close(currencyIsoCodes);
  1.1146 +    uhash_close(currencyPluralIsoCodes);
  1.1147 +
  1.1148 +    // quick sort the struct
  1.1149 +    qsort(*currencyNames, *total_currency_name_count, 
  1.1150 +          sizeof(CurrencyNameStruct), currencyNameComparator);
  1.1151 +    qsort(*currencySymbols, *total_currency_symbol_count, 
  1.1152 +          sizeof(CurrencyNameStruct), currencyNameComparator);
  1.1153 +
  1.1154 +#ifdef UCURR_DEBUG
  1.1155 +    printf("currency name count: %d\n", *total_currency_name_count);
  1.1156 +    for (int32_t index = 0; index < *total_currency_name_count; ++index) {
  1.1157 +        printf("index: %d\n", index);
  1.1158 +        printf("iso: %s\n", (*currencyNames)[index].IsoCode);
  1.1159 +        char curNameBuf[1024];
  1.1160 +        memset(curNameBuf, 0, 1024);
  1.1161 +        u_austrncpy(curNameBuf, (*currencyNames)[index].currencyName, (*currencyNames)[index].currencyNameLen);
  1.1162 +        printf("currencyName: %s\n", curNameBuf);
  1.1163 +        printf("len: %d\n", (*currencyNames)[index].currencyNameLen);
  1.1164 +    }
  1.1165 +    printf("currency symbol count: %d\n", *total_currency_symbol_count);
  1.1166 +    for (int32_t index = 0; index < *total_currency_symbol_count; ++index) {
  1.1167 +        printf("index: %d\n", index);
  1.1168 +        printf("iso: %s\n", (*currencySymbols)[index].IsoCode);
  1.1169 +        char curNameBuf[1024];
  1.1170 +        memset(curNameBuf, 0, 1024);
  1.1171 +        u_austrncpy(curNameBuf, (*currencySymbols)[index].currencyName, (*currencySymbols)[index].currencyNameLen);
  1.1172 +        printf("currencySymbol: %s\n", curNameBuf);
  1.1173 +        printf("len: %d\n", (*currencySymbols)[index].currencyNameLen);
  1.1174 +    }
  1.1175 +#endif
  1.1176 +}
  1.1177 +
  1.1178 +// @param  currencyNames: currency names array
  1.1179 +// @param  indexInCurrencyNames: the index of the character in currency names 
  1.1180 +//         array against which the comparison is done
  1.1181 +// @param  key: input text char to compare against
  1.1182 +// @param  begin(IN/OUT): the begin index of matching range in currency names array
  1.1183 +// @param  end(IN/OUT): the end index of matching range in currency names array.
  1.1184 +static int32_t
  1.1185 +binarySearch(const CurrencyNameStruct* currencyNames, 
  1.1186 +             int32_t indexInCurrencyNames,
  1.1187 +             const UChar key,
  1.1188 +             int32_t* begin, int32_t* end) {
  1.1189 +#ifdef UCURR_DEBUG
  1.1190 +    printf("key = %x\n", key);
  1.1191 +#endif
  1.1192 +   int32_t first = *begin;
  1.1193 +   int32_t last = *end;
  1.1194 +   while (first <= last) {
  1.1195 +       int32_t mid = (first + last) / 2;  // compute mid point.
  1.1196 +       if (indexInCurrencyNames >= currencyNames[mid].currencyNameLen) {
  1.1197 +           first = mid + 1;
  1.1198 +       } else {
  1.1199 +           if (key > currencyNames[mid].currencyName[indexInCurrencyNames]) {
  1.1200 +               first = mid + 1;
  1.1201 +           }
  1.1202 +           else if (key < currencyNames[mid].currencyName[indexInCurrencyNames]) {
  1.1203 +               last = mid - 1;
  1.1204 +           }
  1.1205 +           else {
  1.1206 +                // Find a match, and looking for ranges
  1.1207 +                // Now do two more binary searches. First, on the left side for
  1.1208 +                // the greatest L such that CurrencyNameStruct[L] < key.
  1.1209 +                int32_t L = *begin;
  1.1210 +                int32_t R = mid;
  1.1211 +
  1.1212 +#ifdef UCURR_DEBUG
  1.1213 +                printf("mid = %d\n", mid);
  1.1214 +#endif
  1.1215 +                while (L < R) {
  1.1216 +                    int32_t M = (L + R) / 2;
  1.1217 +#ifdef UCURR_DEBUG
  1.1218 +                    printf("L = %d, R = %d, M = %d\n", L, R, M);
  1.1219 +#endif
  1.1220 +                    if (indexInCurrencyNames >= currencyNames[M].currencyNameLen) {
  1.1221 +                        L = M + 1;
  1.1222 +                    } else {
  1.1223 +                        if (currencyNames[M].currencyName[indexInCurrencyNames] < key) {
  1.1224 +                            L = M + 1;
  1.1225 +                        } else {
  1.1226 +#ifdef UCURR_DEBUG
  1.1227 +                            U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
  1.1228 +#endif
  1.1229 +                            R = M;
  1.1230 +                        }
  1.1231 +                    }
  1.1232 +                }
  1.1233 +#ifdef UCURR_DEBUG
  1.1234 +                U_ASSERT(L == R);
  1.1235 +#endif
  1.1236 +                *begin = L;
  1.1237 +#ifdef UCURR_DEBUG
  1.1238 +                printf("begin = %d\n", *begin);
  1.1239 +                U_ASSERT(currencyNames[*begin].currencyName[indexInCurrencyNames] == key);
  1.1240 +#endif
  1.1241 +
  1.1242 +                // Now for the second search, finding the least R such that
  1.1243 +                // key < CurrencyNameStruct[R].
  1.1244 +                L = mid;
  1.1245 +                R = *end;
  1.1246 +                while (L < R) {
  1.1247 +                    int32_t M = (L + R) / 2;
  1.1248 +#ifdef UCURR_DEBUG
  1.1249 +                    printf("L = %d, R = %d, M = %d\n", L, R, M);
  1.1250 +#endif
  1.1251 +                    if (currencyNames[M].currencyNameLen < indexInCurrencyNames) {
  1.1252 +                        L = M + 1;
  1.1253 +                    } else {
  1.1254 +                        if (currencyNames[M].currencyName[indexInCurrencyNames] > key) {
  1.1255 +                            R = M;
  1.1256 +                        } else {
  1.1257 +#ifdef UCURR_DEBUG
  1.1258 +                            U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
  1.1259 +#endif
  1.1260 +                            L = M + 1;
  1.1261 +                        }
  1.1262 +                    }
  1.1263 +                }
  1.1264 +#ifdef UCURR_DEBUG
  1.1265 +                U_ASSERT(L == R);
  1.1266 +#endif
  1.1267 +                if (currencyNames[R].currencyName[indexInCurrencyNames] > key) {
  1.1268 +                    *end = R - 1;
  1.1269 +                } else {
  1.1270 +                    *end = R;
  1.1271 +                }
  1.1272 +#ifdef UCURR_DEBUG
  1.1273 +                printf("end = %d\n", *end);
  1.1274 +#endif
  1.1275 +
  1.1276 +                // now, found the range. check whether there is exact match
  1.1277 +                if (currencyNames[*begin].currencyNameLen == indexInCurrencyNames + 1) {
  1.1278 +                    return *begin;  // find range and exact match.
  1.1279 +                }
  1.1280 +                return -1;  // find range, but no exact match.
  1.1281 +           }
  1.1282 +       }
  1.1283 +   }
  1.1284 +   *begin = -1;
  1.1285 +   *end = -1;
  1.1286 +   return -1;    // failed to find range.
  1.1287 +}
  1.1288 +
  1.1289 +
  1.1290 +// Linear search "text" in "currencyNames".
  1.1291 +// @param  begin, end: the begin and end index in currencyNames, within which
  1.1292 +//         range should the search be performed.
  1.1293 +// @param  textLen: the length of the text to be compared
  1.1294 +// @param  maxMatchLen(IN/OUT): passing in the computed max matching length
  1.1295 +//                              pass out the new max  matching length
  1.1296 +// @param  maxMatchIndex: the index in currencyName which has the longest
  1.1297 +//                        match with input text.
  1.1298 +static void
  1.1299 +linearSearch(const CurrencyNameStruct* currencyNames, 
  1.1300 +             int32_t begin, int32_t end,
  1.1301 +             const UChar* text, int32_t textLen,
  1.1302 +             int32_t *maxMatchLen, int32_t* maxMatchIndex) {
  1.1303 +    for (int32_t index = begin; index <= end; ++index) {
  1.1304 +        int32_t len = currencyNames[index].currencyNameLen;
  1.1305 +        if (len > *maxMatchLen && len <= textLen &&
  1.1306 +            uprv_memcmp(currencyNames[index].currencyName, text, len * sizeof(UChar)) == 0) {
  1.1307 +            *maxMatchIndex = index;
  1.1308 +            *maxMatchLen = len;
  1.1309 +#ifdef UCURR_DEBUG
  1.1310 +            printf("maxMatchIndex = %d, maxMatchLen = %d\n",
  1.1311 +                   *maxMatchIndex, *maxMatchLen);
  1.1312 +#endif
  1.1313 +        }
  1.1314 +    }
  1.1315 +}
  1.1316 +
  1.1317 +#define LINEAR_SEARCH_THRESHOLD 10
  1.1318 +
  1.1319 +// Find longest match between "text" and currency names in "currencyNames".
  1.1320 +// @param  total_currency_count: total number of currency names in CurrencyNames.
  1.1321 +// @param  textLen: the length of the text to be compared
  1.1322 +// @param  maxMatchLen: passing in the computed max matching length
  1.1323 +//                              pass out the new max  matching length
  1.1324 +// @param  maxMatchIndex: the index in currencyName which has the longest
  1.1325 +//                        match with input text.
  1.1326 +static void
  1.1327 +searchCurrencyName(const CurrencyNameStruct* currencyNames, 
  1.1328 +                   int32_t total_currency_count,
  1.1329 +                   const UChar* text, int32_t textLen, 
  1.1330 +                   int32_t* maxMatchLen, int32_t* maxMatchIndex) {
  1.1331 +    *maxMatchIndex = -1;
  1.1332 +    *maxMatchLen = 0;
  1.1333 +    int32_t matchIndex = -1;
  1.1334 +    int32_t binarySearchBegin = 0;
  1.1335 +    int32_t binarySearchEnd = total_currency_count - 1;
  1.1336 +    // It is a variant of binary search.
  1.1337 +    // For example, given the currency names in currencyNames array are:
  1.1338 +    // A AB ABC AD AZ B BB BBEX BBEXYZ BS C D E....
  1.1339 +    // and the input text is BBEXST
  1.1340 +    // The first round binary search search "B" in the text against
  1.1341 +    // the first char in currency names, and find the first char matching range
  1.1342 +    // to be "B BB BBEX BBEXYZ BS" (and the maximum matching "B").
  1.1343 +    // The 2nd round binary search search the second "B" in the text against
  1.1344 +    // the 2nd char in currency names, and narrow the matching range to
  1.1345 +    // "BB BBEX BBEXYZ" (and the maximum matching "BB").
  1.1346 +    // The 3rd round returnes the range as "BBEX BBEXYZ" (without changing
  1.1347 +    // maximum matching).
  1.1348 +    // The 4th round returns the same range (the maximum matching is "BBEX").
  1.1349 +    // The 5th round returns no matching range.
  1.1350 +    for (int32_t index = 0; index < textLen; ++index) {
  1.1351 +        // matchIndex saves the one with exact match till the current point.
  1.1352 +        // [binarySearchBegin, binarySearchEnd] saves the matching range.
  1.1353 +        matchIndex = binarySearch(currencyNames, index,
  1.1354 +                                  text[index],
  1.1355 +                                  &binarySearchBegin, &binarySearchEnd);
  1.1356 +        if (binarySearchBegin == -1) { // did not find the range
  1.1357 +            break;
  1.1358 +        }
  1.1359 +        if (matchIndex != -1) { 
  1.1360 +            // find an exact match for text from text[0] to text[index] 
  1.1361 +            // in currencyNames array.
  1.1362 +            *maxMatchLen = index + 1;
  1.1363 +            *maxMatchIndex = matchIndex;
  1.1364 +        }
  1.1365 +        if (binarySearchEnd - binarySearchBegin < LINEAR_SEARCH_THRESHOLD) {
  1.1366 +            // linear search if within threshold.
  1.1367 +            linearSearch(currencyNames, binarySearchBegin, binarySearchEnd,
  1.1368 +                         text, textLen,
  1.1369 +                         maxMatchLen, maxMatchIndex);
  1.1370 +            break;
  1.1371 +        }
  1.1372 +    }
  1.1373 +    return;
  1.1374 +}
  1.1375 +
  1.1376 +//========================= currency name cache =====================
  1.1377 +typedef struct {
  1.1378 +    char locale[ULOC_FULLNAME_CAPACITY];  //key
  1.1379 +    // currency names, case insensitive
  1.1380 +    CurrencyNameStruct* currencyNames;  // value
  1.1381 +    int32_t totalCurrencyNameCount;  // currency name count
  1.1382 +    // currency symbols and ISO code, case sensitive
  1.1383 +    CurrencyNameStruct* currencySymbols; // value
  1.1384 +    int32_t totalCurrencySymbolCount;  // count
  1.1385 +    // reference count.
  1.1386 +    // reference count is set to 1 when an entry is put to cache.
  1.1387 +    // it increases by 1 before accessing, and decreased by 1 after accessing.
  1.1388 +    // The entry is deleted when ref count is zero, which means 
  1.1389 +    // the entry is replaced out of cache and no process is accessing it.
  1.1390 +    int32_t refCount;
  1.1391 +} CurrencyNameCacheEntry;
  1.1392 +
  1.1393 +
  1.1394 +#define CURRENCY_NAME_CACHE_NUM 10
  1.1395 +
  1.1396 +// Reserve 10 cache entries.
  1.1397 +static CurrencyNameCacheEntry* currCache[CURRENCY_NAME_CACHE_NUM] = {NULL};
  1.1398 +// Using an index to indicate which entry to be replaced when cache is full.
  1.1399 +// It is a simple round-robin replacement strategy.
  1.1400 +static int8_t currentCacheEntryIndex = 0;
  1.1401 +
  1.1402 +static UMutex gCurrencyCacheMutex = U_MUTEX_INITIALIZER;
  1.1403 +
  1.1404 +// Cache deletion
  1.1405 +static void
  1.1406 +deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
  1.1407 +    for (int32_t index = 0; index < count; ++index) {
  1.1408 +        if ( (currencyNames[index].flag & NEED_TO_BE_DELETED) ) {
  1.1409 +            uprv_free(currencyNames[index].currencyName);
  1.1410 +        }
  1.1411 +    }
  1.1412 +    uprv_free(currencyNames);
  1.1413 +}
  1.1414 +
  1.1415 +
  1.1416 +static void
  1.1417 +deleteCacheEntry(CurrencyNameCacheEntry* entry) {
  1.1418 +    deleteCurrencyNames(entry->currencyNames, entry->totalCurrencyNameCount);
  1.1419 +    deleteCurrencyNames(entry->currencySymbols, entry->totalCurrencySymbolCount);
  1.1420 +    uprv_free(entry);
  1.1421 +}
  1.1422 +
  1.1423 +
  1.1424 +// Cache clean up
  1.1425 +static UBool U_CALLCONV
  1.1426 +currency_cache_cleanup(void) {
  1.1427 +    for (int32_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
  1.1428 +        if (currCache[i]) {
  1.1429 +            deleteCacheEntry(currCache[i]);
  1.1430 +            currCache[i] = 0;
  1.1431 +        }
  1.1432 +    }
  1.1433 +    return TRUE;
  1.1434 +}
  1.1435 +
  1.1436 +
  1.1437 +U_CFUNC void
  1.1438 +uprv_parseCurrency(const char* locale,
  1.1439 +                   const icu::UnicodeString& text,
  1.1440 +                   icu::ParsePosition& pos,
  1.1441 +                   int8_t type,
  1.1442 +                   UChar* result,
  1.1443 +                   UErrorCode& ec)
  1.1444 +{
  1.1445 +    U_NAMESPACE_USE
  1.1446 +
  1.1447 +    if (U_FAILURE(ec)) {
  1.1448 +        return;
  1.1449 +    }
  1.1450 +
  1.1451 +    int32_t total_currency_name_count = 0;
  1.1452 +    CurrencyNameStruct* currencyNames = NULL;
  1.1453 +    int32_t total_currency_symbol_count = 0;
  1.1454 +    CurrencyNameStruct* currencySymbols = NULL;
  1.1455 +    CurrencyNameCacheEntry* cacheEntry = NULL;
  1.1456 +
  1.1457 +    umtx_lock(&gCurrencyCacheMutex);
  1.1458 +    // in order to handle racing correctly,
  1.1459 +    // not putting 'search' in a separate function.
  1.1460 +    int8_t  found = -1;
  1.1461 +    for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
  1.1462 +        if (currCache[i]!= NULL &&
  1.1463 +            uprv_strcmp(locale, currCache[i]->locale) == 0) {
  1.1464 +            found = i;
  1.1465 +            break;
  1.1466 +        }
  1.1467 +    }
  1.1468 +    if (found != -1) {
  1.1469 +        cacheEntry = currCache[found];
  1.1470 +        currencyNames = cacheEntry->currencyNames;
  1.1471 +        total_currency_name_count = cacheEntry->totalCurrencyNameCount;
  1.1472 +        currencySymbols = cacheEntry->currencySymbols;
  1.1473 +        total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
  1.1474 +        ++(cacheEntry->refCount);
  1.1475 +    }
  1.1476 +    umtx_unlock(&gCurrencyCacheMutex);
  1.1477 +    if (found == -1) {
  1.1478 +        collectCurrencyNames(locale, &currencyNames, &total_currency_name_count, &currencySymbols, &total_currency_symbol_count, ec);
  1.1479 +        if (U_FAILURE(ec)) {
  1.1480 +            return;
  1.1481 +        }
  1.1482 +        umtx_lock(&gCurrencyCacheMutex);
  1.1483 +        // check again.
  1.1484 +        int8_t  found = -1;
  1.1485 +        for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
  1.1486 +            if (currCache[i]!= NULL &&
  1.1487 +                uprv_strcmp(locale, currCache[i]->locale) == 0) {
  1.1488 +                found = i;
  1.1489 +                break;
  1.1490 +            }
  1.1491 +        }
  1.1492 +        if (found == -1) {
  1.1493 +            // insert new entry to 
  1.1494 +            // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
  1.1495 +            // and remove the existing entry 
  1.1496 +            // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
  1.1497 +            // from cache.
  1.1498 +            cacheEntry = currCache[currentCacheEntryIndex];
  1.1499 +            if (cacheEntry) {
  1.1500 +                --(cacheEntry->refCount);
  1.1501 +                // delete if the ref count is zero
  1.1502 +                if (cacheEntry->refCount == 0) {
  1.1503 +                    deleteCacheEntry(cacheEntry);
  1.1504 +                }
  1.1505 +            }
  1.1506 +            cacheEntry = (CurrencyNameCacheEntry*)uprv_malloc(sizeof(CurrencyNameCacheEntry));
  1.1507 +            currCache[currentCacheEntryIndex] = cacheEntry;
  1.1508 +            uprv_strcpy(cacheEntry->locale, locale);
  1.1509 +            cacheEntry->currencyNames = currencyNames;
  1.1510 +            cacheEntry->totalCurrencyNameCount = total_currency_name_count;
  1.1511 +            cacheEntry->currencySymbols = currencySymbols;
  1.1512 +            cacheEntry->totalCurrencySymbolCount = total_currency_symbol_count;
  1.1513 +            cacheEntry->refCount = 2; // one for cache, one for reference
  1.1514 +            currentCacheEntryIndex = (currentCacheEntryIndex + 1) % CURRENCY_NAME_CACHE_NUM;
  1.1515 +            ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cache_cleanup);
  1.1516 +            
  1.1517 +        } else {
  1.1518 +            deleteCurrencyNames(currencyNames, total_currency_name_count);
  1.1519 +            deleteCurrencyNames(currencySymbols, total_currency_symbol_count);
  1.1520 +            cacheEntry = currCache[found];
  1.1521 +            currencyNames = cacheEntry->currencyNames;
  1.1522 +            total_currency_name_count = cacheEntry->totalCurrencyNameCount;
  1.1523 +            currencySymbols = cacheEntry->currencySymbols;
  1.1524 +            total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
  1.1525 +            ++(cacheEntry->refCount);
  1.1526 +        }
  1.1527 +        umtx_unlock(&gCurrencyCacheMutex);
  1.1528 +    }
  1.1529 +
  1.1530 +    int32_t start = pos.getIndex();
  1.1531 +
  1.1532 +    UChar inputText[MAX_CURRENCY_NAME_LEN];  
  1.1533 +    UChar upperText[MAX_CURRENCY_NAME_LEN];  
  1.1534 +    int32_t textLen = MIN(MAX_CURRENCY_NAME_LEN, text.length() - start);
  1.1535 +    text.extract(start, textLen, inputText);
  1.1536 +    UErrorCode ec1 = U_ZERO_ERROR;
  1.1537 +    textLen = u_strToUpper(upperText, MAX_CURRENCY_NAME_LEN, inputText, textLen, locale, &ec1);
  1.1538 +
  1.1539 +    int32_t max = 0;
  1.1540 +    int32_t matchIndex = -1;
  1.1541 +    // case in-sensitive comparision against currency names
  1.1542 +    searchCurrencyName(currencyNames, total_currency_name_count, 
  1.1543 +                       upperText, textLen, &max, &matchIndex);
  1.1544 +
  1.1545 +#ifdef UCURR_DEBUG
  1.1546 +    printf("search in names, max = %d, matchIndex = %d\n", max, matchIndex);
  1.1547 +#endif
  1.1548 +
  1.1549 +    int32_t maxInSymbol = 0;
  1.1550 +    int32_t matchIndexInSymbol = -1;
  1.1551 +    if (type != UCURR_LONG_NAME) {  // not name only
  1.1552 +        // case sensitive comparison against currency symbols and ISO code.
  1.1553 +        searchCurrencyName(currencySymbols, total_currency_symbol_count, 
  1.1554 +                           inputText, textLen, 
  1.1555 +                           &maxInSymbol, &matchIndexInSymbol);
  1.1556 +    }
  1.1557 +
  1.1558 +#ifdef UCURR_DEBUG
  1.1559 +    printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol);
  1.1560 +    if(matchIndexInSymbol != -1) {
  1.1561 +      printf("== ISO=%s\n", currencySymbols[matchIndexInSymbol].IsoCode);
  1.1562 +    }
  1.1563 +#endif
  1.1564 +
  1.1565 +    if (max >= maxInSymbol && matchIndex != -1) {
  1.1566 +        u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4);
  1.1567 +        pos.setIndex(start + max);
  1.1568 +    } else if (maxInSymbol >= max && matchIndexInSymbol != -1) {
  1.1569 +        u_charsToUChars(currencySymbols[matchIndexInSymbol].IsoCode, result, 4);
  1.1570 +        pos.setIndex(start + maxInSymbol);
  1.1571 +    } 
  1.1572 +
  1.1573 +    // decrease reference count
  1.1574 +    umtx_lock(&gCurrencyCacheMutex);
  1.1575 +    --(cacheEntry->refCount);
  1.1576 +    if (cacheEntry->refCount == 0) {  // remove 
  1.1577 +        deleteCacheEntry(cacheEntry);
  1.1578 +    }
  1.1579 +    umtx_unlock(&gCurrencyCacheMutex);
  1.1580 +}
  1.1581 +
  1.1582 +
  1.1583 +/**
  1.1584 + * Internal method.  Given a currency ISO code and a locale, return
  1.1585 + * the "static" currency name.  This is usually the same as the
  1.1586 + * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
  1.1587 + * format is applied to the number 2.0 (to yield the more common
  1.1588 + * plural) to return a static name.
  1.1589 + *
  1.1590 + * This is used for backward compatibility with old currency logic in
  1.1591 + * DecimalFormat and DecimalFormatSymbols.
  1.1592 + */
  1.1593 +U_CFUNC void
  1.1594 +uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
  1.1595 +                           icu::UnicodeString& result, UErrorCode& ec)
  1.1596 +{
  1.1597 +    U_NAMESPACE_USE
  1.1598 +
  1.1599 +    UBool isChoiceFormat;
  1.1600 +    int32_t len;
  1.1601 +    const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME,
  1.1602 +                                          &isChoiceFormat, &len, &ec);
  1.1603 +    if (U_SUCCESS(ec)) {
  1.1604 +        // If this is a ChoiceFormat currency, then format an
  1.1605 +        // arbitrary value; pick something != 1; more common.
  1.1606 +        result.truncate(0);
  1.1607 +        if (isChoiceFormat) {
  1.1608 +            ChoiceFormat f(UnicodeString(TRUE, currname, len), ec);
  1.1609 +            if (U_SUCCESS(ec)) {
  1.1610 +                f.format(2.0, result);
  1.1611 +            } else {
  1.1612 +                result.setTo(iso, -1);
  1.1613 +            }
  1.1614 +        } else {
  1.1615 +            result.setTo(currname, -1);
  1.1616 +        }
  1.1617 +    }
  1.1618 +}
  1.1619 +
  1.1620 +U_CAPI int32_t U_EXPORT2
  1.1621 +ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) {
  1.1622 +    return (_findMetaData(currency, *ec))[0];
  1.1623 +}
  1.1624 +
  1.1625 +U_CAPI double U_EXPORT2
  1.1626 +ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) {
  1.1627 +    const int32_t *data = _findMetaData(currency, *ec);
  1.1628 +
  1.1629 +    // If the meta data is invalid, return 0.0.
  1.1630 +    if (data[0] < 0 || data[0] > MAX_POW10) {
  1.1631 +        if (U_SUCCESS(*ec)) {
  1.1632 +            *ec = U_INVALID_FORMAT_ERROR;
  1.1633 +        }
  1.1634 +        return 0.0;
  1.1635 +    }
  1.1636 +
  1.1637 +    // If there is no rounding, return 0.0 to indicate no rounding.  A
  1.1638 +    // rounding value (data[1]) of 0 or 1 indicates no rounding.
  1.1639 +    if (data[1] < 2) {
  1.1640 +        return 0.0;
  1.1641 +    }
  1.1642 +
  1.1643 +    // Return data[1] / 10^(data[0]).  The only actual rounding data,
  1.1644 +    // as of this writing, is CHF { 2, 5 }.
  1.1645 +    return double(data[1]) / POW10[data[0]];
  1.1646 +}
  1.1647 +
  1.1648 +U_CDECL_BEGIN
  1.1649 +
  1.1650 +typedef struct UCurrencyContext {
  1.1651 +    uint32_t currType; /* UCurrCurrencyType */
  1.1652 +    uint32_t listIdx;
  1.1653 +} UCurrencyContext;
  1.1654 +
  1.1655 +/*
  1.1656 +Please keep this list in alphabetical order.
  1.1657 +You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
  1.1658 +of these items.
  1.1659 +ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
  1.1660 +*/
  1.1661 +static const struct CurrencyList {
  1.1662 +    const char *currency;
  1.1663 +    uint32_t currType;
  1.1664 +} gCurrencyList[] = {
  1.1665 +    {"ADP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1666 +    {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1667 +    {"AFA", UCURR_COMMON|UCURR_DEPRECATED},
  1.1668 +    {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1669 +    {"ALK", UCURR_COMMON|UCURR_DEPRECATED},
  1.1670 +    {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1671 +    {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1672 +    {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1673 +    {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1674 +    {"AOK", UCURR_COMMON|UCURR_DEPRECATED},
  1.1675 +    {"AON", UCURR_COMMON|UCURR_DEPRECATED},
  1.1676 +    {"AOR", UCURR_COMMON|UCURR_DEPRECATED},
  1.1677 +    {"ARA", UCURR_COMMON|UCURR_DEPRECATED},
  1.1678 +    {"ARL", UCURR_COMMON|UCURR_DEPRECATED},
  1.1679 +    {"ARM", UCURR_COMMON|UCURR_DEPRECATED},
  1.1680 +    {"ARP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1681 +    {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1682 +    {"ATS", UCURR_COMMON|UCURR_DEPRECATED},
  1.1683 +    {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1684 +    {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1685 +    {"AZM", UCURR_COMMON|UCURR_DEPRECATED},
  1.1686 +    {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1687 +    {"BAD", UCURR_COMMON|UCURR_DEPRECATED},
  1.1688 +    {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1689 +    {"BAN", UCURR_COMMON|UCURR_DEPRECATED},
  1.1690 +    {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1691 +    {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1692 +    {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED},
  1.1693 +    {"BEF", UCURR_COMMON|UCURR_DEPRECATED},
  1.1694 +    {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED},
  1.1695 +    {"BGL", UCURR_COMMON|UCURR_DEPRECATED},
  1.1696 +    {"BGM", UCURR_COMMON|UCURR_DEPRECATED},
  1.1697 +    {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1698 +    {"BGO", UCURR_COMMON|UCURR_DEPRECATED},
  1.1699 +    {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1700 +    {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1701 +    {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1702 +    {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1703 +    {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1704 +    {"BOL", UCURR_COMMON|UCURR_DEPRECATED},
  1.1705 +    {"BOP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1706 +    {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1707 +    {"BRB", UCURR_COMMON|UCURR_DEPRECATED},
  1.1708 +    {"BRC", UCURR_COMMON|UCURR_DEPRECATED},
  1.1709 +    {"BRE", UCURR_COMMON|UCURR_DEPRECATED},
  1.1710 +    {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1711 +    {"BRN", UCURR_COMMON|UCURR_DEPRECATED},
  1.1712 +    {"BRR", UCURR_COMMON|UCURR_DEPRECATED},
  1.1713 +    {"BRZ", UCURR_COMMON|UCURR_DEPRECATED},
  1.1714 +    {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1715 +    {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1716 +    {"BUK", UCURR_COMMON|UCURR_DEPRECATED},
  1.1717 +    {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1718 +    {"BYB", UCURR_COMMON|UCURR_DEPRECATED},
  1.1719 +    {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1720 +    {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1721 +    {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1722 +    {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1723 +    {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1724 +    {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1725 +    {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1726 +    {"CLE", UCURR_COMMON|UCURR_DEPRECATED},
  1.1727 +    {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1728 +    {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1729 +    {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED},
  1.1730 +    {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1731 +    {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1732 +    {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1733 +    {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1734 +    {"CSD", UCURR_COMMON|UCURR_DEPRECATED},
  1.1735 +    {"CSK", UCURR_COMMON|UCURR_DEPRECATED},
  1.1736 +    {"CUC", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1737 +    {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1738 +    {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1739 +    {"CYP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1740 +    {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1741 +    {"DDM", UCURR_COMMON|UCURR_DEPRECATED},
  1.1742 +    {"DEM", UCURR_COMMON|UCURR_DEPRECATED},
  1.1743 +    {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1744 +    {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1745 +    {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1746 +    {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1747 +    {"ECS", UCURR_COMMON|UCURR_DEPRECATED},
  1.1748 +    {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED},
  1.1749 +    {"EEK", UCURR_COMMON|UCURR_DEPRECATED},
  1.1750 +    {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1751 +    {"EQE", UCURR_COMMON|UCURR_DEPRECATED},
  1.1752 +    {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1753 +    {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
  1.1754 +    {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
  1.1755 +    {"ESP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1756 +    {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1757 +    {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1758 +    {"FIM", UCURR_COMMON|UCURR_DEPRECATED},
  1.1759 +    {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1760 +    {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1761 +    {"FRF", UCURR_COMMON|UCURR_DEPRECATED},
  1.1762 +    {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1763 +    {"GEK", UCURR_COMMON|UCURR_DEPRECATED},
  1.1764 +    {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1765 +    {"GHC", UCURR_COMMON|UCURR_DEPRECATED},
  1.1766 +    {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1767 +    {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1768 +    {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1769 +    {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1770 +    {"GNS", UCURR_COMMON|UCURR_DEPRECATED},
  1.1771 +    {"GQE", UCURR_COMMON|UCURR_DEPRECATED},
  1.1772 +    {"GRD", UCURR_COMMON|UCURR_DEPRECATED},
  1.1773 +    {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1774 +    {"GWE", UCURR_COMMON|UCURR_DEPRECATED},
  1.1775 +    {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1776 +    {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1777 +    {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1778 +    {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1779 +    {"HRD", UCURR_COMMON|UCURR_DEPRECATED},
  1.1780 +    {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1781 +    {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1782 +    {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1783 +    {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1784 +    {"IEP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1785 +    {"ILP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1786 +    {"ILR", UCURR_COMMON|UCURR_DEPRECATED},
  1.1787 +    {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1788 +    {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1789 +    {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1790 +    {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1791 +    {"ISJ", UCURR_COMMON|UCURR_DEPRECATED},
  1.1792 +    {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1793 +    {"ITL", UCURR_COMMON|UCURR_DEPRECATED},
  1.1794 +    {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1795 +    {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1796 +    {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1797 +    {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1798 +    {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1799 +    {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1800 +    {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1801 +    {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1802 +    {"KRH", UCURR_COMMON|UCURR_DEPRECATED},
  1.1803 +    {"KRO", UCURR_COMMON|UCURR_DEPRECATED},
  1.1804 +    {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1805 +    {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1806 +    {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1807 +    {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1808 +    {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1809 +    {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1810 +    {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1811 +    {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1812 +    {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1813 +    {"LSM", UCURR_COMMON|UCURR_DEPRECATED},
  1.1814 +    {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1815 +    {"LTT", UCURR_COMMON|UCURR_DEPRECATED},
  1.1816 +    {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED},
  1.1817 +    {"LUF", UCURR_COMMON|UCURR_DEPRECATED},
  1.1818 +    {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED},
  1.1819 +    {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1820 +    {"LVR", UCURR_COMMON|UCURR_DEPRECATED},
  1.1821 +    {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1822 +    {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1823 +    {"MAF", UCURR_COMMON|UCURR_DEPRECATED},
  1.1824 +    {"MCF", UCURR_COMMON|UCURR_DEPRECATED},
  1.1825 +    {"MDC", UCURR_COMMON|UCURR_DEPRECATED},
  1.1826 +    {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1827 +    {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1828 +    {"MGF", UCURR_COMMON|UCURR_DEPRECATED},
  1.1829 +    {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1830 +    {"MKN", UCURR_COMMON|UCURR_DEPRECATED},
  1.1831 +    {"MLF", UCURR_COMMON|UCURR_DEPRECATED},
  1.1832 +    {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1833 +    {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1834 +    {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1835 +    {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1836 +    {"MTL", UCURR_COMMON|UCURR_DEPRECATED},
  1.1837 +    {"MTP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1838 +    {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1839 +    {"MVP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1840 +    {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1841 +    {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1842 +    {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1843 +    {"MXP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1844 +    {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1845 +    {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1846 +    {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1847 +    {"MZM", UCURR_COMMON|UCURR_DEPRECATED},
  1.1848 +    {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1849 +    {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1850 +    {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1851 +    {"NIC", UCURR_COMMON|UCURR_DEPRECATED},
  1.1852 +    {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1853 +    {"NLG", UCURR_COMMON|UCURR_DEPRECATED},
  1.1854 +    {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1855 +    {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1856 +    {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1857 +    {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1858 +    {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1859 +    {"PEI", UCURR_COMMON|UCURR_DEPRECATED},
  1.1860 +    {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1861 +    {"PES", UCURR_COMMON|UCURR_DEPRECATED},
  1.1862 +    {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1863 +    {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1864 +    {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1865 +    {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1866 +    {"PLZ", UCURR_COMMON|UCURR_DEPRECATED},
  1.1867 +    {"PTE", UCURR_COMMON|UCURR_DEPRECATED},
  1.1868 +    {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1869 +    {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1870 +    {"RHD", UCURR_COMMON|UCURR_DEPRECATED},
  1.1871 +    {"ROL", UCURR_COMMON|UCURR_DEPRECATED},
  1.1872 +    {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1873 +    {"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1874 +    {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1875 +    {"RUR", UCURR_COMMON|UCURR_DEPRECATED},
  1.1876 +    {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1877 +    {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1878 +    {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1879 +    {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1880 +    {"SDD", UCURR_COMMON|UCURR_DEPRECATED},
  1.1881 +    {"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1882 +    {"SDP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1883 +    {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1884 +    {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1885 +    {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1886 +    {"SIT", UCURR_COMMON|UCURR_DEPRECATED},
  1.1887 +    {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1888 +    {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1889 +    {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1890 +    {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1891 +    {"SRG", UCURR_COMMON|UCURR_DEPRECATED},
  1.1892 +    {"SSP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1893 +    {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1894 +    {"SUR", UCURR_COMMON|UCURR_DEPRECATED},
  1.1895 +    {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1896 +    {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1897 +    {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1898 +    {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1899 +    {"TJR", UCURR_COMMON|UCURR_DEPRECATED},
  1.1900 +    {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1901 +    {"TMM", UCURR_COMMON|UCURR_DEPRECATED},
  1.1902 +    {"TMT", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1903 +    {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1904 +    {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1905 +    {"TPE", UCURR_COMMON|UCURR_DEPRECATED},
  1.1906 +    {"TRL", UCURR_COMMON|UCURR_DEPRECATED},
  1.1907 +    {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1908 +    {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1909 +    {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1910 +    {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1911 +    {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1912 +    {"UAK", UCURR_COMMON|UCURR_DEPRECATED},
  1.1913 +    {"UGS", UCURR_COMMON|UCURR_DEPRECATED},
  1.1914 +    {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1915 +    {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1916 +    {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1917 +    {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1918 +    {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1919 +    {"UYP", UCURR_COMMON|UCURR_DEPRECATED},
  1.1920 +    {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1921 +    {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1922 +    {"VEB", UCURR_COMMON|UCURR_DEPRECATED},
  1.1923 +    {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1924 +    {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1925 +    {"VNN", UCURR_COMMON|UCURR_DEPRECATED},
  1.1926 +    {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1927 +    {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1928 +    {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1929 +    {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1930 +    {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1931 +    {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1932 +    {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1933 +    {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1934 +    {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1935 +    {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1936 +    {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1937 +    {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
  1.1938 +    {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1939 +    {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1940 +    {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1941 +    {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1942 +    {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1943 +    {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1944 +    {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1945 +    {"XSU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1946 +    {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1947 +    {"XUA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1948 +    {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1949 +    {"YDD", UCURR_COMMON|UCURR_DEPRECATED},
  1.1950 +    {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1951 +    {"YUD", UCURR_COMMON|UCURR_DEPRECATED},
  1.1952 +    {"YUM", UCURR_COMMON|UCURR_DEPRECATED},
  1.1953 +    {"YUN", UCURR_COMMON|UCURR_DEPRECATED},
  1.1954 +    {"YUR", UCURR_COMMON|UCURR_DEPRECATED},
  1.1955 +    {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
  1.1956 +    {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1957 +    {"ZMK", UCURR_COMMON|UCURR_DEPRECATED},
  1.1958 +    {"ZMW", UCURR_COMMON|UCURR_NON_DEPRECATED},
  1.1959 +    {"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
  1.1960 +    {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
  1.1961 +    {"ZWL", UCURR_COMMON|UCURR_DEPRECATED},
  1.1962 +    {"ZWR", UCURR_COMMON|UCURR_DEPRECATED},
  1.1963 +    {"ZWD", UCURR_COMMON|UCURR_DEPRECATED},
  1.1964 +    { NULL, 0 } // Leave here to denote the end of the list.
  1.1965 +};
  1.1966 +
  1.1967 +#define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
  1.1968 +    ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
  1.1969 +
  1.1970 +static int32_t U_CALLCONV
  1.1971 +ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
  1.1972 +    UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
  1.1973 +    uint32_t currType = myContext->currType;
  1.1974 +    int32_t count = 0;
  1.1975 +
  1.1976 +    /* Count the number of items matching the type we are looking for. */
  1.1977 +    for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
  1.1978 +        if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
  1.1979 +            count++;
  1.1980 +        }
  1.1981 +    }
  1.1982 +    return count;
  1.1983 +}
  1.1984 +
  1.1985 +static const char* U_CALLCONV
  1.1986 +ucurr_nextCurrencyList(UEnumeration *enumerator,
  1.1987 +                        int32_t* resultLength,
  1.1988 +                        UErrorCode * /*pErrorCode*/)
  1.1989 +{
  1.1990 +    UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
  1.1991 +
  1.1992 +    /* Find the next in the list that matches the type we are looking for. */
  1.1993 +    while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) {
  1.1994 +        const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
  1.1995 +        if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
  1.1996 +        {
  1.1997 +            if (resultLength) {
  1.1998 +                *resultLength = 3; /* Currency codes are only 3 chars long */
  1.1999 +            }
  1.2000 +            return currItem->currency;
  1.2001 +        }
  1.2002 +    }
  1.2003 +    /* We enumerated too far. */
  1.2004 +    if (resultLength) {
  1.2005 +        *resultLength = 0;
  1.2006 +    }
  1.2007 +    return NULL;
  1.2008 +}
  1.2009 +
  1.2010 +static void U_CALLCONV
  1.2011 +ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
  1.2012 +    ((UCurrencyContext *)(enumerator->context))->listIdx = 0;
  1.2013 +}
  1.2014 +
  1.2015 +static void U_CALLCONV
  1.2016 +ucurr_closeCurrencyList(UEnumeration *enumerator) {
  1.2017 +    uprv_free(enumerator->context);
  1.2018 +    uprv_free(enumerator);
  1.2019 +}
  1.2020 +
  1.2021 +static void U_CALLCONV
  1.2022 +ucurr_createCurrencyList(UHashtable *isoCodes, UErrorCode* status){
  1.2023 +    UErrorCode localStatus = U_ZERO_ERROR;
  1.2024 +
  1.2025 +    // Look up the CurrencyMap element in the root bundle.
  1.2026 +    UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
  1.2027 +    UResourceBundle *currencyMapArray = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
  1.2028 +
  1.2029 +    if (U_SUCCESS(localStatus)) {
  1.2030 +        // process each entry in currency map 
  1.2031 +        for (int32_t i=0; i<ures_getSize(currencyMapArray); i++) {
  1.2032 +            // get the currency resource
  1.2033 +            UResourceBundle *currencyArray = ures_getByIndex(currencyMapArray, i, NULL, &localStatus);
  1.2034 +            // process each currency 
  1.2035 +            if (U_SUCCESS(localStatus)) {
  1.2036 +                for (int32_t j=0; j<ures_getSize(currencyArray); j++) {
  1.2037 +                    // get the currency resource
  1.2038 +                    UResourceBundle *currencyRes = ures_getByIndex(currencyArray, j, NULL, &localStatus);
  1.2039 +                    IsoCodeEntry *entry = (IsoCodeEntry*)uprv_malloc(sizeof(IsoCodeEntry));
  1.2040 +                    if (entry == NULL) {
  1.2041 +                        *status = U_MEMORY_ALLOCATION_ERROR;
  1.2042 +                        return;
  1.2043 +                    }
  1.2044 +
  1.2045 +                    // get the ISO code
  1.2046 +                    int32_t isoLength = 0;
  1.2047 +                    UResourceBundle *idRes = ures_getByKey(currencyRes, "id", NULL, &localStatus);
  1.2048 +                    if (idRes == NULL) {
  1.2049 +                        continue;
  1.2050 +                    }
  1.2051 +                    const UChar *isoCode = ures_getString(idRes, &isoLength, &localStatus);
  1.2052 +
  1.2053 +                    // get from date
  1.2054 +                    UDate fromDate = U_DATE_MIN;
  1.2055 +                    UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
  1.2056 +
  1.2057 +                    if (U_SUCCESS(localStatus)) {
  1.2058 +                        int32_t fromLength = 0;
  1.2059 +                        const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
  1.2060 +                        int64_t currDate64 = (int64_t)fromArray[0] << 32;
  1.2061 +                        currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
  1.2062 +                        fromDate = (UDate)currDate64;
  1.2063 +                    }
  1.2064 +                    ures_close(fromRes);
  1.2065 +
  1.2066 +                    // get to date
  1.2067 +                    UDate toDate = U_DATE_MAX;
  1.2068 +                    localStatus = U_ZERO_ERROR;
  1.2069 +                    UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
  1.2070 +
  1.2071 +                    if (U_SUCCESS(localStatus)) {
  1.2072 +                        int32_t toLength = 0;
  1.2073 +                        const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
  1.2074 +                        int64_t currDate64 = (int64_t)toArray[0] << 32;
  1.2075 +                        currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
  1.2076 +                        toDate = (UDate)currDate64;
  1.2077 +                    }
  1.2078 +                    ures_close(toRes);
  1.2079 +
  1.2080 +                    ures_close(idRes);
  1.2081 +                    ures_close(currencyRes);
  1.2082 +
  1.2083 +                    entry->isoCode = isoCode;
  1.2084 +                    entry->from = fromDate;
  1.2085 +                    entry->to = toDate;
  1.2086 +
  1.2087 +                    localStatus = U_ZERO_ERROR;
  1.2088 +                    uhash_put(isoCodes, (UChar *)isoCode, entry, &localStatus);
  1.2089 +                }
  1.2090 +            } else {
  1.2091 +                *status = localStatus;
  1.2092 +            }
  1.2093 +            ures_close(currencyArray);
  1.2094 +        }
  1.2095 +    } else {
  1.2096 +        *status = localStatus;
  1.2097 +    }
  1.2098 +
  1.2099 +    ures_close(currencyMapArray);
  1.2100 +}
  1.2101 +
  1.2102 +static const UEnumeration gEnumCurrencyList = {
  1.2103 +    NULL,
  1.2104 +    NULL,
  1.2105 +    ucurr_closeCurrencyList,
  1.2106 +    ucurr_countCurrencyList,
  1.2107 +    uenum_unextDefault,
  1.2108 +    ucurr_nextCurrencyList,
  1.2109 +    ucurr_resetCurrencyList
  1.2110 +};
  1.2111 +U_CDECL_END
  1.2112 +
  1.2113 +
  1.2114 +static void U_CALLCONV initIsoCodes(UErrorCode &status) {
  1.2115 +    U_ASSERT(gIsoCodes == NULL);
  1.2116 +    ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
  1.2117 +
  1.2118 +    UHashtable *isoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
  1.2119 +    if (U_FAILURE(status)) {
  1.2120 +        return;
  1.2121 +    }
  1.2122 +    uhash_setValueDeleter(isoCodes, deleteIsoCodeEntry);
  1.2123 +
  1.2124 +    ucurr_createCurrencyList(isoCodes, &status);
  1.2125 +    if (U_FAILURE(status)) {
  1.2126 +        uhash_close(isoCodes);
  1.2127 +        return;
  1.2128 +    }
  1.2129 +    gIsoCodes = isoCodes;  // Note: gIsoCodes is const. Once set up here it is never altered,
  1.2130 +                           //       and read only access is safe without synchronization.
  1.2131 +}
  1.2132 +
  1.2133 +static void populateCurrSymbolsEquiv(icu::Hashtable *hash, UErrorCode &status) {
  1.2134 +    if (U_FAILURE(status)) {
  1.2135 +        return;
  1.2136 +    }
  1.2137 +    int32_t length = sizeof(EQUIV_CURRENCY_SYMBOLS) / sizeof(EQUIV_CURRENCY_SYMBOLS[0]);
  1.2138 +    for (int32_t i = 0; i < length; ++i) {
  1.2139 +        icu::UnicodeString lhs(EQUIV_CURRENCY_SYMBOLS[i][0], -1, US_INV);
  1.2140 +        icu::UnicodeString rhs(EQUIV_CURRENCY_SYMBOLS[i][1], -1, US_INV);
  1.2141 +        makeEquivalent(lhs.unescape(), rhs.unescape(), hash, status);
  1.2142 +        if (U_FAILURE(status)) {
  1.2143 +            return;
  1.2144 +        }
  1.2145 +    }
  1.2146 +}
  1.2147 +
  1.2148 +static void U_CALLCONV initCurrSymbolsEquiv() {
  1.2149 +    U_ASSERT(gCurrSymbolsEquiv == NULL);
  1.2150 +    UErrorCode status = U_ZERO_ERROR;
  1.2151 +    ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
  1.2152 +    icu::Hashtable *temp = new icu::Hashtable(status);
  1.2153 +    if (temp == NULL) {
  1.2154 +        return;
  1.2155 +    }
  1.2156 +    if (U_FAILURE(status)) {
  1.2157 +        delete temp;
  1.2158 +        return;
  1.2159 +    }
  1.2160 +    temp->setValueDeleter(deleteUnicode);
  1.2161 +    populateCurrSymbolsEquiv(temp, status);
  1.2162 +    if (U_FAILURE(status)) {
  1.2163 +        delete temp;
  1.2164 +        return;
  1.2165 +    }
  1.2166 +    gCurrSymbolsEquiv = temp;
  1.2167 +}
  1.2168 +
  1.2169 +U_CAPI UBool U_EXPORT2
  1.2170 +ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
  1.2171 +    umtx_initOnce(gIsoCodesInitOnce, &initIsoCodes, *eErrorCode);
  1.2172 +    if (U_FAILURE(*eErrorCode)) {
  1.2173 +        return FALSE;
  1.2174 +    }
  1.2175 +
  1.2176 +    IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
  1.2177 +    if (result == NULL) {
  1.2178 +        return FALSE;
  1.2179 +    } else if (from > to) {
  1.2180 +        *eErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
  1.2181 +        return FALSE;
  1.2182 +    } else if  ((from > result->to) || (to < result->from)) {
  1.2183 +        return FALSE;
  1.2184 +    }
  1.2185 +    return TRUE;
  1.2186 +}
  1.2187 +
  1.2188 +static const icu::Hashtable* getCurrSymbolsEquiv() {
  1.2189 +    umtx_initOnce(gCurrSymbolsEquivInitOnce, &initCurrSymbolsEquiv);
  1.2190 +    return gCurrSymbolsEquiv;
  1.2191 +}
  1.2192 +
  1.2193 +U_CAPI UEnumeration * U_EXPORT2
  1.2194 +ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
  1.2195 +    UEnumeration *myEnum = NULL;
  1.2196 +    UCurrencyContext *myContext;
  1.2197 +
  1.2198 +    myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
  1.2199 +    if (myEnum == NULL) {
  1.2200 +        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
  1.2201 +        return NULL;
  1.2202 +    }
  1.2203 +    uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
  1.2204 +    myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
  1.2205 +    if (myContext == NULL) {
  1.2206 +        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
  1.2207 +        uprv_free(myEnum);
  1.2208 +        return NULL;
  1.2209 +    }
  1.2210 +    myContext->currType = currType;
  1.2211 +    myContext->listIdx = 0;
  1.2212 +    myEnum->context = myContext;
  1.2213 +    return myEnum;
  1.2214 +}
  1.2215 +
  1.2216 +U_CAPI int32_t U_EXPORT2
  1.2217 +ucurr_countCurrencies(const char* locale, 
  1.2218 +                 UDate date, 
  1.2219 +                 UErrorCode* ec)
  1.2220 +{
  1.2221 +    int32_t currCount = 0;
  1.2222 +
  1.2223 +    if (ec != NULL && U_SUCCESS(*ec)) 
  1.2224 +    {
  1.2225 +        // local variables
  1.2226 +        UErrorCode localStatus = U_ZERO_ERROR;
  1.2227 +        char id[ULOC_FULLNAME_CAPACITY];
  1.2228 +        uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
  1.2229 +        // get country or country_variant in `id'
  1.2230 +        /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
  1.2231 +
  1.2232 +        if (U_FAILURE(*ec))
  1.2233 +        {
  1.2234 +            return 0;
  1.2235 +        }
  1.2236 +
  1.2237 +        // Remove variants, which is only needed for registration.
  1.2238 +        char *idDelim = strchr(id, VAR_DELIM);
  1.2239 +        if (idDelim)
  1.2240 +        {
  1.2241 +            idDelim[0] = 0;
  1.2242 +        }
  1.2243 +
  1.2244 +        // Look up the CurrencyMap element in the root bundle.
  1.2245 +        UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
  1.2246 +        UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
  1.2247 +
  1.2248 +        // Using the id derived from the local, get the currency data
  1.2249 +        UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
  1.2250 +
  1.2251 +        // process each currency to see which one is valid for the given date
  1.2252 +        if (U_SUCCESS(localStatus))
  1.2253 +        {
  1.2254 +            for (int32_t i=0; i<ures_getSize(countryArray); i++)
  1.2255 +            {
  1.2256 +                // get the currency resource
  1.2257 +                UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
  1.2258 +
  1.2259 +                // get the from date
  1.2260 +                int32_t fromLength = 0;
  1.2261 +                UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
  1.2262 +                const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
  1.2263 +
  1.2264 +                int64_t currDate64 = (int64_t)fromArray[0] << 32;
  1.2265 +                currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
  1.2266 +                UDate fromDate = (UDate)currDate64;
  1.2267 +
  1.2268 +                if (ures_getSize(currencyRes)> 2)
  1.2269 +                {
  1.2270 +                    int32_t toLength = 0;
  1.2271 +                    UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
  1.2272 +                    const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
  1.2273 +
  1.2274 +                    currDate64 = (int64_t)toArray[0] << 32;
  1.2275 +                    currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
  1.2276 +                    UDate toDate = (UDate)currDate64;
  1.2277 +
  1.2278 +                    if ((fromDate <= date) && (date < toDate))
  1.2279 +                    {
  1.2280 +                        currCount++;
  1.2281 +                    }
  1.2282 +
  1.2283 +                    ures_close(toRes);
  1.2284 +                }
  1.2285 +                else
  1.2286 +                {
  1.2287 +                    if (fromDate <= date)
  1.2288 +                    {
  1.2289 +                        currCount++;
  1.2290 +                    }
  1.2291 +                }
  1.2292 +
  1.2293 +                // close open resources
  1.2294 +                ures_close(currencyRes);
  1.2295 +                ures_close(fromRes);
  1.2296 +
  1.2297 +            } // end For loop
  1.2298 +        } // end if (U_SUCCESS(localStatus))
  1.2299 +
  1.2300 +        ures_close(countryArray);
  1.2301 +
  1.2302 +        // Check for errors
  1.2303 +        if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
  1.2304 +        {
  1.2305 +            // There is nothing to fallback to. 
  1.2306 +            // Report the failure/warning if possible.
  1.2307 +            *ec = localStatus;
  1.2308 +        }
  1.2309 +
  1.2310 +        if (U_SUCCESS(*ec))
  1.2311 +        {
  1.2312 +            // no errors
  1.2313 +            return currCount;
  1.2314 +        }
  1.2315 +
  1.2316 +    }
  1.2317 +
  1.2318 +    // If we got here, either error code is invalid or
  1.2319 +    // some argument passed is no good.
  1.2320 +    return 0;
  1.2321 +}
  1.2322 +
  1.2323 +U_CAPI int32_t U_EXPORT2 
  1.2324 +ucurr_forLocaleAndDate(const char* locale, 
  1.2325 +                UDate date, 
  1.2326 +                int32_t index,
  1.2327 +                UChar* buff, 
  1.2328 +                int32_t buffCapacity, 
  1.2329 +                UErrorCode* ec)
  1.2330 +{
  1.2331 +    int32_t resLen = 0;
  1.2332 +	int32_t currIndex = 0;
  1.2333 +    const UChar* s = NULL;
  1.2334 +
  1.2335 +    if (ec != NULL && U_SUCCESS(*ec))
  1.2336 +    {
  1.2337 +        // check the arguments passed
  1.2338 +        if ((buff && buffCapacity) || !buffCapacity )
  1.2339 +        {
  1.2340 +            // local variables
  1.2341 +            UErrorCode localStatus = U_ZERO_ERROR;
  1.2342 +            char id[ULOC_FULLNAME_CAPACITY];
  1.2343 +            resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
  1.2344 +
  1.2345 +            // get country or country_variant in `id'
  1.2346 +            /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
  1.2347 +            if (U_FAILURE(*ec))
  1.2348 +            {
  1.2349 +                return 0;
  1.2350 +            }
  1.2351 +
  1.2352 +            // Remove variants, which is only needed for registration.
  1.2353 +            char *idDelim = strchr(id, VAR_DELIM);
  1.2354 +            if (idDelim)
  1.2355 +            {
  1.2356 +                idDelim[0] = 0;
  1.2357 +            }
  1.2358 +
  1.2359 +            // Look up the CurrencyMap element in the root bundle.
  1.2360 +            UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
  1.2361 +            UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
  1.2362 +
  1.2363 +            // Using the id derived from the local, get the currency data
  1.2364 +            UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
  1.2365 +
  1.2366 +            // process each currency to see which one is valid for the given date
  1.2367 +            bool matchFound = false;
  1.2368 +            if (U_SUCCESS(localStatus))
  1.2369 +            {
  1.2370 +                if ((index <= 0) || (index> ures_getSize(countryArray)))
  1.2371 +                {
  1.2372 +                    // requested index is out of bounds
  1.2373 +                    ures_close(countryArray);
  1.2374 +                    return 0;
  1.2375 +                }
  1.2376 +
  1.2377 +                for (int32_t i=0; i<ures_getSize(countryArray); i++)
  1.2378 +                {
  1.2379 +                    // get the currency resource
  1.2380 +                    UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
  1.2381 +                    s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
  1.2382 +
  1.2383 +                    // get the from date
  1.2384 +                    int32_t fromLength = 0;
  1.2385 +                    UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
  1.2386 +                    const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
  1.2387 +
  1.2388 +                    int64_t currDate64 = (int64_t)fromArray[0] << 32;
  1.2389 +                    currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
  1.2390 +                    UDate fromDate = (UDate)currDate64;
  1.2391 +
  1.2392 +                    if (ures_getSize(currencyRes)> 2)
  1.2393 +                    {
  1.2394 +                        int32_t toLength = 0;
  1.2395 +                        UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
  1.2396 +                        const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
  1.2397 +
  1.2398 +                        currDate64 = (int64_t)toArray[0] << 32;
  1.2399 +                        currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
  1.2400 +                        UDate toDate = (UDate)currDate64;
  1.2401 +
  1.2402 +                        if ((fromDate <= date) && (date < toDate))
  1.2403 +                        {
  1.2404 +                            currIndex++;
  1.2405 +                            if (currIndex == index)
  1.2406 +                            {
  1.2407 +                                matchFound = true;
  1.2408 +                            }
  1.2409 +                        }
  1.2410 +
  1.2411 +                        ures_close(toRes);
  1.2412 +                    }
  1.2413 +                    else
  1.2414 +                    {
  1.2415 +                        if (fromDate <= date)
  1.2416 +                        {
  1.2417 +                            currIndex++;
  1.2418 +                            if (currIndex == index)
  1.2419 +                            {
  1.2420 +                                matchFound = true;
  1.2421 +                            }
  1.2422 +                        }
  1.2423 +                    }
  1.2424 +
  1.2425 +                    // close open resources
  1.2426 +                    ures_close(currencyRes);
  1.2427 +                    ures_close(fromRes);
  1.2428 +
  1.2429 +                    // check for loop exit
  1.2430 +                    if (matchFound)
  1.2431 +                    {
  1.2432 +                        break;
  1.2433 +                    }
  1.2434 +
  1.2435 +                } // end For loop
  1.2436 +            }
  1.2437 +
  1.2438 +            ures_close(countryArray);
  1.2439 +
  1.2440 +            // Check for errors
  1.2441 +            if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
  1.2442 +            {
  1.2443 +                // There is nothing to fallback to. 
  1.2444 +                // Report the failure/warning if possible.
  1.2445 +                *ec = localStatus;
  1.2446 +            }
  1.2447 +
  1.2448 +            if (U_SUCCESS(*ec))
  1.2449 +            {
  1.2450 +                // no errors
  1.2451 +                if((buffCapacity> resLen) && matchFound)
  1.2452 +                {
  1.2453 +                    // write out the currency value
  1.2454 +                    u_strcpy(buff, s);
  1.2455 +                }
  1.2456 +                else
  1.2457 +                {
  1.2458 +                    return 0;
  1.2459 +                }
  1.2460 +            }
  1.2461 +
  1.2462 +            // return null terminated currency string
  1.2463 +            return u_terminateUChars(buff, buffCapacity, resLen, ec);
  1.2464 +        }
  1.2465 +        else
  1.2466 +        {
  1.2467 +            // illegal argument encountered
  1.2468 +            *ec = U_ILLEGAL_ARGUMENT_ERROR;
  1.2469 +        }
  1.2470 +
  1.2471 +    }
  1.2472 +
  1.2473 +    // If we got here, either error code is invalid or
  1.2474 +    // some argument passed is no good.
  1.2475 +    return resLen;
  1.2476 +}
  1.2477 +
  1.2478 +static const UEnumeration defaultKeywordValues = {
  1.2479 +    NULL,
  1.2480 +    NULL,
  1.2481 +    ulist_close_keyword_values_iterator,
  1.2482 +    ulist_count_keyword_values,
  1.2483 +    uenum_unextDefault,
  1.2484 +    ulist_next_keyword_value, 
  1.2485 +    ulist_reset_keyword_values_iterator
  1.2486 +};
  1.2487 +
  1.2488 +U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key, const char *locale, UBool commonlyUsed, UErrorCode* status) {
  1.2489 +    // Resolve region
  1.2490 +    char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
  1.2491 +    int32_t prefRegionLength = 0;
  1.2492 +    prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
  1.2493 +    if (prefRegionLength == 0) {
  1.2494 +        char loc[ULOC_FULLNAME_CAPACITY] = "";
  1.2495 +        uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
  1.2496 +        
  1.2497 +        prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
  1.2498 +    }
  1.2499 +    
  1.2500 +    // Read value from supplementalData
  1.2501 +    UList *values = ulist_createEmptyList(status);
  1.2502 +    UList *otherValues = ulist_createEmptyList(status);
  1.2503 +    UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
  1.2504 +    if (U_FAILURE(*status) || en == NULL) {
  1.2505 +        if (en == NULL) {
  1.2506 +            *status = U_MEMORY_ALLOCATION_ERROR;
  1.2507 +        } else {
  1.2508 +            uprv_free(en);
  1.2509 +        }
  1.2510 +        ulist_deleteList(values);
  1.2511 +        ulist_deleteList(otherValues);
  1.2512 +        return NULL;
  1.2513 +    }
  1.2514 +    memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
  1.2515 +    en->context = values;
  1.2516 +    
  1.2517 +    UResourceBundle *bundle = ures_openDirect(U_ICUDATA_CURR, "supplementalData", status);
  1.2518 +    ures_getByKey(bundle, "CurrencyMap", bundle, status);
  1.2519 +    UResourceBundle bundlekey, regbndl, curbndl, to;
  1.2520 +    ures_initStackObject(&bundlekey);
  1.2521 +    ures_initStackObject(&regbndl);
  1.2522 +    ures_initStackObject(&curbndl);
  1.2523 +    ures_initStackObject(&to);
  1.2524 +    
  1.2525 +    while (U_SUCCESS(*status) && ures_hasNext(bundle)) {
  1.2526 +        ures_getNextResource(bundle, &bundlekey, status);
  1.2527 +        if (U_FAILURE(*status)) {
  1.2528 +            break;
  1.2529 +        }
  1.2530 +        const char *region = ures_getKey(&bundlekey);
  1.2531 +        UBool isPrefRegion = uprv_strcmp(region, prefRegion) == 0 ? TRUE : FALSE;
  1.2532 +        if (!isPrefRegion && commonlyUsed) {
  1.2533 +            // With commonlyUsed=true, we do not put
  1.2534 +            // currencies for other regions in the
  1.2535 +            // result list.
  1.2536 +            continue;
  1.2537 +        }
  1.2538 +        ures_getByKey(bundle, region, &regbndl, status);
  1.2539 +        if (U_FAILURE(*status)) {
  1.2540 +            break;
  1.2541 +        }
  1.2542 +        while (U_SUCCESS(*status) && ures_hasNext(&regbndl)) {
  1.2543 +            ures_getNextResource(&regbndl, &curbndl, status);
  1.2544 +            if (ures_getType(&curbndl) != URES_TABLE) {
  1.2545 +                // Currently, an empty ARRAY is mixed in.
  1.2546 +                continue;
  1.2547 +            }
  1.2548 +            char *curID = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
  1.2549 +            int32_t curIDLength = ULOC_KEYWORDS_CAPACITY;
  1.2550 +            if (curID == NULL) {
  1.2551 +                *status = U_MEMORY_ALLOCATION_ERROR;
  1.2552 +                break;
  1.2553 +            }
  1.2554 +
  1.2555 +#if U_CHARSET_FAMILY==U_ASCII_FAMILY
  1.2556 +            ures_getUTF8StringByKey(&curbndl, "id", curID, &curIDLength, TRUE, status);
  1.2557 +            /* optimize - use the utf-8 string */
  1.2558 +#else
  1.2559 +            {
  1.2560 +                       const UChar* defString = ures_getStringByKey(&curbndl, "id", &curIDLength, status);
  1.2561 +                       if(U_SUCCESS(*status)) {
  1.2562 +			   if(curIDLength+1 > ULOC_KEYWORDS_CAPACITY) {
  1.2563 +				*status = U_BUFFER_OVERFLOW_ERROR;
  1.2564 +			   } else {
  1.2565 +                           	u_UCharsToChars(defString, curID, curIDLength+1);
  1.2566 +			   }
  1.2567 +                       }
  1.2568 +            }
  1.2569 +#endif	
  1.2570 +
  1.2571 +            if (U_FAILURE(*status)) {
  1.2572 +                break;
  1.2573 +            }
  1.2574 +            UBool hasTo = FALSE;
  1.2575 +            ures_getByKey(&curbndl, "to", &to, status);
  1.2576 +            if (U_FAILURE(*status)) {
  1.2577 +                // Do nothing here...
  1.2578 +                *status = U_ZERO_ERROR;
  1.2579 +            } else {
  1.2580 +                hasTo = TRUE;
  1.2581 +            }
  1.2582 +            if (isPrefRegion && !hasTo && !ulist_containsString(values, curID, (int32_t)uprv_strlen(curID))) {
  1.2583 +                // Currently active currency for the target country
  1.2584 +                ulist_addItemEndList(values, curID, TRUE, status);
  1.2585 +            } else if (!ulist_containsString(otherValues, curID, (int32_t)uprv_strlen(curID)) && !commonlyUsed) {
  1.2586 +                ulist_addItemEndList(otherValues, curID, TRUE, status);
  1.2587 +            } else {
  1.2588 +                uprv_free(curID);
  1.2589 +            }
  1.2590 +        }
  1.2591 +        
  1.2592 +    }
  1.2593 +    if (U_SUCCESS(*status)) {
  1.2594 +        if (commonlyUsed) {
  1.2595 +            if (ulist_getListSize(values) == 0) {
  1.2596 +                // This could happen if no valid region is supplied in the input
  1.2597 +                // locale. In this case, we use the CLDR's default.
  1.2598 +                uenum_close(en);
  1.2599 +                en = ucurr_getKeywordValuesForLocale(key, "und", TRUE, status);
  1.2600 +            }
  1.2601 +        } else {
  1.2602 +            // Consolidate the list
  1.2603 +            char *value = NULL;
  1.2604 +            ulist_resetList(otherValues);
  1.2605 +            while ((value = (char *)ulist_getNext(otherValues)) != NULL) {
  1.2606 +                if (!ulist_containsString(values, value, (int32_t)uprv_strlen(value))) {
  1.2607 +                    char *tmpValue = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
  1.2608 +                    uprv_memcpy(tmpValue, value, uprv_strlen(value) + 1);
  1.2609 +                    ulist_addItemEndList(values, tmpValue, TRUE, status);
  1.2610 +                    if (U_FAILURE(*status)) {
  1.2611 +                        break;
  1.2612 +                    }
  1.2613 +                }
  1.2614 +            }
  1.2615 +        }
  1.2616 +        
  1.2617 +        ulist_resetList((UList *)(en->context));
  1.2618 +    } else {
  1.2619 +        ulist_deleteList(values);
  1.2620 +        uprv_free(en);
  1.2621 +        values = NULL;
  1.2622 +        en = NULL;
  1.2623 +    }
  1.2624 +    ures_close(&to);
  1.2625 +    ures_close(&curbndl);
  1.2626 +    ures_close(&regbndl);
  1.2627 +    ures_close(&bundlekey);
  1.2628 +    ures_close(bundle);
  1.2629 +    
  1.2630 +    ulist_deleteList(otherValues);
  1.2631 +    
  1.2632 +    return en;
  1.2633 +}
  1.2634 +
  1.2635 +
  1.2636 +U_CAPI int32_t U_EXPORT2
  1.2637 +ucurr_getNumericCode(const UChar* currency) {
  1.2638 +    int32_t code = 0;
  1.2639 +    if (currency && u_strlen(currency) == ISO_CURRENCY_CODE_LENGTH) {
  1.2640 +        UErrorCode status = U_ZERO_ERROR;
  1.2641 +
  1.2642 +        UResourceBundle *bundle = ures_openDirect(0, "currencyNumericCodes", &status);
  1.2643 +        ures_getByKey(bundle, "codeMap", bundle, &status);
  1.2644 +        if (U_SUCCESS(status)) {
  1.2645 +            char alphaCode[ISO_CURRENCY_CODE_LENGTH+1];
  1.2646 +            myUCharsToChars(alphaCode, currency);
  1.2647 +            T_CString_toUpperCase(alphaCode);
  1.2648 +            ures_getByKey(bundle, alphaCode, bundle, &status);
  1.2649 +            int tmpCode = ures_getInt(bundle, &status);
  1.2650 +            if (U_SUCCESS(status)) {
  1.2651 +                code = tmpCode;
  1.2652 +            }
  1.2653 +        }
  1.2654 +        ures_close(bundle);
  1.2655 +    }
  1.2656 +    return code;
  1.2657 +}
  1.2658 +#endif /* #if !UCONFIG_NO_FORMATTING */
  1.2659 +
  1.2660 +//eof

mercurial