Home | History | Annotate | Download | only in common
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 **********************************************************************
      5 * Copyright (c) 2002-2016, International Business Machines
      6 * Corporation and others.  All Rights Reserved.
      7 **********************************************************************
      8 */
      9 
     10 #include "unicode/utypes.h"
     11 
     12 #if !UCONFIG_NO_FORMATTING
     13 
     14 #include "unicode/ucurr.h"
     15 #include "unicode/locid.h"
     16 #include "unicode/ures.h"
     17 #include "unicode/ustring.h"
     18 #include "unicode/parsepos.h"
     19 #include "ustr_imp.h"
     20 #include "cmemory.h"
     21 #include "cstring.h"
     22 #include "uassert.h"
     23 #include "umutex.h"
     24 #include "ucln_cmn.h"
     25 #include "uenumimp.h"
     26 #include "uhash.h"
     27 #include "hash.h"
     28 #include "uinvchar.h"
     29 #include "uresimp.h"
     30 #include "ulist.h"
     31 #include "ureslocs.h"
     32 #include "ulocimp.h"
     33 
     34 //#define UCURR_DEBUG_EQUIV 1
     35 #ifdef UCURR_DEBUG_EQUIV
     36 #include "stdio.h"
     37 #endif
     38 //#define UCURR_DEBUG 1
     39 #ifdef UCURR_DEBUG
     40 #include "stdio.h"
     41 #endif
     42 
     43 typedef struct IsoCodeEntry {
     44     const UChar *isoCode; /* const because it's a reference to a resource bundle string. */
     45     UDate from;
     46     UDate to;
     47 } IsoCodeEntry;
     48 
     49 //------------------------------------------------------------
     50 // Constants
     51 
     52 // Default currency meta data of last resort.  We try to use the
     53 // defaults encoded in the meta data resource bundle.  If there is a
     54 // configuration/build error and these are not available, we use these
     55 // hard-coded defaults (which should be identical).
     56 static const int32_t LAST_RESORT_DATA[] = { 2, 0, 2, 0 };
     57 
     58 // POW10[i] = 10^i, i=0..MAX_POW10
     59 static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
     60                                  1000000, 10000000, 100000000, 1000000000 };
     61 
     62 static const int32_t MAX_POW10 = UPRV_LENGTHOF(POW10) - 1;
     63 
     64 // Defines equivalent currency symbols.
     65 static const char *EQUIV_CURRENCY_SYMBOLS[][2] = {
     66     {"\\u00a5", "\\uffe5"},
     67     {"$", "\\ufe69"},
     68     {"$", "\\uff04"},
     69     {"\\u20a8", "\\u20b9"},
     70     {"\\u00a3", "\\u20a4"}};
     71 
     72 #define ISO_CURRENCY_CODE_LENGTH 3
     73 
     74 //------------------------------------------------------------
     75 // Resource tags
     76 //
     77 
     78 static const char CURRENCY_DATA[] = "supplementalData";
     79 // Tag for meta-data, in root.
     80 static const char CURRENCY_META[] = "CurrencyMeta";
     81 
     82 // Tag for map from countries to currencies, in root.
     83 static const char CURRENCY_MAP[] = "CurrencyMap";
     84 
     85 // Tag for default meta-data, in CURRENCY_META
     86 static const char DEFAULT_META[] = "DEFAULT";
     87 
     88 // Variant for legacy pre-euro mapping in CurrencyMap
     89 static const char VAR_PRE_EURO[] = "PREEURO";
     90 
     91 // Variant for legacy euro mapping in CurrencyMap
     92 static const char VAR_EURO[] = "EURO";
     93 
     94 // Variant delimiter
     95 static const char VAR_DELIM = '_';
     96 static const char VAR_DELIM_STR[] = "_";
     97 
     98 // Variant for legacy euro mapping in CurrencyMap
     99 //static const char VAR_DELIM_EURO[] = "_EURO";
    100 
    101 #define VARIANT_IS_EMPTY    0
    102 #define VARIANT_IS_EURO     0x1
    103 #define VARIANT_IS_PREEURO  0x2
    104 
    105 // Tag for localized display names (symbols) of currencies
    106 static const char CURRENCIES[] = "Currencies";
    107 static const char CURRENCYPLURALS[] = "CurrencyPlurals";
    108 
    109 static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
    110 
    111 // ISO codes mapping table
    112 static const UHashtable* gIsoCodes = NULL;
    113 static icu::UInitOnce gIsoCodesInitOnce = U_INITONCE_INITIALIZER;
    114 
    115 // Currency symbol equivalances
    116 static const icu::Hashtable* gCurrSymbolsEquiv = NULL;
    117 static icu::UInitOnce gCurrSymbolsEquivInitOnce = U_INITONCE_INITIALIZER;
    118 
    119 U_NAMESPACE_BEGIN
    120 
    121 // EquivIterator iterates over all strings that are equivalent to a given
    122 // string, s. Note that EquivIterator will never yield s itself.
    123 class EquivIterator : public icu::UMemory {
    124 public:
    125     // Constructor. hash stores the equivalence relationships; s is the string
    126     // for which we find equivalent strings.
    127     inline EquivIterator(const icu::Hashtable& hash, const icu::UnicodeString& s)
    128         : _hash(hash) {
    129         _start = _current = &s;
    130     }
    131     inline ~EquivIterator() { }
    132 
    133     // next returns the next equivalent string or NULL if there are no more.
    134     // If s has no equivalent strings, next returns NULL on the first call.
    135     const icu::UnicodeString *next();
    136 private:
    137     const icu::Hashtable& _hash;
    138     const icu::UnicodeString* _start;
    139     const icu::UnicodeString* _current;
    140 };
    141 
    142 const icu::UnicodeString *
    143 EquivIterator::next() {
    144     const icu::UnicodeString* _next = (const icu::UnicodeString*) _hash.get(*_current);
    145     if (_next == NULL) {
    146         U_ASSERT(_current == _start);
    147         return NULL;
    148     }
    149     if (*_next == *_start) {
    150         return NULL;
    151     }
    152     _current = _next;
    153     return _next;
    154 }
    155 
    156 U_NAMESPACE_END
    157 
    158 // makeEquivalent makes lhs and rhs equivalent by updating the equivalence
    159 // relations in hash accordingly.
    160 static void makeEquivalent(
    161     const icu::UnicodeString &lhs,
    162     const icu::UnicodeString &rhs,
    163     icu::Hashtable* hash, UErrorCode &status) {
    164     if (U_FAILURE(status)) {
    165         return;
    166     }
    167     if (lhs == rhs) {
    168         // already equivalent
    169         return;
    170     }
    171     icu::EquivIterator leftIter(*hash, lhs);
    172     icu::EquivIterator rightIter(*hash, rhs);
    173     const icu::UnicodeString *firstLeft = leftIter.next();
    174     const icu::UnicodeString *firstRight = rightIter.next();
    175     const icu::UnicodeString *nextLeft = firstLeft;
    176     const icu::UnicodeString *nextRight = firstRight;
    177     while (nextLeft != NULL && nextRight != NULL) {
    178         if (*nextLeft == rhs || *nextRight == lhs) {
    179             // Already equivalent
    180             return;
    181         }
    182         nextLeft = leftIter.next();
    183         nextRight = rightIter.next();
    184     }
    185     // Not equivalent. Must join.
    186     icu::UnicodeString *newFirstLeft;
    187     icu::UnicodeString *newFirstRight;
    188     if (firstRight == NULL && firstLeft == NULL) {
    189         // Neither lhs or rhs belong to an equivalence circle, so we form
    190         // a new equivalnce circle of just lhs and rhs.
    191         newFirstLeft = new icu::UnicodeString(rhs);
    192         newFirstRight = new icu::UnicodeString(lhs);
    193     } else if (firstRight == NULL) {
    194         // lhs belongs to an equivalence circle, but rhs does not, so we link
    195         // rhs into lhs' circle.
    196         newFirstLeft = new icu::UnicodeString(rhs);
    197         newFirstRight = new icu::UnicodeString(*firstLeft);
    198     } else if (firstLeft == NULL) {
    199         // rhs belongs to an equivlance circle, but lhs does not, so we link
    200         // lhs into rhs' circle.
    201         newFirstLeft = new icu::UnicodeString(*firstRight);
    202         newFirstRight = new icu::UnicodeString(lhs);
    203     } else {
    204         // Both lhs and rhs belong to different equivalnce circles. We link
    205         // them together to form one single, larger equivalnce circle.
    206         newFirstLeft = new icu::UnicodeString(*firstRight);
    207         newFirstRight = new icu::UnicodeString(*firstLeft);
    208     }
    209     if (newFirstLeft == NULL || newFirstRight == NULL) {
    210         delete newFirstLeft;
    211         delete newFirstRight;
    212         status = U_MEMORY_ALLOCATION_ERROR;
    213         return;
    214     }
    215     hash->put(lhs, (void *) newFirstLeft, status);
    216     hash->put(rhs, (void *) newFirstRight, status);
    217 }
    218 
    219 // countEquivalent counts how many strings are equivalent to s.
    220 // hash stores all the equivalnce relations.
    221 // countEquivalent does not include s itself in the count.
    222 static int32_t countEquivalent(const icu::Hashtable &hash, const icu::UnicodeString &s) {
    223     int32_t result = 0;
    224     icu::EquivIterator iter(hash, s);
    225     while (iter.next() != NULL) {
    226         ++result;
    227     }
    228 #ifdef UCURR_DEBUG_EQUIV
    229  {
    230    char tmp[200];
    231    s.extract(0,s.length(),tmp, "UTF-8");
    232    printf("CountEquivalent('%s') = %d\n", tmp, result);
    233  }
    234 #endif
    235     return result;
    236 }
    237 
    238 static const icu::Hashtable* getCurrSymbolsEquiv();
    239 
    240 //------------------------------------------------------------
    241 // Code
    242 
    243 /**
    244  * Cleanup callback func
    245  */
    246 static UBool U_CALLCONV
    247 isoCodes_cleanup(void)
    248 {
    249     if (gIsoCodes != NULL) {
    250         uhash_close(const_cast<UHashtable *>(gIsoCodes));
    251         gIsoCodes = NULL;
    252     }
    253     gIsoCodesInitOnce.reset();
    254     return TRUE;
    255 }
    256 
    257 /**
    258  * Cleanup callback func
    259  */
    260 static UBool U_CALLCONV
    261 currSymbolsEquiv_cleanup(void)
    262 {
    263     delete const_cast<icu::Hashtable *>(gCurrSymbolsEquiv);
    264     gCurrSymbolsEquiv = NULL;
    265     gCurrSymbolsEquivInitOnce.reset();
    266     return TRUE;
    267 }
    268 
    269 /**
    270  * Deleter for OlsonToMetaMappingEntry
    271  */
    272 static void U_CALLCONV
    273 deleteIsoCodeEntry(void *obj) {
    274     IsoCodeEntry *entry = (IsoCodeEntry*)obj;
    275     uprv_free(entry);
    276 }
    277 
    278 /**
    279  * Deleter for gCurrSymbolsEquiv.
    280  */
    281 static void U_CALLCONV
    282 deleteUnicode(void *obj) {
    283     icu::UnicodeString *entry = (icu::UnicodeString*)obj;
    284     delete entry;
    285 }
    286 
    287 /**
    288  * Unfortunately, we have to convert the UChar* currency code to char*
    289  * to use it as a resource key.
    290  */
    291 static inline char*
    292 myUCharsToChars(char* resultOfLen4, const UChar* currency) {
    293     u_UCharsToChars(currency, resultOfLen4, ISO_CURRENCY_CODE_LENGTH);
    294     resultOfLen4[ISO_CURRENCY_CODE_LENGTH] = 0;
    295     return resultOfLen4;
    296 }
    297 
    298 /**
    299  * Internal function to look up currency data.  Result is an array of
    300  * four integers.  The first is the fraction digits.  The second is the
    301  * rounding increment, or 0 if none.  The rounding increment is in
    302  * units of 10^(-fraction_digits).  The third and fourth are the same
    303  * except that they are those used in cash transations ( cashDigits
    304  * and cashRounding ).
    305  */
    306 static const int32_t*
    307 _findMetaData(const UChar* currency, UErrorCode& ec) {
    308 
    309     if (currency == 0 || *currency == 0) {
    310         if (U_SUCCESS(ec)) {
    311             ec = U_ILLEGAL_ARGUMENT_ERROR;
    312         }
    313         return LAST_RESORT_DATA;
    314     }
    315 
    316     // Get CurrencyMeta resource out of root locale file.  [This may
    317     // move out of the root locale file later; if it does, update this
    318     // code.]
    319     UResourceBundle* currencyData = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &ec);
    320     UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec);
    321 
    322     if (U_FAILURE(ec)) {
    323         ures_close(currencyMeta);
    324         // Config/build error; return hard-coded defaults
    325         return LAST_RESORT_DATA;
    326     }
    327 
    328     // Look up our currency, or if that's not available, then DEFAULT
    329     char buf[ISO_CURRENCY_CODE_LENGTH+1];
    330     UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure
    331     UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2);
    332       if (U_FAILURE(ec2)) {
    333         ures_close(rb);
    334         rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec);
    335         if (U_FAILURE(ec)) {
    336             ures_close(currencyMeta);
    337             ures_close(rb);
    338             // Config/build error; return hard-coded defaults
    339             return LAST_RESORT_DATA;
    340         }
    341     }
    342 
    343     int32_t len;
    344     const int32_t *data = ures_getIntVector(rb, &len, &ec);
    345     if (U_FAILURE(ec) || len != 4) {
    346         // Config/build error; return hard-coded defaults
    347         if (U_SUCCESS(ec)) {
    348             ec = U_INVALID_FORMAT_ERROR;
    349         }
    350         ures_close(currencyMeta);
    351         ures_close(rb);
    352         return LAST_RESORT_DATA;
    353     }
    354 
    355     ures_close(currencyMeta);
    356     ures_close(rb);
    357     return data;
    358 }
    359 
    360 // -------------------------------------
    361 
    362 /**
    363  * @see VARIANT_IS_EURO
    364  * @see VARIANT_IS_PREEURO
    365  */
    366 static uint32_t
    367 idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec)
    368 {
    369     uint32_t variantType = 0;
    370     // !!! this is internal only, assumes buffer is not null and capacity is sufficient
    371     // Extract the country name and variant name.  We only
    372     // recognize two variant names, EURO and PREEURO.
    373     char variant[ULOC_FULLNAME_CAPACITY];
    374     ulocimp_getRegionForSupplementalData(locale, FALSE, countryAndVariant, capacity, ec);
    375     uloc_getVariant(locale, variant, sizeof(variant), ec);
    376     if (variant[0] != 0) {
    377         variantType = (uint32_t)(0 == uprv_strcmp(variant, VAR_EURO))
    378                    | ((uint32_t)(0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1);
    379         if (variantType)
    380         {
    381             uprv_strcat(countryAndVariant, VAR_DELIM_STR);
    382             uprv_strcat(countryAndVariant, variant);
    383         }
    384     }
    385     return variantType;
    386 }
    387 
    388 // ------------------------------------------
    389 //
    390 // Registration
    391 //
    392 //-------------------------------------------
    393 
    394 // don't use ICUService since we don't need fallback
    395 
    396 U_CDECL_BEGIN
    397 static UBool U_CALLCONV currency_cleanup(void);
    398 U_CDECL_END
    399 
    400 #if !UCONFIG_NO_SERVICE
    401 struct CReg;
    402 
    403 static UMutex gCRegLock = U_MUTEX_INITIALIZER;
    404 static CReg* gCRegHead = 0;
    405 
    406 struct CReg : public icu::UMemory {
    407     CReg *next;
    408     UChar iso[ISO_CURRENCY_CODE_LENGTH+1];
    409     char  id[ULOC_FULLNAME_CAPACITY];
    410 
    411     CReg(const UChar* _iso, const char* _id)
    412         : next(0)
    413     {
    414         int32_t len = (int32_t)uprv_strlen(_id);
    415         if (len > (int32_t)(sizeof(id)-1)) {
    416             len = (sizeof(id)-1);
    417         }
    418         uprv_strncpy(id, _id, len);
    419         id[len] = 0;
    420         u_memcpy(iso, _iso, ISO_CURRENCY_CODE_LENGTH);
    421         iso[ISO_CURRENCY_CODE_LENGTH] = 0;
    422     }
    423 
    424     static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status)
    425     {
    426         if (status && U_SUCCESS(*status) && _iso && _id) {
    427             CReg* n = new CReg(_iso, _id);
    428             if (n) {
    429                 umtx_lock(&gCRegLock);
    430                 if (!gCRegHead) {
    431                     /* register for the first time */
    432                     ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cleanup);
    433                 }
    434                 n->next = gCRegHead;
    435                 gCRegHead = n;
    436                 umtx_unlock(&gCRegLock);
    437                 return n;
    438             }
    439             *status = U_MEMORY_ALLOCATION_ERROR;
    440         }
    441         return 0;
    442     }
    443 
    444     static UBool unreg(UCurrRegistryKey key) {
    445         UBool found = FALSE;
    446         umtx_lock(&gCRegLock);
    447 
    448         CReg** p = &gCRegHead;
    449         while (*p) {
    450             if (*p == key) {
    451                 *p = ((CReg*)key)->next;
    452                 delete (CReg*)key;
    453                 found = TRUE;
    454                 break;
    455             }
    456             p = &((*p)->next);
    457         }
    458 
    459         umtx_unlock(&gCRegLock);
    460         return found;
    461     }
    462 
    463     static const UChar* get(const char* id) {
    464         const UChar* result = NULL;
    465         umtx_lock(&gCRegLock);
    466         CReg* p = gCRegHead;
    467 
    468         /* register cleanup of the mutex */
    469         ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cleanup);
    470         while (p) {
    471             if (uprv_strcmp(id, p->id) == 0) {
    472                 result = p->iso;
    473                 break;
    474             }
    475             p = p->next;
    476         }
    477         umtx_unlock(&gCRegLock);
    478         return result;
    479     }
    480 
    481     /* This doesn't need to be thread safe. It's for u_cleanup only. */
    482     static void cleanup(void) {
    483         while (gCRegHead) {
    484             CReg* n = gCRegHead;
    485             gCRegHead = gCRegHead->next;
    486             delete n;
    487         }
    488     }
    489 };
    490 
    491 // -------------------------------------
    492 
    493 U_CAPI UCurrRegistryKey U_EXPORT2
    494 ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
    495 {
    496     if (status && U_SUCCESS(*status)) {
    497         char id[ULOC_FULLNAME_CAPACITY];
    498         idForLocale(locale, id, sizeof(id), status);
    499         return CReg::reg(isoCode, id, status);
    500     }
    501     return NULL;
    502 }
    503 
    504 // -------------------------------------
    505 
    506 U_CAPI UBool U_EXPORT2
    507 ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
    508 {
    509     if (status && U_SUCCESS(*status)) {
    510         return CReg::unreg(key);
    511     }
    512     return FALSE;
    513 }
    514 #endif /* UCONFIG_NO_SERVICE */
    515 
    516 // -------------------------------------
    517 
    518 /**
    519  * Release all static memory held by currency.
    520  */
    521 /*The declaration here is needed so currency_cleanup(void)
    522  * can call this function.
    523  */
    524 static UBool U_CALLCONV
    525 currency_cache_cleanup(void);
    526 
    527 U_CDECL_BEGIN
    528 static UBool U_CALLCONV currency_cleanup(void) {
    529 #if !UCONFIG_NO_SERVICE
    530     CReg::cleanup();
    531 #endif
    532     /*
    533      * There might be some cached currency data or isoCodes data.
    534      */
    535     currency_cache_cleanup();
    536     isoCodes_cleanup();
    537     currSymbolsEquiv_cleanup();
    538 
    539     return TRUE;
    540 }
    541 U_CDECL_END
    542 
    543 // -------------------------------------
    544 
    545 U_CAPI int32_t U_EXPORT2
    546 ucurr_forLocale(const char* locale,
    547                 UChar* buff,
    548                 int32_t buffCapacity,
    549                 UErrorCode* ec) {
    550     if (U_FAILURE(*ec)) { return 0; }
    551     if (buffCapacity < 0 || (buff == nullptr && buffCapacity > 0)) {
    552         *ec = U_ILLEGAL_ARGUMENT_ERROR;
    553         return 0;
    554     }
    555 
    556     char currency[4];  // ISO currency codes are alpha3 codes.
    557     UErrorCode localStatus = U_ZERO_ERROR;
    558     int32_t resLen = uloc_getKeywordValue(locale, "currency",
    559                                           currency, UPRV_LENGTHOF(currency), &localStatus);
    560     if (U_SUCCESS(localStatus) && resLen == 3 && uprv_isInvariantString(currency, resLen)) {
    561         if (resLen < buffCapacity) {
    562             T_CString_toUpperCase(currency);
    563             u_charsToUChars(currency, buff, resLen);
    564         }
    565         return u_terminateUChars(buff, buffCapacity, resLen, ec);
    566     }
    567 
    568     // get country or country_variant in `id'
    569     char id[ULOC_FULLNAME_CAPACITY];
    570     uint32_t variantType = idForLocale(locale, id, UPRV_LENGTHOF(id), ec);
    571     if (U_FAILURE(*ec)) {
    572         return 0;
    573     }
    574 
    575 #if !UCONFIG_NO_SERVICE
    576     const UChar* result = CReg::get(id);
    577     if (result) {
    578         if(buffCapacity > u_strlen(result)) {
    579             u_strcpy(buff, result);
    580         }
    581         resLen = u_strlen(result);
    582         return u_terminateUChars(buff, buffCapacity, resLen, ec);
    583     }
    584 #endif
    585     // Remove variants, which is only needed for registration.
    586     char *idDelim = uprv_strchr(id, VAR_DELIM);
    587     if (idDelim) {
    588         idDelim[0] = 0;
    589     }
    590 
    591     const UChar* s = NULL;  // Currency code from data file.
    592     if (id[0] == 0) {
    593         // No point looking in the data for an empty string.
    594         // This is what we would get.
    595         localStatus = U_MISSING_RESOURCE_ERROR;
    596     } else {
    597         // Look up the CurrencyMap element in the root bundle.
    598         localStatus = U_ZERO_ERROR;
    599         UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
    600         UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
    601         UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
    602         UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus);
    603         s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
    604 
    605         // Get the second item when PREEURO is requested, and this is a known Euro country.
    606         // If the requested variant is PREEURO, and this isn't a Euro country,
    607         // assume that the country changed over to the Euro in the future.
    608         // This is probably an old version of ICU that hasn't been updated yet.
    609         // The latest currency is probably correct.
    610         if (U_SUCCESS(localStatus)) {
    611             if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) {
    612                 currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus);
    613                 s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
    614             } else if ((variantType & VARIANT_IS_EURO)) {
    615                 s = EUR_STR;
    616             }
    617         }
    618         ures_close(currencyReq);
    619         ures_close(countryArray);
    620     }
    621 
    622     if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0) {
    623         // We don't know about it.  Check to see if we support the variant.
    624         uloc_getParent(locale, id, UPRV_LENGTHOF(id), ec);
    625         *ec = U_USING_FALLBACK_WARNING;
    626         // TODO: Loop over the shortened id rather than recursing and
    627         // looking again for a currency keyword.
    628         return ucurr_forLocale(id, buff, buffCapacity, ec);
    629     }
    630     if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) {
    631         // There is nothing to fallback to. Report the failure/warning if possible.
    632         *ec = localStatus;
    633     }
    634     if (U_SUCCESS(*ec)) {
    635         if(buffCapacity > resLen) {
    636             u_strcpy(buff, s);
    637         }
    638     }
    639     return u_terminateUChars(buff, buffCapacity, resLen, ec);
    640 }
    641 
    642 // end registration
    643 
    644 /**
    645  * Modify the given locale name by removing the rightmost _-delimited
    646  * element.  If there is none, empty the string ("" == root).
    647  * NOTE: The string "root" is not recognized; do not use it.
    648  * @return TRUE if the fallback happened; FALSE if locale is already
    649  * root ("").
    650  */
    651 static UBool fallback(char *loc) {
    652     if (!*loc) {
    653         return FALSE;
    654     }
    655     UErrorCode status = U_ZERO_ERROR;
    656     if (uprv_strcmp(loc, "en_GB") == 0) {
    657         // HACK: See #13368.  We need "en_GB" to fall back to "en_001" instead of "en"
    658         // in order to consume the correct data strings.  This hack will be removed
    659         // when proper data sink loading is implemented here.
    660         // NOTE: "001" adds 1 char over "GB".  However, both call sites allocate
    661         // arrays with length ULOC_FULLNAME_CAPACITY (plenty of room for en_001).
    662         uprv_strcpy(loc + 3, "001");
    663     } else {
    664         uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status);
    665     }
    666  /*
    667     char *i = uprv_strrchr(loc, '_');
    668     if (i == NULL) {
    669         i = loc;
    670     }
    671     *i = 0;
    672  */
    673     return TRUE;
    674 }
    675 
    676 
    677 U_CAPI const UChar* U_EXPORT2
    678 ucurr_getName(const UChar* currency,
    679               const char* locale,
    680               UCurrNameStyle nameStyle,
    681               UBool* isChoiceFormat, // fillin
    682               int32_t* len, // fillin
    683               UErrorCode* ec) {
    684 
    685     // Look up the Currencies resource for the given locale.  The
    686     // Currencies locale data looks like this:
    687     //|en {
    688     //|  Currencies {
    689     //|    USD { "US$", "US Dollar" }
    690     //|    CHF { "Sw F", "Swiss Franc" }
    691     //|    INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
    692     //|    //...
    693     //|  }
    694     //|}
    695 
    696     if (U_FAILURE(*ec)) {
    697         return 0;
    698     }
    699 
    700     int32_t choice = (int32_t) nameStyle;
    701     if (choice < 0 || choice > 1) {
    702         *ec = U_ILLEGAL_ARGUMENT_ERROR;
    703         return 0;
    704     }
    705 
    706     // In the future, resource bundles may implement multi-level
    707     // fallback.  That is, if a currency is not found in the en_US
    708     // Currencies data, then the en Currencies data will be searched.
    709     // Currently, if a Currencies datum exists in en_US and en, the
    710     // en_US entry hides that in en.
    711 
    712     // We want multi-level fallback for this resource, so we implement
    713     // it manually.
    714 
    715     // Use a separate UErrorCode here that does not propagate out of
    716     // this function.
    717     UErrorCode ec2 = U_ZERO_ERROR;
    718 
    719     char loc[ULOC_FULLNAME_CAPACITY];
    720     uloc_getName(locale, loc, sizeof(loc), &ec2);
    721     if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
    722         *ec = U_ILLEGAL_ARGUMENT_ERROR;
    723         return 0;
    724     }
    725 
    726     char buf[ISO_CURRENCY_CODE_LENGTH+1];
    727     myUCharsToChars(buf, currency);
    728 
    729     /* Normalize the keyword value to uppercase */
    730     T_CString_toUpperCase(buf);
    731 
    732     const UChar* s = NULL;
    733     ec2 = U_ZERO_ERROR;
    734     UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
    735 
    736     rb = ures_getByKey(rb, CURRENCIES, rb, &ec2);
    737 
    738     // Fetch resource with multi-level resource inheritance fallback
    739     rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
    740 
    741     s = ures_getStringByIndex(rb, choice, len, &ec2);
    742     ures_close(rb);
    743 
    744     // If we've succeeded we're done.  Otherwise, try to fallback.
    745     // If that fails (because we are already at root) then exit.
    746     if (U_SUCCESS(ec2)) {
    747         if (ec2 == U_USING_DEFAULT_WARNING
    748             || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
    749             *ec = ec2;
    750         }
    751     }
    752 
    753     // We no longer support choice format data in names.  Data should not contain
    754     // choice patterns.
    755     *isChoiceFormat = FALSE;
    756     if (U_SUCCESS(ec2)) {
    757         U_ASSERT(s != NULL);
    758         return s;
    759     }
    760 
    761     // If we fail to find a match, use the ISO 4217 code
    762     *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
    763     *ec = U_USING_DEFAULT_WARNING;
    764     return currency;
    765 }
    766 
    767 U_CAPI const UChar* U_EXPORT2
    768 ucurr_getPluralName(const UChar* currency,
    769                     const char* locale,
    770                     UBool* isChoiceFormat,
    771                     const char* pluralCount,
    772                     int32_t* len, // fillin
    773                     UErrorCode* ec) {
    774     // Look up the Currencies resource for the given locale.  The
    775     // Currencies locale data looks like this:
    776     //|en {
    777     //|  CurrencyPlurals {
    778     //|    USD{
    779     //|      one{"US dollar"}
    780     //|      other{"US dollars"}
    781     //|    }
    782     //|  }
    783     //|}
    784 
    785     if (U_FAILURE(*ec)) {
    786         return 0;
    787     }
    788 
    789     // Use a separate UErrorCode here that does not propagate out of
    790     // this function.
    791     UErrorCode ec2 = U_ZERO_ERROR;
    792 
    793     char loc[ULOC_FULLNAME_CAPACITY];
    794     uloc_getName(locale, loc, sizeof(loc), &ec2);
    795     if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
    796         *ec = U_ILLEGAL_ARGUMENT_ERROR;
    797         return 0;
    798     }
    799 
    800     char buf[ISO_CURRENCY_CODE_LENGTH+1];
    801     myUCharsToChars(buf, currency);
    802 
    803     const UChar* s = NULL;
    804     ec2 = U_ZERO_ERROR;
    805     UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
    806 
    807     rb = ures_getByKey(rb, CURRENCYPLURALS, rb, &ec2);
    808 
    809     // Fetch resource with multi-level resource inheritance fallback
    810     rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
    811 
    812     s = ures_getStringByKeyWithFallback(rb, pluralCount, len, &ec2);
    813     if (U_FAILURE(ec2)) {
    814         //  fall back to "other"
    815         ec2 = U_ZERO_ERROR;
    816         s = ures_getStringByKeyWithFallback(rb, "other", len, &ec2);
    817         if (U_FAILURE(ec2)) {
    818             ures_close(rb);
    819             // fall back to long name in Currencies
    820             return ucurr_getName(currency, locale, UCURR_LONG_NAME,
    821                                  isChoiceFormat, len, ec);
    822         }
    823     }
    824     ures_close(rb);
    825 
    826     // If we've succeeded we're done.  Otherwise, try to fallback.
    827     // If that fails (because we are already at root) then exit.
    828     if (U_SUCCESS(ec2)) {
    829         if (ec2 == U_USING_DEFAULT_WARNING
    830             || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
    831             *ec = ec2;
    832         }
    833         U_ASSERT(s != NULL);
    834         return s;
    835     }
    836 
    837     // If we fail to find a match, use the ISO 4217 code
    838     *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
    839     *ec = U_USING_DEFAULT_WARNING;
    840     return currency;
    841 }
    842 
    843 
    844 //========================================================================
    845 // Following are structure and function for parsing currency names
    846 
    847 #define NEED_TO_BE_DELETED 0x1
    848 
    849 // TODO: a better way to define this?
    850 #define MAX_CURRENCY_NAME_LEN 100
    851 
    852 typedef struct {
    853     const char* IsoCode;  // key
    854     UChar* currencyName;  // value
    855     int32_t currencyNameLen;  // value length
    856     int32_t flag;  // flags
    857 } CurrencyNameStruct;
    858 
    859 
    860 #ifndef MIN
    861 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
    862 #endif
    863 
    864 #ifndef MAX
    865 #define MAX(a,b) (((a)<(b)) ? (b) : (a))
    866 #endif
    867 
    868 
    869 // Comparason function used in quick sort.
    870 static int U_CALLCONV currencyNameComparator(const void* a, const void* b) {
    871     const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
    872     const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b;
    873     for (int32_t i = 0;
    874          i < MIN(currName_1->currencyNameLen, currName_2->currencyNameLen);
    875          ++i) {
    876         if (currName_1->currencyName[i] < currName_2->currencyName[i]) {
    877             return -1;
    878         }
    879         if (currName_1->currencyName[i] > currName_2->currencyName[i]) {
    880             return 1;
    881         }
    882     }
    883     if (currName_1->currencyNameLen < currName_2->currencyNameLen) {
    884         return -1;
    885     } else if (currName_1->currencyNameLen > currName_2->currencyNameLen) {
    886         return 1;
    887     }
    888     return 0;
    889 }
    890 
    891 
    892 // Give a locale, return the maximum number of currency names associated with
    893 // this locale.
    894 // It gets currency names from resource bundles using fallback.
    895 // It is the maximum number because in the fallback chain, some of the
    896 // currency names are duplicated.
    897 // For example, given locale as "en_US", the currency names get from resource
    898 // bundle in "en_US" and "en" are duplicated. The fallback mechanism will count
    899 // all currency names in "en_US" and "en".
    900 static void
    901 getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_t* total_currency_symbol_count) {
    902     U_NAMESPACE_USE
    903     *total_currency_name_count = 0;
    904     *total_currency_symbol_count = 0;
    905     const UChar* s = NULL;
    906     char locale[ULOC_FULLNAME_CAPACITY];
    907     uprv_strcpy(locale, loc);
    908     const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv();
    909     for (;;) {
    910         UErrorCode ec2 = U_ZERO_ERROR;
    911         // TODO: ures_openDirect?
    912         UResourceBundle* rb = ures_open(U_ICUDATA_CURR, locale, &ec2);
    913         UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
    914         int32_t n = ures_getSize(curr);
    915         for (int32_t i=0; i<n; ++i) {
    916             UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
    917             int32_t len;
    918             s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
    919             ++(*total_currency_symbol_count);  // currency symbol
    920             if (currencySymbolsEquiv != NULL) {
    921                 *total_currency_symbol_count += countEquivalent(*currencySymbolsEquiv, UnicodeString(TRUE, s, len));
    922             }
    923             ++(*total_currency_symbol_count); // iso code
    924             ++(*total_currency_name_count); // long name
    925             ures_close(names);
    926         }
    927 
    928         // currency plurals
    929         UErrorCode ec3 = U_ZERO_ERROR;
    930         UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
    931         n = ures_getSize(curr_p);
    932         for (int32_t i=0; i<n; ++i) {
    933             UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
    934             *total_currency_name_count += ures_getSize(names);
    935             ures_close(names);
    936         }
    937         ures_close(curr_p);
    938         ures_close(curr);
    939         ures_close(rb);
    940 
    941         if (!fallback(locale)) {
    942             break;
    943         }
    944     }
    945 }
    946 
    947 static UChar*
    948 toUpperCase(const UChar* source, int32_t len, const char* locale) {
    949     UChar* dest = NULL;
    950     UErrorCode ec = U_ZERO_ERROR;
    951     int32_t destLen = u_strToUpper(dest, 0, source, len, locale, &ec);
    952 
    953     ec = U_ZERO_ERROR;
    954     dest = (UChar*)uprv_malloc(sizeof(UChar) * MAX(destLen, len));
    955     u_strToUpper(dest, destLen, source, len, locale, &ec);
    956     if (U_FAILURE(ec)) {
    957         u_memcpy(dest, source, len);
    958     }
    959     return dest;
    960 }
    961 
    962 
    963 // Collect all available currency names associated with the given locale
    964 // (enable fallback chain).
    965 // Read currenc names defined in resource bundle "Currencies" and
    966 // "CurrencyPlural", enable fallback chain.
    967 // return the malloc-ed currency name arrays and the total number of currency
    968 // names in the array.
    969 static void
    970 collectCurrencyNames(const char* locale,
    971                      CurrencyNameStruct** currencyNames,
    972                      int32_t* total_currency_name_count,
    973                      CurrencyNameStruct** currencySymbols,
    974                      int32_t* total_currency_symbol_count,
    975                      UErrorCode& ec) {
    976     U_NAMESPACE_USE
    977     const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv();
    978     // Look up the Currencies resource for the given locale.
    979     UErrorCode ec2 = U_ZERO_ERROR;
    980 
    981     char loc[ULOC_FULLNAME_CAPACITY];
    982     uloc_getName(locale, loc, sizeof(loc), &ec2);
    983     if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
    984         ec = U_ILLEGAL_ARGUMENT_ERROR;
    985     }
    986 
    987     // Get maximum currency name count first.
    988     getCurrencyNameCount(loc, total_currency_name_count, total_currency_symbol_count);
    989 
    990     *currencyNames = (CurrencyNameStruct*)uprv_malloc
    991         (sizeof(CurrencyNameStruct) * (*total_currency_name_count));
    992     *currencySymbols = (CurrencyNameStruct*)uprv_malloc
    993         (sizeof(CurrencyNameStruct) * (*total_currency_symbol_count));
    994 
    995     if(currencyNames == NULL || currencySymbols == NULL) {
    996       ec = U_MEMORY_ALLOCATION_ERROR;
    997     }
    998 
    999     if (U_FAILURE(ec)) return;
   1000 
   1001     const UChar* s = NULL;  // currency name
   1002     char* iso = NULL;  // currency ISO code
   1003 
   1004     *total_currency_name_count = 0;
   1005     *total_currency_symbol_count = 0;
   1006 
   1007     UErrorCode ec3 = U_ZERO_ERROR;
   1008     UErrorCode ec4 = U_ZERO_ERROR;
   1009 
   1010     // Using hash to remove duplicates caused by locale fallback
   1011     UHashtable* currencyIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec3);
   1012     UHashtable* currencyPluralIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec4);
   1013     for (int32_t localeLevel = 0; ; ++localeLevel) {
   1014         ec2 = U_ZERO_ERROR;
   1015         // TODO: ures_openDirect
   1016         UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
   1017         UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
   1018         int32_t n = ures_getSize(curr);
   1019         for (int32_t i=0; i<n; ++i) {
   1020             UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
   1021             int32_t len;
   1022             s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
   1023             // TODO: uhash_put wont change key/value?
   1024             iso = (char*)ures_getKey(names);
   1025             if (localeLevel == 0) {
   1026                 uhash_put(currencyIsoCodes, iso, iso, &ec3);
   1027             } else {
   1028                 if (uhash_get(currencyIsoCodes, iso) != NULL) {
   1029                     ures_close(names);
   1030                     continue;
   1031                 } else {
   1032                     uhash_put(currencyIsoCodes, iso, iso, &ec3);
   1033                 }
   1034             }
   1035             // Add currency symbol.
   1036             (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
   1037             (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s;
   1038             (*currencySymbols)[*total_currency_symbol_count].flag = 0;
   1039             (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
   1040             // Add equivalent symbols
   1041             if (currencySymbolsEquiv != NULL) {
   1042                 UnicodeString str(TRUE, s, len);
   1043                 icu::EquivIterator iter(*currencySymbolsEquiv, str);
   1044                 const UnicodeString *symbol;
   1045                 while ((symbol = iter.next()) != NULL) {
   1046                     (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
   1047                     (*currencySymbols)[*total_currency_symbol_count].currencyName =
   1048                         const_cast<UChar*>(symbol->getBuffer());
   1049                     (*currencySymbols)[*total_currency_symbol_count].flag = 0;
   1050                     (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = symbol->length();
   1051                 }
   1052             }
   1053 
   1054             // Add currency long name.
   1055             s = ures_getStringByIndex(names, UCURR_LONG_NAME, &len, &ec2);
   1056             (*currencyNames)[*total_currency_name_count].IsoCode = iso;
   1057             UChar* upperName = toUpperCase(s, len, locale);
   1058             (*currencyNames)[*total_currency_name_count].currencyName = upperName;
   1059             (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
   1060             (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
   1061 
   1062             // put (iso, 3, and iso) in to array
   1063             // Add currency ISO code.
   1064             (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
   1065             (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
   1066             // Must convert iso[] into Unicode
   1067             u_charsToUChars(iso, (*currencySymbols)[*total_currency_symbol_count].currencyName, 3);
   1068             (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
   1069             (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = 3;
   1070 
   1071             ures_close(names);
   1072         }
   1073 
   1074         // currency plurals
   1075         UErrorCode ec3 = U_ZERO_ERROR;
   1076         UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
   1077         n = ures_getSize(curr_p);
   1078         for (int32_t i=0; i<n; ++i) {
   1079             UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
   1080             iso = (char*)ures_getKey(names);
   1081             // Using hash to remove duplicated ISO codes in fallback chain.
   1082             if (localeLevel == 0) {
   1083                 uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
   1084             } else {
   1085                 if (uhash_get(currencyPluralIsoCodes, iso) != NULL) {
   1086                     ures_close(names);
   1087                     continue;
   1088                 } else {
   1089                     uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
   1090                 }
   1091             }
   1092             int32_t num = ures_getSize(names);
   1093             int32_t len;
   1094             for (int32_t j = 0; j < num; ++j) {
   1095                 // TODO: remove duplicates between singular name and
   1096                 // currency long name?
   1097                 s = ures_getStringByIndex(names, j, &len, &ec3);
   1098                 (*currencyNames)[*total_currency_name_count].IsoCode = iso;
   1099                 UChar* upperName = toUpperCase(s, len, locale);
   1100                 (*currencyNames)[*total_currency_name_count].currencyName = upperName;
   1101                 (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
   1102                 (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
   1103             }
   1104             ures_close(names);
   1105         }
   1106         ures_close(curr_p);
   1107         ures_close(curr);
   1108         ures_close(rb);
   1109 
   1110         if (!fallback(loc)) {
   1111             break;
   1112         }
   1113     }
   1114 
   1115     uhash_close(currencyIsoCodes);
   1116     uhash_close(currencyPluralIsoCodes);
   1117 
   1118     // quick sort the struct
   1119     qsort(*currencyNames, *total_currency_name_count,
   1120           sizeof(CurrencyNameStruct), currencyNameComparator);
   1121     qsort(*currencySymbols, *total_currency_symbol_count,
   1122           sizeof(CurrencyNameStruct), currencyNameComparator);
   1123 
   1124 #ifdef UCURR_DEBUG
   1125     printf("currency name count: %d\n", *total_currency_name_count);
   1126     for (int32_t index = 0; index < *total_currency_name_count; ++index) {
   1127         printf("index: %d\n", index);
   1128         printf("iso: %s\n", (*currencyNames)[index].IsoCode);
   1129         char curNameBuf[1024];
   1130         memset(curNameBuf, 0, 1024);
   1131         u_austrncpy(curNameBuf, (*currencyNames)[index].currencyName, (*currencyNames)[index].currencyNameLen);
   1132         printf("currencyName: %s\n", curNameBuf);
   1133         printf("len: %d\n", (*currencyNames)[index].currencyNameLen);
   1134     }
   1135     printf("currency symbol count: %d\n", *total_currency_symbol_count);
   1136     for (int32_t index = 0; index < *total_currency_symbol_count; ++index) {
   1137         printf("index: %d\n", index);
   1138         printf("iso: %s\n", (*currencySymbols)[index].IsoCode);
   1139         char curNameBuf[1024];
   1140         memset(curNameBuf, 0, 1024);
   1141         u_austrncpy(curNameBuf, (*currencySymbols)[index].currencyName, (*currencySymbols)[index].currencyNameLen);
   1142         printf("currencySymbol: %s\n", curNameBuf);
   1143         printf("len: %d\n", (*currencySymbols)[index].currencyNameLen);
   1144     }
   1145 #endif
   1146     // fail on hashtable errors
   1147     if (U_FAILURE(ec3)) {
   1148       ec = ec3;
   1149       return;
   1150     }
   1151     if (U_FAILURE(ec4)) {
   1152       ec = ec4;
   1153       return;
   1154     }
   1155 }
   1156 
   1157 // @param  currencyNames: currency names array
   1158 // @param  indexInCurrencyNames: the index of the character in currency names
   1159 //         array against which the comparison is done
   1160 // @param  key: input text char to compare against
   1161 // @param  begin(IN/OUT): the begin index of matching range in currency names array
   1162 // @param  end(IN/OUT): the end index of matching range in currency names array.
   1163 static int32_t
   1164 binarySearch(const CurrencyNameStruct* currencyNames,
   1165              int32_t indexInCurrencyNames,
   1166              const UChar key,
   1167              int32_t* begin, int32_t* end) {
   1168 #ifdef UCURR_DEBUG
   1169     printf("key = %x\n", key);
   1170 #endif
   1171    int32_t first = *begin;
   1172    int32_t last = *end;
   1173    while (first <= last) {
   1174        int32_t mid = (first + last) / 2;  // compute mid point.
   1175        if (indexInCurrencyNames >= currencyNames[mid].currencyNameLen) {
   1176            first = mid + 1;
   1177        } else {
   1178            if (key > currencyNames[mid].currencyName[indexInCurrencyNames]) {
   1179                first = mid + 1;
   1180            }
   1181            else if (key < currencyNames[mid].currencyName[indexInCurrencyNames]) {
   1182                last = mid - 1;
   1183            }
   1184            else {
   1185                 // Find a match, and looking for ranges
   1186                 // Now do two more binary searches. First, on the left side for
   1187                 // the greatest L such that CurrencyNameStruct[L] < key.
   1188                 int32_t L = *begin;
   1189                 int32_t R = mid;
   1190 
   1191 #ifdef UCURR_DEBUG
   1192                 printf("mid = %d\n", mid);
   1193 #endif
   1194                 while (L < R) {
   1195                     int32_t M = (L + R) / 2;
   1196 #ifdef UCURR_DEBUG
   1197                     printf("L = %d, R = %d, M = %d\n", L, R, M);
   1198 #endif
   1199                     if (indexInCurrencyNames >= currencyNames[M].currencyNameLen) {
   1200                         L = M + 1;
   1201                     } else {
   1202                         if (currencyNames[M].currencyName[indexInCurrencyNames] < key) {
   1203                             L = M + 1;
   1204                         } else {
   1205 #ifdef UCURR_DEBUG
   1206                             U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
   1207 #endif
   1208                             R = M;
   1209                         }
   1210                     }
   1211                 }
   1212 #ifdef UCURR_DEBUG
   1213                 U_ASSERT(L == R);
   1214 #endif
   1215                 *begin = L;
   1216 #ifdef UCURR_DEBUG
   1217                 printf("begin = %d\n", *begin);
   1218                 U_ASSERT(currencyNames[*begin].currencyName[indexInCurrencyNames] == key);
   1219 #endif
   1220 
   1221                 // Now for the second search, finding the least R such that
   1222                 // key < CurrencyNameStruct[R].
   1223                 L = mid;
   1224                 R = *end;
   1225                 while (L < R) {
   1226                     int32_t M = (L + R) / 2;
   1227 #ifdef UCURR_DEBUG
   1228                     printf("L = %d, R = %d, M = %d\n", L, R, M);
   1229 #endif
   1230                     if (currencyNames[M].currencyNameLen < indexInCurrencyNames) {
   1231                         L = M + 1;
   1232                     } else {
   1233                         if (currencyNames[M].currencyName[indexInCurrencyNames] > key) {
   1234                             R = M;
   1235                         } else {
   1236 #ifdef UCURR_DEBUG
   1237                             U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
   1238 #endif
   1239                             L = M + 1;
   1240                         }
   1241                     }
   1242                 }
   1243 #ifdef UCURR_DEBUG
   1244                 U_ASSERT(L == R);
   1245 #endif
   1246                 if (currencyNames[R].currencyName[indexInCurrencyNames] > key) {
   1247                     *end = R - 1;
   1248                 } else {
   1249                     *end = R;
   1250                 }
   1251 #ifdef UCURR_DEBUG
   1252                 printf("end = %d\n", *end);
   1253 #endif
   1254 
   1255                 // now, found the range. check whether there is exact match
   1256                 if (currencyNames[*begin].currencyNameLen == indexInCurrencyNames + 1) {
   1257                     return *begin;  // find range and exact match.
   1258                 }
   1259                 return -1;  // find range, but no exact match.
   1260            }
   1261        }
   1262    }
   1263    *begin = -1;
   1264    *end = -1;
   1265    return -1;    // failed to find range.
   1266 }
   1267 
   1268 
   1269 // Linear search "text" in "currencyNames".
   1270 // @param  begin, end: the begin and end index in currencyNames, within which
   1271 //         range should the search be performed.
   1272 // @param  textLen: the length of the text to be compared
   1273 // @param  maxMatchLen(IN/OUT): passing in the computed max matching length
   1274 //                              pass out the new max  matching length
   1275 // @param  maxMatchIndex: the index in currencyName which has the longest
   1276 //                        match with input text.
   1277 static void
   1278 linearSearch(const CurrencyNameStruct* currencyNames,
   1279              int32_t begin, int32_t end,
   1280              const UChar* text, int32_t textLen,
   1281              int32_t *maxMatchLen, int32_t* maxMatchIndex) {
   1282     for (int32_t index = begin; index <= end; ++index) {
   1283         int32_t len = currencyNames[index].currencyNameLen;
   1284         if (len > *maxMatchLen && len <= textLen &&
   1285             uprv_memcmp(currencyNames[index].currencyName, text, len * sizeof(UChar)) == 0) {
   1286             *maxMatchIndex = index;
   1287             *maxMatchLen = len;
   1288 #ifdef UCURR_DEBUG
   1289             printf("maxMatchIndex = %d, maxMatchLen = %d\n",
   1290                    *maxMatchIndex, *maxMatchLen);
   1291 #endif
   1292         }
   1293     }
   1294 }
   1295 
   1296 #define LINEAR_SEARCH_THRESHOLD 10
   1297 
   1298 // Find longest match between "text" and currency names in "currencyNames".
   1299 // @param  total_currency_count: total number of currency names in CurrencyNames.
   1300 // @param  textLen: the length of the text to be compared
   1301 // @param  maxMatchLen: passing in the computed max matching length
   1302 //                              pass out the new max  matching length
   1303 // @param  maxMatchIndex: the index in currencyName which has the longest
   1304 //                        match with input text.
   1305 static void
   1306 searchCurrencyName(const CurrencyNameStruct* currencyNames,
   1307                    int32_t total_currency_count,
   1308                    const UChar* text, int32_t textLen,
   1309                    int32_t* maxMatchLen, int32_t* maxMatchIndex) {
   1310     *maxMatchIndex = -1;
   1311     *maxMatchLen = 0;
   1312     int32_t matchIndex = -1;
   1313     int32_t binarySearchBegin = 0;
   1314     int32_t binarySearchEnd = total_currency_count - 1;
   1315     // It is a variant of binary search.
   1316     // For example, given the currency names in currencyNames array are:
   1317     // A AB ABC AD AZ B BB BBEX BBEXYZ BS C D E....
   1318     // and the input text is BBEXST
   1319     // The first round binary search search "B" in the text against
   1320     // the first char in currency names, and find the first char matching range
   1321     // to be "B BB BBEX BBEXYZ BS" (and the maximum matching "B").
   1322     // The 2nd round binary search search the second "B" in the text against
   1323     // the 2nd char in currency names, and narrow the matching range to
   1324     // "BB BBEX BBEXYZ" (and the maximum matching "BB").
   1325     // The 3rd round returnes the range as "BBEX BBEXYZ" (without changing
   1326     // maximum matching).
   1327     // The 4th round returns the same range (the maximum matching is "BBEX").
   1328     // The 5th round returns no matching range.
   1329     for (int32_t index = 0; index < textLen; ++index) {
   1330         // matchIndex saves the one with exact match till the current point.
   1331         // [binarySearchBegin, binarySearchEnd] saves the matching range.
   1332         matchIndex = binarySearch(currencyNames, index,
   1333                                   text[index],
   1334                                   &binarySearchBegin, &binarySearchEnd);
   1335         if (binarySearchBegin == -1) { // did not find the range
   1336             break;
   1337         }
   1338         if (matchIndex != -1) {
   1339             // find an exact match for text from text[0] to text[index]
   1340             // in currencyNames array.
   1341             *maxMatchLen = index + 1;
   1342             *maxMatchIndex = matchIndex;
   1343         }
   1344         if (binarySearchEnd - binarySearchBegin < LINEAR_SEARCH_THRESHOLD) {
   1345             // linear search if within threshold.
   1346             linearSearch(currencyNames, binarySearchBegin, binarySearchEnd,
   1347                          text, textLen,
   1348                          maxMatchLen, maxMatchIndex);
   1349             break;
   1350         }
   1351     }
   1352     return;
   1353 }
   1354 
   1355 //========================= currency name cache =====================
   1356 typedef struct {
   1357     char locale[ULOC_FULLNAME_CAPACITY];  //key
   1358     // currency names, case insensitive
   1359     CurrencyNameStruct* currencyNames;  // value
   1360     int32_t totalCurrencyNameCount;  // currency name count
   1361     // currency symbols and ISO code, case sensitive
   1362     CurrencyNameStruct* currencySymbols; // value
   1363     int32_t totalCurrencySymbolCount;  // count
   1364     // reference count.
   1365     // reference count is set to 1 when an entry is put to cache.
   1366     // it increases by 1 before accessing, and decreased by 1 after accessing.
   1367     // The entry is deleted when ref count is zero, which means
   1368     // the entry is replaced out of cache and no process is accessing it.
   1369     int32_t refCount;
   1370 } CurrencyNameCacheEntry;
   1371 
   1372 
   1373 #define CURRENCY_NAME_CACHE_NUM 10
   1374 
   1375 // Reserve 10 cache entries.
   1376 static CurrencyNameCacheEntry* currCache[CURRENCY_NAME_CACHE_NUM] = {NULL};
   1377 // Using an index to indicate which entry to be replaced when cache is full.
   1378 // It is a simple round-robin replacement strategy.
   1379 static int8_t currentCacheEntryIndex = 0;
   1380 
   1381 static UMutex gCurrencyCacheMutex = U_MUTEX_INITIALIZER;
   1382 
   1383 // Cache deletion
   1384 static void
   1385 deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
   1386     for (int32_t index = 0; index < count; ++index) {
   1387         if ( (currencyNames[index].flag & NEED_TO_BE_DELETED) ) {
   1388             uprv_free(currencyNames[index].currencyName);
   1389         }
   1390     }
   1391     uprv_free(currencyNames);
   1392 }
   1393 
   1394 
   1395 static void
   1396 deleteCacheEntry(CurrencyNameCacheEntry* entry) {
   1397     deleteCurrencyNames(entry->currencyNames, entry->totalCurrencyNameCount);
   1398     deleteCurrencyNames(entry->currencySymbols, entry->totalCurrencySymbolCount);
   1399     uprv_free(entry);
   1400 }
   1401 
   1402 
   1403 // Cache clean up
   1404 static UBool U_CALLCONV
   1405 currency_cache_cleanup(void) {
   1406     for (int32_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
   1407         if (currCache[i]) {
   1408             deleteCacheEntry(currCache[i]);
   1409             currCache[i] = 0;
   1410         }
   1411     }
   1412     return TRUE;
   1413 }
   1414 
   1415 
   1416 U_CAPI void
   1417 uprv_parseCurrency(const char* locale,
   1418                    const icu::UnicodeString& text,
   1419                    icu::ParsePosition& pos,
   1420                    int8_t type,
   1421                    UChar* result,
   1422                    UErrorCode& ec)
   1423 {
   1424     U_NAMESPACE_USE
   1425 
   1426     if (U_FAILURE(ec)) {
   1427         return;
   1428     }
   1429 
   1430     int32_t total_currency_name_count = 0;
   1431     CurrencyNameStruct* currencyNames = NULL;
   1432     int32_t total_currency_symbol_count = 0;
   1433     CurrencyNameStruct* currencySymbols = NULL;
   1434     CurrencyNameCacheEntry* cacheEntry = NULL;
   1435 
   1436     umtx_lock(&gCurrencyCacheMutex);
   1437     // in order to handle racing correctly,
   1438     // not putting 'search' in a separate function.
   1439     int8_t  found = -1;
   1440     for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
   1441         if (currCache[i]!= NULL &&
   1442             uprv_strcmp(locale, currCache[i]->locale) == 0) {
   1443             found = i;
   1444             break;
   1445         }
   1446     }
   1447     if (found != -1) {
   1448         cacheEntry = currCache[found];
   1449         currencyNames = cacheEntry->currencyNames;
   1450         total_currency_name_count = cacheEntry->totalCurrencyNameCount;
   1451         currencySymbols = cacheEntry->currencySymbols;
   1452         total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
   1453         ++(cacheEntry->refCount);
   1454     }
   1455     umtx_unlock(&gCurrencyCacheMutex);
   1456     if (found == -1) {
   1457         collectCurrencyNames(locale, &currencyNames, &total_currency_name_count, &currencySymbols, &total_currency_symbol_count, ec);
   1458         if (U_FAILURE(ec)) {
   1459             return;
   1460         }
   1461         umtx_lock(&gCurrencyCacheMutex);
   1462         // check again.
   1463         int8_t  found = -1;
   1464         for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
   1465             if (currCache[i]!= NULL &&
   1466                 uprv_strcmp(locale, currCache[i]->locale) == 0) {
   1467                 found = i;
   1468                 break;
   1469             }
   1470         }
   1471         if (found == -1) {
   1472             // insert new entry to
   1473             // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
   1474             // and remove the existing entry
   1475             // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
   1476             // from cache.
   1477             cacheEntry = currCache[currentCacheEntryIndex];
   1478             if (cacheEntry) {
   1479                 --(cacheEntry->refCount);
   1480                 // delete if the ref count is zero
   1481                 if (cacheEntry->refCount == 0) {
   1482                     deleteCacheEntry(cacheEntry);
   1483                 }
   1484             }
   1485             cacheEntry = (CurrencyNameCacheEntry*)uprv_malloc(sizeof(CurrencyNameCacheEntry));
   1486             currCache[currentCacheEntryIndex] = cacheEntry;
   1487             uprv_strcpy(cacheEntry->locale, locale);
   1488             cacheEntry->currencyNames = currencyNames;
   1489             cacheEntry->totalCurrencyNameCount = total_currency_name_count;
   1490             cacheEntry->currencySymbols = currencySymbols;
   1491             cacheEntry->totalCurrencySymbolCount = total_currency_symbol_count;
   1492             cacheEntry->refCount = 2; // one for cache, one for reference
   1493             currentCacheEntryIndex = (currentCacheEntryIndex + 1) % CURRENCY_NAME_CACHE_NUM;
   1494             ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cache_cleanup);
   1495         } else {
   1496             deleteCurrencyNames(currencyNames, total_currency_name_count);
   1497             deleteCurrencyNames(currencySymbols, total_currency_symbol_count);
   1498             cacheEntry = currCache[found];
   1499             currencyNames = cacheEntry->currencyNames;
   1500             total_currency_name_count = cacheEntry->totalCurrencyNameCount;
   1501             currencySymbols = cacheEntry->currencySymbols;
   1502             total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
   1503             ++(cacheEntry->refCount);
   1504         }
   1505         umtx_unlock(&gCurrencyCacheMutex);
   1506     }
   1507 
   1508     int32_t start = pos.getIndex();
   1509 
   1510     UChar inputText[MAX_CURRENCY_NAME_LEN];
   1511     UChar upperText[MAX_CURRENCY_NAME_LEN];
   1512     int32_t textLen = MIN(MAX_CURRENCY_NAME_LEN, text.length() - start);
   1513     text.extract(start, textLen, inputText);
   1514     UErrorCode ec1 = U_ZERO_ERROR;
   1515     textLen = u_strToUpper(upperText, MAX_CURRENCY_NAME_LEN, inputText, textLen, locale, &ec1);
   1516 
   1517     int32_t max = 0;
   1518     int32_t matchIndex = -1;
   1519     // case in-sensitive comparision against currency names
   1520     searchCurrencyName(currencyNames, total_currency_name_count,
   1521                        upperText, textLen, &max, &matchIndex);
   1522 
   1523 #ifdef UCURR_DEBUG
   1524     printf("search in names, max = %d, matchIndex = %d\n", max, matchIndex);
   1525 #endif
   1526 
   1527     int32_t maxInSymbol = 0;
   1528     int32_t matchIndexInSymbol = -1;
   1529     if (type != UCURR_LONG_NAME) {  // not name only
   1530         // case sensitive comparison against currency symbols and ISO code.
   1531         searchCurrencyName(currencySymbols, total_currency_symbol_count,
   1532                            inputText, textLen,
   1533                            &maxInSymbol, &matchIndexInSymbol);
   1534     }
   1535 
   1536 #ifdef UCURR_DEBUG
   1537     printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol);
   1538     if(matchIndexInSymbol != -1) {
   1539       printf("== ISO=%s\n", currencySymbols[matchIndexInSymbol].IsoCode);
   1540     }
   1541 #endif
   1542 
   1543     if (max >= maxInSymbol && matchIndex != -1) {
   1544         u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4);
   1545         pos.setIndex(start + max);
   1546     } else if (maxInSymbol >= max && matchIndexInSymbol != -1) {
   1547         u_charsToUChars(currencySymbols[matchIndexInSymbol].IsoCode, result, 4);
   1548         pos.setIndex(start + maxInSymbol);
   1549     }
   1550 
   1551     // decrease reference count
   1552     umtx_lock(&gCurrencyCacheMutex);
   1553     --(cacheEntry->refCount);
   1554     if (cacheEntry->refCount == 0) {  // remove
   1555         deleteCacheEntry(cacheEntry);
   1556     }
   1557     umtx_unlock(&gCurrencyCacheMutex);
   1558 }
   1559 
   1560 
   1561 /**
   1562  * Internal method.  Given a currency ISO code and a locale, return
   1563  * the "static" currency name.  This is usually the same as the
   1564  * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
   1565  * format is applied to the number 2.0 (to yield the more common
   1566  * plural) to return a static name.
   1567  *
   1568  * This is used for backward compatibility with old currency logic in
   1569  * DecimalFormat and DecimalFormatSymbols.
   1570  */
   1571 U_CAPI void
   1572 uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
   1573                            icu::UnicodeString& result, UErrorCode& ec)
   1574 {
   1575     U_NAMESPACE_USE
   1576 
   1577     UBool isChoiceFormat;
   1578     int32_t len;
   1579     const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME,
   1580                                           &isChoiceFormat, &len, &ec);
   1581     if (U_SUCCESS(ec)) {
   1582         result.setTo(currname, len);
   1583     }
   1584 }
   1585 
   1586 U_CAPI int32_t U_EXPORT2
   1587 ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) {
   1588     return ucurr_getDefaultFractionDigitsForUsage(currency,UCURR_USAGE_STANDARD,ec);
   1589 }
   1590 
   1591 U_DRAFT int32_t U_EXPORT2
   1592 ucurr_getDefaultFractionDigitsForUsage(const UChar* currency, const UCurrencyUsage usage, UErrorCode* ec) {
   1593     int32_t fracDigits = 0;
   1594     if (U_SUCCESS(*ec)) {
   1595         switch (usage) {
   1596             case UCURR_USAGE_STANDARD:
   1597                 fracDigits = (_findMetaData(currency, *ec))[0];
   1598                 break;
   1599             case UCURR_USAGE_CASH:
   1600                 fracDigits = (_findMetaData(currency, *ec))[2];
   1601                 break;
   1602             default:
   1603                 *ec = U_UNSUPPORTED_ERROR;
   1604         }
   1605     }
   1606     return fracDigits;
   1607 }
   1608 
   1609 U_CAPI double U_EXPORT2
   1610 ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) {
   1611     return ucurr_getRoundingIncrementForUsage(currency, UCURR_USAGE_STANDARD, ec);
   1612 }
   1613 
   1614 U_DRAFT double U_EXPORT2
   1615 ucurr_getRoundingIncrementForUsage(const UChar* currency, const UCurrencyUsage usage, UErrorCode* ec) {
   1616     double result = 0.0;
   1617 
   1618     const int32_t *data = _findMetaData(currency, *ec);
   1619     if (U_SUCCESS(*ec)) {
   1620         int32_t fracDigits;
   1621         int32_t increment;
   1622         switch (usage) {
   1623             case UCURR_USAGE_STANDARD:
   1624                 fracDigits = data[0];
   1625                 increment = data[1];
   1626                 break;
   1627             case UCURR_USAGE_CASH:
   1628                 fracDigits = data[2];
   1629                 increment = data[3];
   1630                 break;
   1631             default:
   1632                 *ec = U_UNSUPPORTED_ERROR;
   1633                 return result;
   1634         }
   1635 
   1636         // If the meta data is invalid, return 0.0
   1637         if (fracDigits < 0 || fracDigits > MAX_POW10) {
   1638             *ec = U_INVALID_FORMAT_ERROR;
   1639         } else {
   1640             // A rounding value of 0 or 1 indicates no rounding.
   1641             if (increment >= 2) {
   1642                 // Return (increment) / 10^(fracDigits).  The only actual rounding data,
   1643                 // as of this writing, is CHF { 2, 5 }.
   1644                 result = double(increment) / POW10[fracDigits];
   1645             }
   1646         }
   1647     }
   1648 
   1649     return result;
   1650 }
   1651 
   1652 U_CDECL_BEGIN
   1653 
   1654 typedef struct UCurrencyContext {
   1655     uint32_t currType; /* UCurrCurrencyType */
   1656     uint32_t listIdx;
   1657 } UCurrencyContext;
   1658 
   1659 /*
   1660 Please keep this list in alphabetical order.
   1661 You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
   1662 of these items.
   1663 ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
   1664 */
   1665 static const struct CurrencyList {
   1666     const char *currency;
   1667     uint32_t currType;
   1668 } gCurrencyList[] = {
   1669     {"ADP", UCURR_COMMON|UCURR_DEPRECATED},
   1670     {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1671     {"AFA", UCURR_COMMON|UCURR_DEPRECATED},
   1672     {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1673     {"ALK", UCURR_COMMON|UCURR_DEPRECATED},
   1674     {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1675     {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1676     {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1677     {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1678     {"AOK", UCURR_COMMON|UCURR_DEPRECATED},
   1679     {"AON", UCURR_COMMON|UCURR_DEPRECATED},
   1680     {"AOR", UCURR_COMMON|UCURR_DEPRECATED},
   1681     {"ARA", UCURR_COMMON|UCURR_DEPRECATED},
   1682     {"ARL", UCURR_COMMON|UCURR_DEPRECATED},
   1683     {"ARM", UCURR_COMMON|UCURR_DEPRECATED},
   1684     {"ARP", UCURR_COMMON|UCURR_DEPRECATED},
   1685     {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1686     {"ATS", UCURR_COMMON|UCURR_DEPRECATED},
   1687     {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1688     {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1689     {"AZM", UCURR_COMMON|UCURR_DEPRECATED},
   1690     {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1691     {"BAD", UCURR_COMMON|UCURR_DEPRECATED},
   1692     {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1693     {"BAN", UCURR_COMMON|UCURR_DEPRECATED},
   1694     {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1695     {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1696     {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1697     {"BEF", UCURR_COMMON|UCURR_DEPRECATED},
   1698     {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1699     {"BGL", UCURR_COMMON|UCURR_DEPRECATED},
   1700     {"BGM", UCURR_COMMON|UCURR_DEPRECATED},
   1701     {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1702     {"BGO", UCURR_COMMON|UCURR_DEPRECATED},
   1703     {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1704     {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1705     {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1706     {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1707     {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1708     {"BOL", UCURR_COMMON|UCURR_DEPRECATED},
   1709     {"BOP", UCURR_COMMON|UCURR_DEPRECATED},
   1710     {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1711     {"BRB", UCURR_COMMON|UCURR_DEPRECATED},
   1712     {"BRC", UCURR_COMMON|UCURR_DEPRECATED},
   1713     {"BRE", UCURR_COMMON|UCURR_DEPRECATED},
   1714     {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1715     {"BRN", UCURR_COMMON|UCURR_DEPRECATED},
   1716     {"BRR", UCURR_COMMON|UCURR_DEPRECATED},
   1717     {"BRZ", UCURR_COMMON|UCURR_DEPRECATED},
   1718     {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1719     {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1720     {"BUK", UCURR_COMMON|UCURR_DEPRECATED},
   1721     {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1722     {"BYB", UCURR_COMMON|UCURR_DEPRECATED},
   1723     {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1724     {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1725     {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1726     {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1727     {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1728     {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1729     {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1730     {"CLE", UCURR_COMMON|UCURR_DEPRECATED},
   1731     {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1732     {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1733     {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1734     {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1735     {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1736     {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1737     {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1738     {"CSD", UCURR_COMMON|UCURR_DEPRECATED},
   1739     {"CSK", UCURR_COMMON|UCURR_DEPRECATED},
   1740     {"CUC", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1741     {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1742     {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1743     {"CYP", UCURR_COMMON|UCURR_DEPRECATED},
   1744     {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1745     {"DDM", UCURR_COMMON|UCURR_DEPRECATED},
   1746     {"DEM", UCURR_COMMON|UCURR_DEPRECATED},
   1747     {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1748     {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1749     {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1750     {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1751     {"ECS", UCURR_COMMON|UCURR_DEPRECATED},
   1752     {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1753     {"EEK", UCURR_COMMON|UCURR_DEPRECATED},
   1754     {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1755     {"EQE", UCURR_COMMON|UCURR_DEPRECATED},
   1756     {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1757     {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1758     {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1759     {"ESP", UCURR_COMMON|UCURR_DEPRECATED},
   1760     {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1761     {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1762     {"FIM", UCURR_COMMON|UCURR_DEPRECATED},
   1763     {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1764     {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1765     {"FRF", UCURR_COMMON|UCURR_DEPRECATED},
   1766     {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1767     {"GEK", UCURR_COMMON|UCURR_DEPRECATED},
   1768     {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1769     {"GHC", UCURR_COMMON|UCURR_DEPRECATED},
   1770     {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1771     {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1772     {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1773     {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1774     {"GNS", UCURR_COMMON|UCURR_DEPRECATED},
   1775     {"GQE", UCURR_COMMON|UCURR_DEPRECATED},
   1776     {"GRD", UCURR_COMMON|UCURR_DEPRECATED},
   1777     {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1778     {"GWE", UCURR_COMMON|UCURR_DEPRECATED},
   1779     {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1780     {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1781     {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1782     {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1783     {"HRD", UCURR_COMMON|UCURR_DEPRECATED},
   1784     {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1785     {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1786     {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1787     {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1788     {"IEP", UCURR_COMMON|UCURR_DEPRECATED},
   1789     {"ILP", UCURR_COMMON|UCURR_DEPRECATED},
   1790     {"ILR", UCURR_COMMON|UCURR_DEPRECATED},
   1791     {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1792     {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1793     {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1794     {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1795     {"ISJ", UCURR_COMMON|UCURR_DEPRECATED},
   1796     {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1797     {"ITL", UCURR_COMMON|UCURR_DEPRECATED},
   1798     {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1799     {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1800     {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1801     {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1802     {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1803     {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1804     {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1805     {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1806     {"KRH", UCURR_COMMON|UCURR_DEPRECATED},
   1807     {"KRO", UCURR_COMMON|UCURR_DEPRECATED},
   1808     {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1809     {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1810     {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1811     {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1812     {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1813     {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1814     {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1815     {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1816     {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1817     {"LSM", UCURR_COMMON|UCURR_DEPRECATED},
   1818     {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1819     {"LTT", UCURR_COMMON|UCURR_DEPRECATED},
   1820     {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1821     {"LUF", UCURR_COMMON|UCURR_DEPRECATED},
   1822     {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1823     {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1824     {"LVR", UCURR_COMMON|UCURR_DEPRECATED},
   1825     {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1826     {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1827     {"MAF", UCURR_COMMON|UCURR_DEPRECATED},
   1828     {"MCF", UCURR_COMMON|UCURR_DEPRECATED},
   1829     {"MDC", UCURR_COMMON|UCURR_DEPRECATED},
   1830     {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1831     {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1832     {"MGF", UCURR_COMMON|UCURR_DEPRECATED},
   1833     {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1834     {"MKN", UCURR_COMMON|UCURR_DEPRECATED},
   1835     {"MLF", UCURR_COMMON|UCURR_DEPRECATED},
   1836     {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1837     {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1838     {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1839     {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1840     {"MTL", UCURR_COMMON|UCURR_DEPRECATED},
   1841     {"MTP", UCURR_COMMON|UCURR_DEPRECATED},
   1842     {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1843     {"MVP", UCURR_COMMON|UCURR_DEPRECATED},
   1844     {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1845     {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1846     {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1847     {"MXP", UCURR_COMMON|UCURR_DEPRECATED},
   1848     {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1849     {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1850     {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1851     {"MZM", UCURR_COMMON|UCURR_DEPRECATED},
   1852     {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1853     {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1854     {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1855     {"NIC", UCURR_COMMON|UCURR_DEPRECATED},
   1856     {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1857     {"NLG", UCURR_COMMON|UCURR_DEPRECATED},
   1858     {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1859     {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1860     {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1861     {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1862     {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1863     {"PEI", UCURR_COMMON|UCURR_DEPRECATED},
   1864     {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1865     {"PES", UCURR_COMMON|UCURR_DEPRECATED},
   1866     {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1867     {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1868     {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1869     {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1870     {"PLZ", UCURR_COMMON|UCURR_DEPRECATED},
   1871     {"PTE", UCURR_COMMON|UCURR_DEPRECATED},
   1872     {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1873     {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1874     {"RHD", UCURR_COMMON|UCURR_DEPRECATED},
   1875     {"ROL", UCURR_COMMON|UCURR_DEPRECATED},
   1876     {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1877     {"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1878     {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1879     {"RUR", UCURR_COMMON|UCURR_DEPRECATED},
   1880     {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1881     {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1882     {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1883     {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1884     {"SDD", UCURR_COMMON|UCURR_DEPRECATED},
   1885     {"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1886     {"SDP", UCURR_COMMON|UCURR_DEPRECATED},
   1887     {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1888     {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1889     {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1890     {"SIT", UCURR_COMMON|UCURR_DEPRECATED},
   1891     {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1892     {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1893     {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1894     {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1895     {"SRG", UCURR_COMMON|UCURR_DEPRECATED},
   1896     {"SSP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1897     {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1898     {"SUR", UCURR_COMMON|UCURR_DEPRECATED},
   1899     {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1900     {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1901     {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1902     {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1903     {"TJR", UCURR_COMMON|UCURR_DEPRECATED},
   1904     {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1905     {"TMM", UCURR_COMMON|UCURR_DEPRECATED},
   1906     {"TMT", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1907     {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1908     {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1909     {"TPE", UCURR_COMMON|UCURR_DEPRECATED},
   1910     {"TRL", UCURR_COMMON|UCURR_DEPRECATED},
   1911     {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1912     {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1913     {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1914     {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1915     {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1916     {"UAK", UCURR_COMMON|UCURR_DEPRECATED},
   1917     {"UGS", UCURR_COMMON|UCURR_DEPRECATED},
   1918     {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1919     {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1920     {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1921     {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1922     {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1923     {"UYP", UCURR_COMMON|UCURR_DEPRECATED},
   1924     {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1925     {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1926     {"VEB", UCURR_COMMON|UCURR_DEPRECATED},
   1927     {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1928     {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1929     {"VNN", UCURR_COMMON|UCURR_DEPRECATED},
   1930     {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1931     {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1932     {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1933     {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1934     {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1935     {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1936     {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1937     {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1938     {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1939     {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1940     {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1941     {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
   1942     {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1943     {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1944     {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1945     {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1946     {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1947     {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1948     {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1949     {"XSU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1950     {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1951     {"XUA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1952     {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1953     {"YDD", UCURR_COMMON|UCURR_DEPRECATED},
   1954     {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1955     {"YUD", UCURR_COMMON|UCURR_DEPRECATED},
   1956     {"YUM", UCURR_COMMON|UCURR_DEPRECATED},
   1957     {"YUN", UCURR_COMMON|UCURR_DEPRECATED},
   1958     {"YUR", UCURR_COMMON|UCURR_DEPRECATED},
   1959     {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
   1960     {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1961     {"ZMK", UCURR_COMMON|UCURR_DEPRECATED},
   1962     {"ZMW", UCURR_COMMON|UCURR_NON_DEPRECATED},
   1963     {"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
   1964     {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
   1965     {"ZWL", UCURR_COMMON|UCURR_DEPRECATED},
   1966     {"ZWR", UCURR_COMMON|UCURR_DEPRECATED},
   1967     {"ZWD", UCURR_COMMON|UCURR_DEPRECATED},
   1968     { NULL, 0 } // Leave here to denote the end of the list.
   1969 };
   1970 
   1971 #define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
   1972     ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
   1973 
   1974 static int32_t U_CALLCONV
   1975 ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
   1976     UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
   1977     uint32_t currType = myContext->currType;
   1978     int32_t count = 0;
   1979 
   1980     /* Count the number of items matching the type we are looking for. */
   1981     for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
   1982         if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
   1983             count++;
   1984         }
   1985     }
   1986     return count;
   1987 }
   1988 
   1989 static const char* U_CALLCONV
   1990 ucurr_nextCurrencyList(UEnumeration *enumerator,
   1991                         int32_t* resultLength,
   1992                         UErrorCode * /*pErrorCode*/)
   1993 {
   1994     UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
   1995 
   1996     /* Find the next in the list that matches the type we are looking for. */
   1997     while (myContext->listIdx < UPRV_LENGTHOF(gCurrencyList)-1) {
   1998         const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
   1999         if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
   2000         {
   2001             if (resultLength) {
   2002                 *resultLength = 3; /* Currency codes are only 3 chars long */
   2003             }
   2004             return currItem->currency;
   2005         }
   2006     }
   2007     /* We enumerated too far. */
   2008     if (resultLength) {
   2009         *resultLength = 0;
   2010     }
   2011     return NULL;
   2012 }
   2013 
   2014 static void U_CALLCONV
   2015 ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
   2016     ((UCurrencyContext *)(enumerator->context))->listIdx = 0;
   2017 }
   2018 
   2019 static void U_CALLCONV
   2020 ucurr_closeCurrencyList(UEnumeration *enumerator) {
   2021     uprv_free(enumerator->context);
   2022     uprv_free(enumerator);
   2023 }
   2024 
   2025 static void U_CALLCONV
   2026 ucurr_createCurrencyList(UHashtable *isoCodes, UErrorCode* status){
   2027     UErrorCode localStatus = U_ZERO_ERROR;
   2028 
   2029     // Look up the CurrencyMap element in the root bundle.
   2030     UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
   2031     UResourceBundle *currencyMapArray = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
   2032 
   2033     if (U_SUCCESS(localStatus)) {
   2034         // process each entry in currency map
   2035         for (int32_t i=0; i<ures_getSize(currencyMapArray); i++) {
   2036             // get the currency resource
   2037             UResourceBundle *currencyArray = ures_getByIndex(currencyMapArray, i, NULL, &localStatus);
   2038             // process each currency
   2039             if (U_SUCCESS(localStatus)) {
   2040                 for (int32_t j=0; j<ures_getSize(currencyArray); j++) {
   2041                     // get the currency resource
   2042                     UResourceBundle *currencyRes = ures_getByIndex(currencyArray, j, NULL, &localStatus);
   2043                     IsoCodeEntry *entry = (IsoCodeEntry*)uprv_malloc(sizeof(IsoCodeEntry));
   2044                     if (entry == NULL) {
   2045                         *status = U_MEMORY_ALLOCATION_ERROR;
   2046                         return;
   2047                     }
   2048 
   2049                     // get the ISO code
   2050                     int32_t isoLength = 0;
   2051                     UResourceBundle *idRes = ures_getByKey(currencyRes, "id", NULL, &localStatus);
   2052                     if (idRes == NULL) {
   2053                         continue;
   2054                     }
   2055                     const UChar *isoCode = ures_getString(idRes, &isoLength, &localStatus);
   2056 
   2057                     // get from date
   2058                     UDate fromDate = U_DATE_MIN;
   2059                     UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
   2060 
   2061                     if (U_SUCCESS(localStatus)) {
   2062                         int32_t fromLength = 0;
   2063                         const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
   2064                         int64_t currDate64 = (int64_t)fromArray[0] << 32;
   2065                         currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2066                         fromDate = (UDate)currDate64;
   2067                     }
   2068                     ures_close(fromRes);
   2069 
   2070                     // get to date
   2071                     UDate toDate = U_DATE_MAX;
   2072                     localStatus = U_ZERO_ERROR;
   2073                     UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
   2074 
   2075                     if (U_SUCCESS(localStatus)) {
   2076                         int32_t toLength = 0;
   2077                         const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
   2078                         int64_t currDate64 = (int64_t)toArray[0] << 32;
   2079                         currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2080                         toDate = (UDate)currDate64;
   2081                     }
   2082                     ures_close(toRes);
   2083 
   2084                     ures_close(idRes);
   2085                     ures_close(currencyRes);
   2086 
   2087                     entry->isoCode = isoCode;
   2088                     entry->from = fromDate;
   2089                     entry->to = toDate;
   2090 
   2091                     localStatus = U_ZERO_ERROR;
   2092                     uhash_put(isoCodes, (UChar *)isoCode, entry, &localStatus);
   2093                 }
   2094             } else {
   2095                 *status = localStatus;
   2096             }
   2097             ures_close(currencyArray);
   2098         }
   2099     } else {
   2100         *status = localStatus;
   2101     }
   2102 
   2103     ures_close(currencyMapArray);
   2104 }
   2105 
   2106 static const UEnumeration gEnumCurrencyList = {
   2107     NULL,
   2108     NULL,
   2109     ucurr_closeCurrencyList,
   2110     ucurr_countCurrencyList,
   2111     uenum_unextDefault,
   2112     ucurr_nextCurrencyList,
   2113     ucurr_resetCurrencyList
   2114 };
   2115 U_CDECL_END
   2116 
   2117 
   2118 static void U_CALLCONV initIsoCodes(UErrorCode &status) {
   2119     U_ASSERT(gIsoCodes == NULL);
   2120     ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cleanup);
   2121 
   2122     UHashtable *isoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
   2123     if (U_FAILURE(status)) {
   2124         return;
   2125     }
   2126     uhash_setValueDeleter(isoCodes, deleteIsoCodeEntry);
   2127 
   2128     ucurr_createCurrencyList(isoCodes, &status);
   2129     if (U_FAILURE(status)) {
   2130         uhash_close(isoCodes);
   2131         return;
   2132     }
   2133     gIsoCodes = isoCodes;  // Note: gIsoCodes is const. Once set up here it is never altered,
   2134                            //       and read only access is safe without synchronization.
   2135 }
   2136 
   2137 static void populateCurrSymbolsEquiv(icu::Hashtable *hash, UErrorCode &status) {
   2138     if (U_FAILURE(status)) {
   2139         return;
   2140     }
   2141     int32_t length = UPRV_LENGTHOF(EQUIV_CURRENCY_SYMBOLS);
   2142     for (int32_t i = 0; i < length; ++i) {
   2143         icu::UnicodeString lhs(EQUIV_CURRENCY_SYMBOLS[i][0], -1, US_INV);
   2144         icu::UnicodeString rhs(EQUIV_CURRENCY_SYMBOLS[i][1], -1, US_INV);
   2145         makeEquivalent(lhs.unescape(), rhs.unescape(), hash, status);
   2146         if (U_FAILURE(status)) {
   2147             return;
   2148         }
   2149     }
   2150 }
   2151 
   2152 static void U_CALLCONV initCurrSymbolsEquiv() {
   2153     U_ASSERT(gCurrSymbolsEquiv == NULL);
   2154     UErrorCode status = U_ZERO_ERROR;
   2155     ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cleanup);
   2156     icu::Hashtable *temp = new icu::Hashtable(status);
   2157     if (temp == NULL) {
   2158         return;
   2159     }
   2160     if (U_FAILURE(status)) {
   2161         delete temp;
   2162         return;
   2163     }
   2164     temp->setValueDeleter(deleteUnicode);
   2165     populateCurrSymbolsEquiv(temp, status);
   2166     if (U_FAILURE(status)) {
   2167         delete temp;
   2168         return;
   2169     }
   2170     gCurrSymbolsEquiv = temp;
   2171 }
   2172 
   2173 U_CAPI UBool U_EXPORT2
   2174 ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
   2175     umtx_initOnce(gIsoCodesInitOnce, &initIsoCodes, *eErrorCode);
   2176     if (U_FAILURE(*eErrorCode)) {
   2177         return FALSE;
   2178     }
   2179 
   2180     IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
   2181     if (result == NULL) {
   2182         return FALSE;
   2183     } else if (from > to) {
   2184         *eErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
   2185         return FALSE;
   2186     } else if  ((from > result->to) || (to < result->from)) {
   2187         return FALSE;
   2188     }
   2189     return TRUE;
   2190 }
   2191 
   2192 static const icu::Hashtable* getCurrSymbolsEquiv() {
   2193     umtx_initOnce(gCurrSymbolsEquivInitOnce, &initCurrSymbolsEquiv);
   2194     return gCurrSymbolsEquiv;
   2195 }
   2196 
   2197 U_CAPI UEnumeration * U_EXPORT2
   2198 ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
   2199     UEnumeration *myEnum = NULL;
   2200     UCurrencyContext *myContext;
   2201 
   2202     myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
   2203     if (myEnum == NULL) {
   2204         *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
   2205         return NULL;
   2206     }
   2207     uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
   2208     myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
   2209     if (myContext == NULL) {
   2210         *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
   2211         uprv_free(myEnum);
   2212         return NULL;
   2213     }
   2214     myContext->currType = currType;
   2215     myContext->listIdx = 0;
   2216     myEnum->context = myContext;
   2217     return myEnum;
   2218 }
   2219 
   2220 U_CAPI int32_t U_EXPORT2
   2221 ucurr_countCurrencies(const char* locale,
   2222                  UDate date,
   2223                  UErrorCode* ec)
   2224 {
   2225     int32_t currCount = 0;
   2226 
   2227     if (ec != NULL && U_SUCCESS(*ec))
   2228     {
   2229         // local variables
   2230         UErrorCode localStatus = U_ZERO_ERROR;
   2231         char id[ULOC_FULLNAME_CAPACITY];
   2232         uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
   2233 
   2234         // get country or country_variant in `id'
   2235         /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
   2236 
   2237         if (U_FAILURE(*ec))
   2238         {
   2239             return 0;
   2240         }
   2241 
   2242         // Remove variants, which is only needed for registration.
   2243         char *idDelim = strchr(id, VAR_DELIM);
   2244         if (idDelim)
   2245         {
   2246             idDelim[0] = 0;
   2247         }
   2248 
   2249         // Look up the CurrencyMap element in the root bundle.
   2250         UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
   2251         UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
   2252 
   2253         // Using the id derived from the local, get the currency data
   2254         UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
   2255 
   2256         // process each currency to see which one is valid for the given date
   2257         if (U_SUCCESS(localStatus))
   2258         {
   2259             for (int32_t i=0; i<ures_getSize(countryArray); i++)
   2260             {
   2261                 // get the currency resource
   2262                 UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
   2263 
   2264                 // get the from date
   2265                 int32_t fromLength = 0;
   2266                 UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
   2267                 const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
   2268 
   2269                 int64_t currDate64 = (int64_t)fromArray[0] << 32;
   2270                 currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2271                 UDate fromDate = (UDate)currDate64;
   2272 
   2273                 if (ures_getSize(currencyRes)> 2)
   2274                 {
   2275                     int32_t toLength = 0;
   2276                     UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
   2277                     const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
   2278 
   2279                     currDate64 = (int64_t)toArray[0] << 32;
   2280                     currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2281                     UDate toDate = (UDate)currDate64;
   2282 
   2283                     if ((fromDate <= date) && (date < toDate))
   2284                     {
   2285                         currCount++;
   2286                     }
   2287 
   2288                     ures_close(toRes);
   2289                 }
   2290                 else
   2291                 {
   2292                     if (fromDate <= date)
   2293                     {
   2294                         currCount++;
   2295                     }
   2296                 }
   2297 
   2298                 // close open resources
   2299                 ures_close(currencyRes);
   2300                 ures_close(fromRes);
   2301 
   2302             } // end For loop
   2303         } // end if (U_SUCCESS(localStatus))
   2304 
   2305         ures_close(countryArray);
   2306 
   2307         // Check for errors
   2308         if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
   2309         {
   2310             // There is nothing to fallback to.
   2311             // Report the failure/warning if possible.
   2312             *ec = localStatus;
   2313         }
   2314 
   2315         if (U_SUCCESS(*ec))
   2316         {
   2317             // no errors
   2318             return currCount;
   2319         }
   2320 
   2321     }
   2322 
   2323     // If we got here, either error code is invalid or
   2324     // some argument passed is no good.
   2325     return 0;
   2326 }
   2327 
   2328 U_CAPI int32_t U_EXPORT2
   2329 ucurr_forLocaleAndDate(const char* locale,
   2330                 UDate date,
   2331                 int32_t index,
   2332                 UChar* buff,
   2333                 int32_t buffCapacity,
   2334                 UErrorCode* ec)
   2335 {
   2336     int32_t resLen = 0;
   2337 	int32_t currIndex = 0;
   2338     const UChar* s = NULL;
   2339 
   2340     if (ec != NULL && U_SUCCESS(*ec))
   2341     {
   2342         // check the arguments passed
   2343         if ((buff && buffCapacity) || !buffCapacity )
   2344         {
   2345             // local variables
   2346             UErrorCode localStatus = U_ZERO_ERROR;
   2347             char id[ULOC_FULLNAME_CAPACITY];
   2348             resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
   2349 
   2350             // get country or country_variant in `id'
   2351             /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
   2352             if (U_FAILURE(*ec))
   2353             {
   2354                 return 0;
   2355             }
   2356 
   2357             // Remove variants, which is only needed for registration.
   2358             char *idDelim = strchr(id, VAR_DELIM);
   2359             if (idDelim)
   2360             {
   2361                 idDelim[0] = 0;
   2362             }
   2363 
   2364             // Look up the CurrencyMap element in the root bundle.
   2365             UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
   2366             UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
   2367 
   2368             // Using the id derived from the local, get the currency data
   2369             UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
   2370 
   2371             // process each currency to see which one is valid for the given date
   2372             bool matchFound = false;
   2373             if (U_SUCCESS(localStatus))
   2374             {
   2375                 if ((index <= 0) || (index> ures_getSize(countryArray)))
   2376                 {
   2377                     // requested index is out of bounds
   2378                     ures_close(countryArray);
   2379                     return 0;
   2380                 }
   2381 
   2382                 for (int32_t i=0; i<ures_getSize(countryArray); i++)
   2383                 {
   2384                     // get the currency resource
   2385                     UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
   2386                     s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
   2387 
   2388                     // get the from date
   2389                     int32_t fromLength = 0;
   2390                     UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
   2391                     const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
   2392 
   2393                     int64_t currDate64 = (int64_t)fromArray[0] << 32;
   2394                     currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2395                     UDate fromDate = (UDate)currDate64;
   2396 
   2397                     if (ures_getSize(currencyRes)> 2)
   2398                     {
   2399                         int32_t toLength = 0;
   2400                         UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
   2401                         const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
   2402 
   2403                         currDate64 = (int64_t)toArray[0] << 32;
   2404                         currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
   2405                         UDate toDate = (UDate)currDate64;
   2406 
   2407                         if ((fromDate <= date) && (date < toDate))
   2408                         {
   2409                             currIndex++;
   2410                             if (currIndex == index)
   2411                             {
   2412                                 matchFound = true;
   2413                             }
   2414                         }
   2415 
   2416                         ures_close(toRes);
   2417                     }
   2418                     else
   2419                     {
   2420                         if (fromDate <= date)
   2421                         {
   2422                             currIndex++;
   2423                             if (currIndex == index)
   2424                             {
   2425                                 matchFound = true;
   2426                             }
   2427                         }
   2428                     }
   2429 
   2430                     // close open resources
   2431                     ures_close(currencyRes);
   2432                     ures_close(fromRes);
   2433 
   2434                     // check for loop exit
   2435                     if (matchFound)
   2436                     {
   2437                         break;
   2438                     }
   2439 
   2440                 } // end For loop
   2441             }
   2442 
   2443             ures_close(countryArray);
   2444 
   2445             // Check for errors
   2446             if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
   2447             {
   2448                 // There is nothing to fallback to.
   2449                 // Report the failure/warning if possible.
   2450                 *ec = localStatus;
   2451             }
   2452 
   2453             if (U_SUCCESS(*ec))
   2454             {
   2455                 // no errors
   2456                 if((buffCapacity> resLen) && matchFound)
   2457                 {
   2458                     // write out the currency value
   2459                     u_strcpy(buff, s);
   2460                 }
   2461                 else
   2462                 {
   2463                     return 0;
   2464                 }
   2465             }
   2466 
   2467             // return null terminated currency string
   2468             return u_terminateUChars(buff, buffCapacity, resLen, ec);
   2469         }
   2470         else
   2471         {
   2472             // illegal argument encountered
   2473             *ec = U_ILLEGAL_ARGUMENT_ERROR;
   2474         }
   2475 
   2476     }
   2477 
   2478     // If we got here, either error code is invalid or
   2479     // some argument passed is no good.
   2480     return resLen;
   2481 }
   2482 
   2483 static const UEnumeration defaultKeywordValues = {
   2484     NULL,
   2485     NULL,
   2486     ulist_close_keyword_values_iterator,
   2487     ulist_count_keyword_values,
   2488     uenum_unextDefault,
   2489     ulist_next_keyword_value,
   2490     ulist_reset_keyword_values_iterator
   2491 };
   2492 
   2493 U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key, const char *locale, UBool commonlyUsed, UErrorCode* status) {
   2494     // Resolve region
   2495     char prefRegion[ULOC_COUNTRY_CAPACITY];
   2496     ulocimp_getRegionForSupplementalData(locale, TRUE, prefRegion, sizeof(prefRegion), status);
   2497 
   2498     // Read value from supplementalData
   2499     UList *values = ulist_createEmptyList(status);
   2500     UList *otherValues = ulist_createEmptyList(status);
   2501     UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
   2502     if (U_FAILURE(*status) || en == NULL) {
   2503         if (en == NULL) {
   2504             *status = U_MEMORY_ALLOCATION_ERROR;
   2505         } else {
   2506             uprv_free(en);
   2507         }
   2508         ulist_deleteList(values);
   2509         ulist_deleteList(otherValues);
   2510         return NULL;
   2511     }
   2512     memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
   2513     en->context = values;
   2514 
   2515     UResourceBundle *bundle = ures_openDirect(U_ICUDATA_CURR, "supplementalData", status);
   2516     ures_getByKey(bundle, "CurrencyMap", bundle, status);
   2517     UResourceBundle bundlekey, regbndl, curbndl, to;
   2518     ures_initStackObject(&bundlekey);
   2519     ures_initStackObject(&regbndl);
   2520     ures_initStackObject(&curbndl);
   2521     ures_initStackObject(&to);
   2522 
   2523     while (U_SUCCESS(*status) && ures_hasNext(bundle)) {
   2524         ures_getNextResource(bundle, &bundlekey, status);
   2525         if (U_FAILURE(*status)) {
   2526             break;
   2527         }
   2528         const char *region = ures_getKey(&bundlekey);
   2529         UBool isPrefRegion = uprv_strcmp(region, prefRegion) == 0 ? TRUE : FALSE;
   2530         if (!isPrefRegion && commonlyUsed) {
   2531             // With commonlyUsed=true, we do not put
   2532             // currencies for other regions in the
   2533             // result list.
   2534             continue;
   2535         }
   2536         ures_getByKey(bundle, region, &regbndl, status);
   2537         if (U_FAILURE(*status)) {
   2538             break;
   2539         }
   2540         while (U_SUCCESS(*status) && ures_hasNext(&regbndl)) {
   2541             ures_getNextResource(&regbndl, &curbndl, status);
   2542             if (ures_getType(&curbndl) != URES_TABLE) {
   2543                 // Currently, an empty ARRAY is mixed in.
   2544                 continue;
   2545             }
   2546             char *curID = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
   2547             int32_t curIDLength = ULOC_KEYWORDS_CAPACITY;
   2548             if (curID == NULL) {
   2549                 *status = U_MEMORY_ALLOCATION_ERROR;
   2550                 break;
   2551             }
   2552 
   2553 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
   2554             ures_getUTF8StringByKey(&curbndl, "id", curID, &curIDLength, TRUE, status);
   2555             /* optimize - use the utf-8 string */
   2556 #else
   2557             {
   2558                        const UChar* defString = ures_getStringByKey(&curbndl, "id", &curIDLength, status);
   2559                        if(U_SUCCESS(*status)) {
   2560 			   if(curIDLength+1 > ULOC_KEYWORDS_CAPACITY) {
   2561 				*status = U_BUFFER_OVERFLOW_ERROR;
   2562 			   } else {
   2563                            	u_UCharsToChars(defString, curID, curIDLength+1);
   2564 			   }
   2565                        }
   2566             }
   2567 #endif
   2568 
   2569             if (U_FAILURE(*status)) {
   2570                 break;
   2571             }
   2572             UBool hasTo = FALSE;
   2573             ures_getByKey(&curbndl, "to", &to, status);
   2574             if (U_FAILURE(*status)) {
   2575                 // Do nothing here...
   2576                 *status = U_ZERO_ERROR;
   2577             } else {
   2578                 hasTo = TRUE;
   2579             }
   2580             if (isPrefRegion && !hasTo && !ulist_containsString(values, curID, (int32_t)uprv_strlen(curID))) {
   2581                 // Currently active currency for the target country
   2582                 ulist_addItemEndList(values, curID, TRUE, status);
   2583             } else if (!ulist_containsString(otherValues, curID, (int32_t)uprv_strlen(curID)) && !commonlyUsed) {
   2584                 ulist_addItemEndList(otherValues, curID, TRUE, status);
   2585             } else {
   2586                 uprv_free(curID);
   2587             }
   2588         }
   2589 
   2590     }
   2591     if (U_SUCCESS(*status)) {
   2592         if (commonlyUsed) {
   2593             if (ulist_getListSize(values) == 0) {
   2594                 // This could happen if no valid region is supplied in the input
   2595                 // locale. In this case, we use the CLDR's default.
   2596                 uenum_close(en);
   2597                 en = ucurr_getKeywordValuesForLocale(key, "und", TRUE, status);
   2598             }
   2599         } else {
   2600             // Consolidate the list
   2601             char *value = NULL;
   2602             ulist_resetList(otherValues);
   2603             while ((value = (char *)ulist_getNext(otherValues)) != NULL) {
   2604                 if (!ulist_containsString(values, value, (int32_t)uprv_strlen(value))) {
   2605                     char *tmpValue = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
   2606                     uprv_memcpy(tmpValue, value, uprv_strlen(value) + 1);
   2607                     ulist_addItemEndList(values, tmpValue, TRUE, status);
   2608                     if (U_FAILURE(*status)) {
   2609                         break;
   2610                     }
   2611                 }
   2612             }
   2613         }
   2614 
   2615         ulist_resetList((UList *)(en->context));
   2616     } else {
   2617         ulist_deleteList(values);
   2618         uprv_free(en);
   2619         values = NULL;
   2620         en = NULL;
   2621     }
   2622     ures_close(&to);
   2623     ures_close(&curbndl);
   2624     ures_close(&regbndl);
   2625     ures_close(&bundlekey);
   2626     ures_close(bundle);
   2627 
   2628     ulist_deleteList(otherValues);
   2629 
   2630     return en;
   2631 }
   2632 
   2633 
   2634 U_CAPI int32_t U_EXPORT2
   2635 ucurr_getNumericCode(const UChar* currency) {
   2636     int32_t code = 0;
   2637     if (currency && u_strlen(currency) == ISO_CURRENCY_CODE_LENGTH) {
   2638         UErrorCode status = U_ZERO_ERROR;
   2639 
   2640         UResourceBundle *bundle = ures_openDirect(0, "currencyNumericCodes", &status);
   2641         ures_getByKey(bundle, "codeMap", bundle, &status);
   2642         if (U_SUCCESS(status)) {
   2643             char alphaCode[ISO_CURRENCY_CODE_LENGTH+1];
   2644             myUCharsToChars(alphaCode, currency);
   2645             T_CString_toUpperCase(alphaCode);
   2646             ures_getByKey(bundle, alphaCode, bundle, &status);
   2647             int tmpCode = ures_getInt(bundle, &status);
   2648             if (U_SUCCESS(status)) {
   2649                 code = tmpCode;
   2650             }
   2651         }
   2652         ures_close(bundle);
   2653     }
   2654     return code;
   2655 }
   2656 #endif /* #if !UCONFIG_NO_FORMATTING */
   2657 
   2658 //eof
   2659