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