]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/ucurr.cpp
ICU-8.11.tar.gz
[apple/icu.git] / icuSources / i18n / ucurr.cpp
CommitLineData
b75a7d8f
A
1/*
2**********************************************************************
73c04bcf 3* Copyright (c) 2002-2006, International Business Machines
b75a7d8f
A
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"
374ca955 14#include "unicode/ures.h"
b75a7d8f 15#include "unicode/ustring.h"
374ca955
A
16#include "unicode/choicfmt.h"
17#include "unicode/parsepos.h"
18#include "ustr_imp.h"
b75a7d8f
A
19#include "cmemory.h"
20#include "cstring.h"
21#include "uassert.h"
374ca955 22#include "mutex.h"
b75a7d8f 23#include "ucln_in.h"
73c04bcf 24#include "uenumimp.h"
b75a7d8f
A
25
26//------------------------------------------------------------
27// Constants
28
29// Default currency meta data of last resort. We try to use the
30// defaults encoded in the meta data resource bundle. If there is a
31// configuration/build error and these are not available, we use these
32// hard-coded defaults (which should be identical).
33static const int32_t LAST_RESORT_DATA[] = { 2, 0 };
34
35// POW10[i] = 10^i, i=0..MAX_POW10
36static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
37 1000000, 10000000, 100000000, 1000000000 };
38
39static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1;
40
41#define ISO_COUNTRY_CODE_LENGTH 3
42
43//------------------------------------------------------------
44// Resource tags
374ca955 45//
b75a7d8f 46
374ca955 47static const char CURRENCY_DATA[] = "CurrencyData";
b75a7d8f
A
48// Tag for meta-data, in root.
49static const char CURRENCY_META[] = "CurrencyMeta";
50
51// Tag for map from countries to currencies, in root.
52static const char CURRENCY_MAP[] = "CurrencyMap";
53
54// Tag for default meta-data, in CURRENCY_META
55static const char DEFAULT_META[] = "DEFAULT";
56
57// Variant for legacy pre-euro mapping in CurrencyMap
58static const char VAR_PRE_EURO[] = "PREEURO";
59
60// Variant for legacy euro mapping in CurrencyMap
61static const char VAR_EURO[] = "EURO";
62
63// Variant delimiter
64static const char VAR_DELIM[] = "_";
65
374ca955
A
66// Variant for legacy euro mapping in CurrencyMap
67static const char VAR_DELIM_EURO[] = "_EURO";
68
69#define VARIANT_IS_EMPTY 0
70#define VARIANT_IS_EURO 0x1
71#define VARIANT_IS_PREEURO 0x2
72
b75a7d8f
A
73// Tag for localized display names (symbols) of currencies
74static const char CURRENCIES[] = "Currencies";
75
76// Marker character indicating that a display name is a ChoiceFormat
77// pattern. Strings that start with one mark are ChoiceFormat
78// patterns. Strings that start with 2 marks are static strings, and
79// the first mark is deleted.
80static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign
81
82//------------------------------------------------------------
83// Code
84
85/**
86 * Unfortunately, we have to convert the UChar* currency code to char*
87 * to use it as a resource key.
88 */
89static inline char*
90myUCharsToChars(char* resultOfLen4, const UChar* currency) {
91 u_UCharsToChars(currency, resultOfLen4, ISO_COUNTRY_CODE_LENGTH);
92 resultOfLen4[ISO_COUNTRY_CODE_LENGTH] = 0;
93 return resultOfLen4;
94}
95
96/**
97 * Internal function to look up currency data. Result is an array of
98 * two integers. The first is the fraction digits. The second is the
99 * rounding increment, or 0 if none. The rounding increment is in
100 * units of 10^(-fraction_digits).
101 */
102static const int32_t*
374ca955
A
103_findMetaData(const UChar* currency, UErrorCode& ec) {
104
105 if (currency == 0 || *currency == 0) {
106 if (U_SUCCESS(ec)) {
107 ec = U_ILLEGAL_ARGUMENT_ERROR;
108 }
109 return LAST_RESORT_DATA;
110 }
b75a7d8f
A
111
112 // Get CurrencyMeta resource out of root locale file. [This may
113 // move out of the root locale file later; if it does, update this
114 // code.]
374ca955
A
115 UResourceBundle* currencyData = ures_openDirect(NULL, CURRENCY_DATA, &ec);
116 UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec);
117
b75a7d8f 118 if (U_FAILURE(ec)) {
374ca955 119 ures_close(currencyMeta);
b75a7d8f
A
120 // Config/build error; return hard-coded defaults
121 return LAST_RESORT_DATA;
122 }
123
124 // Look up our currency, or if that's not available, then DEFAULT
125 char buf[ISO_COUNTRY_CODE_LENGTH+1];
374ca955
A
126 UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure
127 UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2);
128 if (U_FAILURE(ec2)) {
129 ures_close(rb);
130 rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec);
b75a7d8f 131 if (U_FAILURE(ec)) {
374ca955
A
132 ures_close(currencyMeta);
133 ures_close(rb);
b75a7d8f
A
134 // Config/build error; return hard-coded defaults
135 return LAST_RESORT_DATA;
136 }
137 }
138
139 int32_t len;
374ca955
A
140 const int32_t *data = ures_getIntVector(rb, &len, &ec);
141 if (U_FAILURE(ec) || len != 2) {
b75a7d8f 142 // Config/build error; return hard-coded defaults
374ca955
A
143 if (U_SUCCESS(ec)) {
144 ec = U_INVALID_FORMAT_ERROR;
145 }
146 ures_close(currencyMeta);
147 ures_close(rb);
b75a7d8f
A
148 return LAST_RESORT_DATA;
149 }
150
374ca955
A
151 ures_close(currencyMeta);
152 ures_close(rb);
b75a7d8f
A
153 return data;
154}
155
374ca955
A
156// -------------------------------------
157
158/**
159 * @see VARIANT_IS_EURO
160 * @see VARIANT_IS_PREEURO
161 */
162static uint32_t
163idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec)
164{
165 uint32_t variantType = 0;
166 // !!! this is internal only, assumes buffer is not null and capacity is sufficient
167 // Extract the country name and variant name. We only
168 // recognize two variant names, EURO and PREEURO.
169 char variant[ULOC_FULLNAME_CAPACITY];
170 uloc_getCountry(locale, countryAndVariant, capacity, ec);
171 uloc_getVariant(locale, variant, sizeof(variant), ec);
172 if (variant[0] != 0) {
173 variantType = (0 == uprv_strcmp(variant, VAR_EURO))
174 | ((0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1);
175 if (variantType)
176 {
177 uprv_strcat(countryAndVariant, VAR_DELIM);
178 uprv_strcat(countryAndVariant, variant);
179 }
180 }
181 return variantType;
182}
b75a7d8f
A
183
184// ------------------------------------------
185//
186// Registration
187//
188//-------------------------------------------
189
190// don't use ICUService since we don't need fallback
191
374ca955
A
192#if !UCONFIG_NO_SERVICE
193U_CDECL_BEGIN
194static UBool U_CALLCONV currency_cleanup(void);
195U_CDECL_END
b75a7d8f
A
196struct CReg;
197
198/* Remember to call umtx_init(&gCRegLock) before using it! */
199static UMTX gCRegLock = 0;
200static CReg* gCRegHead = 0;
201
202struct CReg : public UMemory {
203 CReg *next;
204 UChar iso[ISO_COUNTRY_CODE_LENGTH+1];
205 char id[ULOC_FULLNAME_CAPACITY];
374ca955 206
b75a7d8f
A
207 CReg(const UChar* _iso, const char* _id)
208 : next(0)
209 {
374ca955 210 int32_t len = (int32_t)uprv_strlen(_id);
b75a7d8f
A
211 if (len > (int32_t)(sizeof(id)-1)) {
212 len = (sizeof(id)-1);
213 }
214 uprv_strncpy(id, _id, len);
215 id[len] = 0;
216 uprv_memcpy(iso, _iso, ISO_COUNTRY_CODE_LENGTH * sizeof(const UChar));
217 iso[ISO_COUNTRY_CODE_LENGTH] = 0;
218 }
374ca955 219
b75a7d8f
A
220 static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status)
221 {
222 if (status && U_SUCCESS(*status) && _iso && _id) {
223 CReg* n = new CReg(_iso, _id);
224 if (n) {
225 umtx_init(&gCRegLock);
226 Mutex mutex(&gCRegLock);
227 if (!gCRegHead) {
374ca955
A
228 /* register for the first time */
229 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
b75a7d8f
A
230 }
231 n->next = gCRegHead;
232 gCRegHead = n;
233 return n;
234 }
235 *status = U_MEMORY_ALLOCATION_ERROR;
236 }
237 return 0;
238 }
374ca955 239
b75a7d8f
A
240 static UBool unreg(UCurrRegistryKey key) {
241 umtx_init(&gCRegLock);
242 Mutex mutex(&gCRegLock);
243 if (gCRegHead == key) {
244 gCRegHead = gCRegHead->next;
245 delete (CReg*)key;
246 return TRUE;
247 }
374ca955 248
b75a7d8f
A
249 CReg* p = gCRegHead;
250 while (p) {
251 if (p->next == key) {
252 p->next = ((CReg*)key)->next;
374ca955 253 delete (CReg*)key;
b75a7d8f
A
254 return TRUE;
255 }
256 p = p->next;
257 }
374ca955 258
b75a7d8f
A
259 return FALSE;
260 }
374ca955 261
b75a7d8f
A
262 static const UChar* get(const char* id) {
263 umtx_init(&gCRegLock);
264 Mutex mutex(&gCRegLock);
265 CReg* p = gCRegHead;
374ca955
A
266
267 /* register cleanup of the mutex */
268 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
b75a7d8f
A
269 while (p) {
270 if (uprv_strcmp(id, p->id) == 0) {
271 return p->iso;
272 }
273 p = p->next;
274 }
275 return NULL;
276 }
277
278 /* This doesn't need to be thread safe. It's for u_cleanup only. */
279 static void cleanup(void) {
280 while (gCRegHead) {
281 CReg* n = gCRegHead;
282 gCRegHead = gCRegHead->next;
283 delete n;
284 }
285 umtx_destroy(&gCRegLock);
286 }
287};
288
374ca955
A
289/**
290 * Release all static memory held by currency.
291 */
292U_CDECL_BEGIN
293static UBool U_CALLCONV currency_cleanup(void) {
294#if !UCONFIG_NO_SERVICE
295 CReg::cleanup();
296#endif
297 return TRUE;
b75a7d8f 298}
374ca955 299U_CDECL_END
b75a7d8f
A
300
301// -------------------------------------
302
303U_CAPI UCurrRegistryKey U_EXPORT2
374ca955 304ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
b75a7d8f
A
305{
306 if (status && U_SUCCESS(*status)) {
307 char id[ULOC_FULLNAME_CAPACITY];
308 idForLocale(locale, id, sizeof(id), status);
309 return CReg::reg(isoCode, id, status);
310 }
311 return NULL;
312}
313
314// -------------------------------------
315
316U_CAPI UBool U_EXPORT2
374ca955 317ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
b75a7d8f
A
318{
319 if (status && U_SUCCESS(*status)) {
320 return CReg::unreg(key);
321 }
322 return FALSE;
323}
374ca955 324#endif /* UCONFIG_NO_SERVICE */
b75a7d8f
A
325
326// -------------------------------------
327
374ca955
A
328U_CAPI int32_t U_EXPORT2
329ucurr_forLocale(const char* locale,
330 UChar* buff,
331 int32_t buffCapacity,
332 UErrorCode* ec)
333{
334 int32_t resLen = 0;
335 const UChar* s = NULL;
b75a7d8f 336 if (ec != NULL && U_SUCCESS(*ec)) {
374ca955
A
337 if ((buff && buffCapacity) || !buffCapacity) {
338 UErrorCode localStatus = U_ZERO_ERROR;
339 char id[ULOC_FULLNAME_CAPACITY];
340 if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) {
341 // there is a currency keyword. Try to see if it's valid
342 if(buffCapacity > resLen) {
343 u_charsToUChars(id, buff, resLen);
344 }
345 } else {
346 // get country or country_variant in `id'
347 uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
348
349 if (U_FAILURE(*ec)) {
350 return 0;
351 }
352
353#if !UCONFIG_NO_SERVICE
354 const UChar* result = CReg::get(id);
355 if (result) {
356 if(buffCapacity > u_strlen(result)) {
357 u_strcpy(buff, result);
358 }
359 return u_strlen(result);
360 }
361#endif
362
363 // Look up the CurrencyMap element in the root bundle.
364 UResourceBundle *rb = ures_openDirect(NULL, CURRENCY_DATA, &localStatus);
365 UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
366 s = ures_getStringByKey(cm, id, &resLen, &localStatus);
367
368 if ((s == NULL || U_FAILURE(localStatus)) && variantType != VARIANT_IS_EMPTY
369 && (id[0] != 0))
370 {
371 // We don't know about it. Check to see if we support the variant.
372 if (variantType & VARIANT_IS_EURO) {
373 s = ures_getStringByKey(cm, VAR_DELIM_EURO, &resLen, ec);
374 }
375 else {
376 uloc_getParent(locale, id, sizeof(id), ec);
377 *ec = U_USING_FALLBACK_WARNING;
378 ures_close(cm);
379 return ucurr_forLocale(id, buff, buffCapacity, ec);
380 }
381 }
382 else if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) {
383 // There is nothing to fallback to. Report the failure/warning if possible.
384 *ec = localStatus;
385 }
386 if (U_SUCCESS(*ec)) {
387 if(buffCapacity > resLen) {
388 u_strcpy(buff, s);
389 }
390 }
391 ures_close(cm);
392 }
393 return u_terminateUChars(buff, buffCapacity, resLen, ec);
394 } else {
395 *ec = U_ILLEGAL_ARGUMENT_ERROR;
b75a7d8f
A
396 }
397 }
374ca955 398 return resLen;
b75a7d8f
A
399}
400
401// end registration
402
403/**
404 * Modify the given locale name by removing the rightmost _-delimited
405 * element. If there is none, empty the string ("" == root).
406 * NOTE: The string "root" is not recognized; do not use it.
407 * @return TRUE if the fallback happened; FALSE if locale is already
408 * root ("").
409 */
410static UBool fallback(char *loc) {
411 if (!*loc) {
412 return FALSE;
413 }
414 UErrorCode status = U_ZERO_ERROR;
374ca955 415 uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status);
b75a7d8f
A
416 /*
417 char *i = uprv_strrchr(loc, '_');
418 if (i == NULL) {
419 i = loc;
420 }
421 *i = 0;
422 */
423 return TRUE;
424}
425
426
427U_CAPI const UChar* U_EXPORT2
428ucurr_getName(const UChar* currency,
429 const char* locale,
430 UCurrNameStyle nameStyle,
431 UBool* isChoiceFormat, // fillin
432 int32_t* len, // fillin
433 UErrorCode* ec) {
434
435 // Look up the Currencies resource for the given locale. The
436 // Currencies locale data looks like this:
437 //|en {
374ca955 438 //| Currencies {
b75a7d8f
A
439 //| USD { "US$", "US Dollar" }
440 //| CHF { "Sw F", "Swiss Franc" }
441 //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
442 //| //...
443 //| }
444 //|}
445
374ca955 446 if (U_FAILURE(*ec)) {
b75a7d8f
A
447 return 0;
448 }
449
450 int32_t choice = (int32_t) nameStyle;
451 if (choice < 0 || choice > 1) {
452 *ec = U_ILLEGAL_ARGUMENT_ERROR;
453 return 0;
454 }
374ca955 455
b75a7d8f
A
456 // In the future, resource bundles may implement multi-level
457 // fallback. That is, if a currency is not found in the en_US
458 // Currencies data, then the en Currencies data will be searched.
459 // Currently, if a Currencies datum exists in en_US and en, the
460 // en_US entry hides that in en.
461
462 // We want multi-level fallback for this resource, so we implement
463 // it manually.
464
465 // Use a separate UErrorCode here that does not propagate out of
466 // this function.
467 UErrorCode ec2 = U_ZERO_ERROR;
468
469 char loc[ULOC_FULLNAME_CAPACITY];
470 uloc_getName(locale, loc, sizeof(loc), &ec2);
471 if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
472 *ec = U_ILLEGAL_ARGUMENT_ERROR;
473 return 0;
474 }
475
476 char buf[ISO_COUNTRY_CODE_LENGTH+1];
477 myUCharsToChars(buf, currency);
478
479 const UChar* s = NULL;
480
481 // Multi-level resource inheritance fallback loop
482 for (;;) {
483 ec2 = U_ZERO_ERROR;
484 UResourceBundle* rb = ures_open(NULL, loc, &ec2);
374ca955
A
485 rb = ures_getByKey(rb, CURRENCIES, rb, &ec2);
486 rb = ures_getByKey(rb, buf, rb, &ec2);
487 s = ures_getStringByIndex(rb, choice, len, &ec2);
b75a7d8f
A
488 ures_close(rb);
489
490 // If we've succeeded we're done. Otherwise, try to fallback.
491 // If that fails (because we are already at root) then exit.
492 if (U_SUCCESS(ec2) || !fallback(loc)) {
374ca955
A
493 if (ec2 == U_USING_DEFAULT_WARNING
494 || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
495 *ec = ec2;
496 }
b75a7d8f 497 break;
374ca955
A
498 } else if (strlen(loc) == 0) {
499 *ec = U_USING_DEFAULT_WARNING;
500 } else if (*ec != U_USING_DEFAULT_WARNING) {
501 *ec = U_USING_FALLBACK_WARNING;
b75a7d8f
A
502 }
503 }
504
505 // Determine if this is a ChoiceFormat pattern. One leading mark
506 // indicates a ChoiceFormat. Two indicates a static string that
507 // starts with a mark. In either case, the first mark is ignored,
508 // if present. Marks in the rest of the string have no special
509 // meaning.
510 *isChoiceFormat = FALSE;
511 if (U_SUCCESS(ec2)) {
512 U_ASSERT(s != NULL);
513 int32_t i=0;
514 while (i < *len && s[i] == CHOICE_FORMAT_MARK && i < 2) {
515 ++i;
516 }
517 *isChoiceFormat = (i == 1);
518 if (i != 0) ++s; // Skip over first mark
519 return s;
520 }
521
522 // If we fail to find a match, use the ISO 4217 code
523 *len = u_strlen(currency); // Should == ISO_COUNTRY_CODE_LENGTH, but maybe not...?
374ca955 524 *ec = U_USING_DEFAULT_WARNING;
b75a7d8f
A
525 return currency;
526}
527
374ca955
A
528U_NAMESPACE_BEGIN
529
530void
531uprv_parseCurrency(const char* locale,
532 const UnicodeString& text,
533 ParsePosition& pos,
534 UChar* result,
535 UErrorCode& ec) {
536
537 // TODO: There is a slight problem with the pseudo-multi-level
538 // fallback implemented here. More-specific locales don't
539 // properly shield duplicate entries in less-specific locales.
540 // This problem will go away when real multi-level fallback is
541 // implemented. We could also fix this by recording (in a
542 // hash) which codes are used at each level of fallback, but
543 // this doesn't seem warranted.
544
545 if (U_FAILURE(ec)) {
546 return;
547 }
548
549 // Look up the Currencies resource for the given locale. The
550 // Currencies locale data looks like this:
551 //|en {
552 //| Currencies {
553 //| USD { "US$", "US Dollar" }
554 //| CHF { "Sw F", "Swiss Franc" }
555 //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
556 //| //...
557 //| }
558 //|}
559
560 // In the future, resource bundles may implement multi-level
561 // fallback. That is, if a currency is not found in the en_US
562 // Currencies data, then the en Currencies data will be searched.
563 // Currently, if a Currencies datum exists in en_US and en, the
564 // en_US entry hides that in en.
565
566 // We want multi-level fallback for this resource, so we implement
567 // it manually.
568
569 // Use a separate UErrorCode here that does not propagate out of
570 // this function.
571 UErrorCode ec2 = U_ZERO_ERROR;
572
573 char loc[ULOC_FULLNAME_CAPACITY];
574 uloc_getName(locale, loc, sizeof(loc), &ec2);
575 if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
576 ec = U_ILLEGAL_ARGUMENT_ERROR;
577 return;
578 }
579
580 int32_t start = pos.getIndex();
581 const UChar* s = NULL;
582
583 const char* iso = NULL;
584 int32_t max = 0;
585
586 // Multi-level resource inheritance fallback loop
587 for (;;) {
588 ec2 = U_ZERO_ERROR;
589 UResourceBundle* rb = ures_open(NULL, loc, &ec2);
590 UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
591 int32_t n = ures_getSize(curr);
592 for (int32_t i=0; i<n; ++i) {
593 UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
594 int32_t len;
595 s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
596 UBool isChoice = FALSE;
597 if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
598 ++s;
599 --len;
600 if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
601 isChoice = TRUE;
602 }
603 }
604 if (isChoice) {
605 Formattable temp;
606 ChoiceFormat fmt(s, ec2);
607 fmt.parse(text, temp, pos);
608 len = pos.getIndex() - start;
609 pos.setIndex(start);
610 } else if (len > max &&
611 text.compare(pos.getIndex(), len, s) != 0) {
612 len = 0;
613 }
614 if (len > max) {
615 iso = ures_getKey(names);
616 max = len;
617 }
618 ures_close(names);
619 }
620 ures_close(curr);
621 ures_close(rb);
622
623 // Try to fallback. If that fails (because we are already at
624 // root) then exit.
625 if (!fallback(loc)) {
626 break;
627 }
628 }
629
630 if (iso != NULL) {
631 u_charsToUChars(iso, result, 4);
632 }
633
634 // If display name parse fails or if it matches fewer than 3
635 // characters, try to parse 3-letter ISO. Do this after the
636 // display name processing so 3-letter display names are
637 // preferred. Consider /[A-Z]{3}/ to be valid ISO, and parse
638 // it manually--UnicodeSet/regex are too slow and heavy.
639 if (max < 3 && (text.length() - start) >= 3) {
640 UBool valid = TRUE;
641 for (int32_t k=0; k<3; ++k) {
642 UChar ch = text.charAt(start + k); // 16-bit ok
643 if (ch < 0x41/*'A'*/ || ch > 0x5A/*'Z'*/) {
644 valid = FALSE;
645 break;
646 }
647 }
648 if (valid) {
649 text.extract(start, 3, result);
650 result[3] = 0;
651 max = 3;
652 }
653 }
654
655 pos.setIndex(start + max);
656}
657
658U_NAMESPACE_END
659
660/**
661 * Internal method. Given a currency ISO code and a locale, return
662 * the "static" currency name. This is usually the same as the
663 * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
664 * format is applied to the number 2.0 (to yield the more common
665 * plural) to return a static name.
666 *
667 * This is used for backward compatibility with old currency logic in
668 * DecimalFormat and DecimalFormatSymbols.
669 */
670U_CAPI void
671uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
672 UnicodeString& result, UErrorCode& ec)
673{
674 UBool isChoiceFormat;
675 int32_t len;
676 const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME,
677 &isChoiceFormat, &len, &ec);
678 if (U_SUCCESS(ec)) {
679 // If this is a ChoiceFormat currency, then format an
680 // arbitrary value; pick something != 1; more common.
681 result.truncate(0);
682 if (isChoiceFormat) {
683 ChoiceFormat f(currname, ec);
684 if (U_SUCCESS(ec)) {
685 f.format(2.0, result);
686 } else {
687 result = iso;
688 }
689 } else {
690 result = currname;
691 }
692 }
693}
b75a7d8f
A
694
695U_CAPI int32_t U_EXPORT2
374ca955
A
696ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) {
697 return (_findMetaData(currency, *ec))[0];
b75a7d8f
A
698}
699
700U_CAPI double U_EXPORT2
374ca955
A
701ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) {
702 const int32_t *data = _findMetaData(currency, *ec);
b75a7d8f 703
374ca955
A
704 // If the meta data is invalid, return 0.0.
705 if (data[0] < 0 || data[0] > MAX_POW10) {
706 if (U_SUCCESS(*ec)) {
707 *ec = U_INVALID_FORMAT_ERROR;
708 }
709 return 0.0;
710 }
711
712 // If there is no rounding, return 0.0 to indicate no rounding. A
713 // rounding value (data[1]) of 0 or 1 indicates no rounding.
714 if (data[1] < 2) {
b75a7d8f
A
715 return 0.0;
716 }
717
718 // Return data[1] / 10^(data[0]). The only actual rounding data,
719 // as of this writing, is CHF { 2, 5 }.
720 return double(data[1]) / POW10[data[0]];
721}
722
73c04bcf
A
723U_CDECL_BEGIN
724
725typedef struct UCurrencyContext {
726 uint32_t currType; /* UCurrCurrencyType */
727 uint32_t listIdx;
728} UCurrencyContext;
729
730/*
731Please keep this list in alphabetical order.
732You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
733of these items.
734ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
735*/
736static const struct CurrencyList {
737 const char *currency;
738 uint32_t currType;
739} gCurrencyList[] = {
740 {"ADP", UCURR_COMMON|UCURR_DEPRECATED},
741 {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED},
742 {"AFA", UCURR_COMMON|UCURR_DEPRECATED},
743 {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED},
744 {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED},
745 {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
746 {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED},
747 {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED},
748 {"AOK", UCURR_COMMON|UCURR_DEPRECATED},
749 {"AON", UCURR_COMMON|UCURR_DEPRECATED},
750 {"AOR", UCURR_COMMON|UCURR_DEPRECATED},
751 {"ARA", UCURR_COMMON|UCURR_DEPRECATED},
752 {"ARP", UCURR_COMMON|UCURR_DEPRECATED},
753 {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED},
754 {"ATS", UCURR_COMMON|UCURR_DEPRECATED},
755 {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED},
756 {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED},
757 {"AZM", UCURR_COMMON|UCURR_DEPRECATED},
758 {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
759 {"BAD", UCURR_COMMON|UCURR_DEPRECATED},
760 {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED},
761 {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
762 {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED},
763 {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED},
764 {"BEF", UCURR_COMMON|UCURR_DEPRECATED},
765 {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED},
766 {"BGL", UCURR_COMMON|UCURR_DEPRECATED},
767 {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
768 {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED},
769 {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED},
770 {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
771 {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED},
772 {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED},
773 {"BOP", UCURR_COMMON|UCURR_DEPRECATED},
774 {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
775 {"BRB", UCURR_COMMON|UCURR_DEPRECATED},
776 {"BRC", UCURR_COMMON|UCURR_DEPRECATED},
777 {"BRE", UCURR_COMMON|UCURR_DEPRECATED},
778 {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED},
779 {"BRN", UCURR_COMMON|UCURR_DEPRECATED},
780 {"BRR", UCURR_COMMON|UCURR_DEPRECATED},
781 {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
782 {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED},
783 {"BUK", UCURR_COMMON|UCURR_DEPRECATED},
784 {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
785 {"BYB", UCURR_COMMON|UCURR_DEPRECATED},
786 {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
787 {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
788 {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
789 {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED},
790 {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
791 {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED},
792 {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
793 {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
794 {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED},
795 {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED},
796 {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED},
797 {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED},
798 {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
799 {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED},
800 {"CSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
801 {"CSK", UCURR_COMMON|UCURR_DEPRECATED},
802 {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED},
803 {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED},
804 {"CYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
805 {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED},
806 {"DDM", UCURR_COMMON|UCURR_DEPRECATED},
807 {"DEM", UCURR_COMMON|UCURR_DEPRECATED},
808 {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED},
809 {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
810 {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
811 {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
812 {"ECS", UCURR_COMMON|UCURR_DEPRECATED},
813 {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED},
814 {"EEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
815 {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
816 {"EQE", UCURR_COMMON|UCURR_DEPRECATED},
817 {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
818 {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
819 {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
820 {"ESP", UCURR_COMMON|UCURR_DEPRECATED},
821 {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
822 {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
823 {"FIM", UCURR_COMMON|UCURR_DEPRECATED},
824 {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
825 {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
826 {"FRF", UCURR_COMMON|UCURR_DEPRECATED},
827 {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
828 {"GEK", UCURR_COMMON|UCURR_DEPRECATED},
829 {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
830 {"GHC", UCURR_COMMON|UCURR_NON_DEPRECATED},
831 {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
832 {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
833 {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
834 {"GNS", UCURR_COMMON|UCURR_DEPRECATED},
835 {"GQE", UCURR_COMMON|UCURR_DEPRECATED},
836 {"GRD", UCURR_COMMON|UCURR_DEPRECATED},
837 {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
838 {"GWE", UCURR_COMMON|UCURR_DEPRECATED},
839 {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
840 {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
841 {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
842 {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
843 {"HRD", UCURR_COMMON|UCURR_DEPRECATED},
844 {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
845 {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
846 {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
847 {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
848 {"IEP", UCURR_COMMON|UCURR_DEPRECATED},
849 {"ILP", UCURR_COMMON|UCURR_DEPRECATED},
850 {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED},
851 {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED},
852 {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED},
853 {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED},
854 {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED},
855 {"ITL", UCURR_COMMON|UCURR_DEPRECATED},
856 {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
857 {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED},
858 {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED},
859 {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED},
860 {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED},
861 {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED},
862 {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED},
863 {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED},
864 {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED},
865 {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
866 {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
867 {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED},
868 {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED},
869 {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
870 {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
871 {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
872 {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED},
873 {"LSM", UCURR_COMMON|UCURR_DEPRECATED},
874 {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
875 {"LTT", UCURR_COMMON|UCURR_DEPRECATED},
876 {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED},
877 {"LUF", UCURR_COMMON|UCURR_DEPRECATED},
878 {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED},
879 {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED},
880 {"LVR", UCURR_COMMON|UCURR_DEPRECATED},
881 {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
882 {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
883 {"MAF", UCURR_COMMON|UCURR_DEPRECATED},
884 {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED},
885 {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED},
886 {"MGF", UCURR_COMMON|UCURR_DEPRECATED},
887 {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
888 {"MLF", UCURR_COMMON|UCURR_DEPRECATED},
889 {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
890 {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED},
891 {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
892 {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED},
893 {"MTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
894 {"MTP", UCURR_COMMON|UCURR_DEPRECATED},
895 {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
896 {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED},
897 {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED},
898 {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED},
899 {"MXP", UCURR_COMMON|UCURR_DEPRECATED},
900 {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
901 {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
902 {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED},
903 {"MZM", UCURR_COMMON|UCURR_DEPRECATED},
904 {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
905 {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
906 {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
907 {"NIC", UCURR_COMMON|UCURR_DEPRECATED},
908 {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED},
909 {"NLG", UCURR_COMMON|UCURR_DEPRECATED},
910 {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED},
911 {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED},
912 {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
913 {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED},
914 {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED},
915 {"PEI", UCURR_COMMON|UCURR_DEPRECATED},
916 {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED},
917 {"PES", UCURR_COMMON|UCURR_DEPRECATED},
918 {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED},
919 {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
920 {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
921 {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED},
922 {"PLZ", UCURR_COMMON|UCURR_DEPRECATED},
923 {"PTE", UCURR_COMMON|UCURR_DEPRECATED},
924 {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED},
925 {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
926 {"RHD", UCURR_COMMON|UCURR_DEPRECATED},
927 {"ROL", UCURR_COMMON|UCURR_DEPRECATED},
928 {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED},
929 {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED},
930 {"RUR", UCURR_COMMON|UCURR_DEPRECATED},
931 {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED},
932 {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
933 {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
934 {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED},
935 {"SDD", UCURR_COMMON|UCURR_NON_DEPRECATED},
936 {"SDP", UCURR_COMMON|UCURR_DEPRECATED},
937 {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
938 {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED},
939 {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
940 {"SIT", UCURR_COMMON|UCURR_DEPRECATED},
941 {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
942 {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
943 {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
944 {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
945 {"SRG", UCURR_COMMON|UCURR_DEPRECATED},
946 {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
947 {"SUR", UCURR_COMMON|UCURR_DEPRECATED},
948 {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
949 {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
950 {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
951 {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
952 {"TJR", UCURR_COMMON|UCURR_DEPRECATED},
953 {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
954 {"TMM", UCURR_COMMON|UCURR_NON_DEPRECATED},
955 {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
956 {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
957 {"TPE", UCURR_COMMON|UCURR_DEPRECATED},
958 {"TRL", UCURR_COMMON|UCURR_DEPRECATED},
959 {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
960 {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
961 {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
962 {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
963 {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
964 {"UAK", UCURR_COMMON|UCURR_DEPRECATED},
965 {"UGS", UCURR_COMMON|UCURR_DEPRECATED},
966 {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
967 {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
968 {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
969 {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
970 {"UYP", UCURR_COMMON|UCURR_DEPRECATED},
971 {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
972 {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
973 {"VEB", UCURR_COMMON|UCURR_NON_DEPRECATED},
974 {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
975 {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
976 {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
977 {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
978 {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
979 {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
980 {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
981 {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
982 {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
983 {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
984 {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
985 {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
986 {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
987 {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
988 {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
989 {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
990 {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
991 {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
992 {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
993 {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
994 {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
995 {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
996 {"YDD", UCURR_COMMON|UCURR_DEPRECATED},
997 {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
998 {"YUD", UCURR_COMMON|UCURR_DEPRECATED},
999 {"YUM", UCURR_COMMON|UCURR_DEPRECATED},
1000 {"YUN", UCURR_COMMON|UCURR_DEPRECATED},
1001 {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1002 {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1003 {"ZMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1004 {"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
1005 {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
1006 {"ZWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1007 { NULL, 0 } // Leave here to denote the end of the list.
1008};
1009
1010#define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
1011 ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
1012
1013static int32_t U_CALLCONV
1014ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
1015 UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
1016 uint32_t currType = myContext->currType;
1017 int32_t count = 0;
1018
1019 /* Count the number of items matching the type we are looking for. */
1020 for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
1021 if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
1022 count++;
1023 }
1024 }
1025 return count;
1026}
1027
1028static const char* U_CALLCONV
1029ucurr_nextCurrencyList(UEnumeration *enumerator,
1030 int32_t* resultLength,
1031 UErrorCode * /*pErrorCode*/)
1032{
1033 UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
1034
1035 /* Find the next in the list that matches the type we are looking for. */
1036 while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) {
1037 const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
1038 if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
1039 {
1040 if (resultLength) {
1041 *resultLength = 3; /* Currency codes are only 3 chars long */
1042 }
1043 return currItem->currency;
1044 }
1045 }
1046 /* We enumerated too far. */
1047 if (resultLength) {
1048 *resultLength = 0;
1049 }
1050 return NULL;
1051}
1052
1053static void U_CALLCONV
1054ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
1055 ((UCurrencyContext *)(enumerator->context))->listIdx = 0;
1056}
1057
1058static void U_CALLCONV
1059ucurr_closeCurrencyList(UEnumeration *enumerator) {
1060 uprv_free(enumerator->context);
1061 uprv_free(enumerator);
1062}
1063
1064static const UEnumeration gEnumCurrencyList = {
1065 NULL,
1066 NULL,
1067 ucurr_closeCurrencyList,
1068 ucurr_countCurrencyList,
1069 uenum_unextDefault,
1070 ucurr_nextCurrencyList,
1071 ucurr_resetCurrencyList
1072};
1073U_CDECL_END
1074
1075U_CAPI UEnumeration * U_EXPORT2
1076ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
1077 UEnumeration *myEnum = NULL;
1078 UCurrencyContext *myContext;
1079
1080 myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
1081 if (myEnum == NULL) {
1082 *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
1083 return NULL;
1084 }
1085 uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
1086 myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
1087 if (myContext == NULL) {
1088 *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
1089 uprv_free(myEnum);
1090 return NULL;
1091 }
1092 myContext->currType = currType;
1093 myContext->listIdx = 0;
1094 myEnum->context = myContext;
1095 return myEnum;
1096}
1097
b75a7d8f
A
1098#endif /* #if !UCONFIG_NO_FORMATTING */
1099
1100//eof