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