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