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