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