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