]>
Commit | Line | Data |
---|---|---|
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). | |
33 | static const int32_t LAST_RESORT_DATA[] = { 2, 0 }; | |
34 | ||
35 | // POW10[i] = 10^i, i=0..MAX_POW10 | |
36 | static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000, | |
37 | 1000000, 10000000, 100000000, 1000000000 }; | |
38 | ||
39 | static 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 | 47 | static const char CURRENCY_DATA[] = "CurrencyData"; |
b75a7d8f A |
48 | // Tag for meta-data, in root. |
49 | static const char CURRENCY_META[] = "CurrencyMeta"; | |
50 | ||
51 | // Tag for map from countries to currencies, in root. | |
52 | static const char CURRENCY_MAP[] = "CurrencyMap"; | |
53 | ||
54 | // Tag for default meta-data, in CURRENCY_META | |
55 | static const char DEFAULT_META[] = "DEFAULT"; | |
56 | ||
57 | // Variant for legacy pre-euro mapping in CurrencyMap | |
58 | static const char VAR_PRE_EURO[] = "PREEURO"; | |
59 | ||
60 | // Variant for legacy euro mapping in CurrencyMap | |
61 | static const char VAR_EURO[] = "EURO"; | |
62 | ||
63 | // Variant delimiter | |
64 | static const char VAR_DELIM[] = "_"; | |
65 | ||
374ca955 A |
66 | // Variant for legacy euro mapping in CurrencyMap |
67 | static 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 |
74 | static 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. | |
80 | static 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 | */ | |
89 | static inline char* | |
90 | myUCharsToChars(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 | */ | |
102 | static 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 | */ | |
162 | static uint32_t | |
163 | idForLocale(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 |
193 | U_CDECL_BEGIN | |
194 | static UBool U_CALLCONV currency_cleanup(void); | |
195 | U_CDECL_END | |
b75a7d8f A |
196 | struct CReg; |
197 | ||
198 | /* Remember to call umtx_init(&gCRegLock) before using it! */ | |
199 | static UMTX gCRegLock = 0; | |
200 | static CReg* gCRegHead = 0; | |
201 | ||
202 | struct 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 | */ | |
292 | U_CDECL_BEGIN | |
293 | static UBool U_CALLCONV currency_cleanup(void) { | |
294 | #if !UCONFIG_NO_SERVICE | |
295 | CReg::cleanup(); | |
296 | #endif | |
297 | return TRUE; | |
b75a7d8f | 298 | } |
374ca955 | 299 | U_CDECL_END |
b75a7d8f A |
300 | |
301 | // ------------------------------------- | |
302 | ||
303 | U_CAPI UCurrRegistryKey U_EXPORT2 | |
374ca955 | 304 | ucurr_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 | ||
316 | U_CAPI UBool U_EXPORT2 | |
374ca955 | 317 | ucurr_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 |
328 | U_CAPI int32_t U_EXPORT2 |
329 | ucurr_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 | */ | |
410 | static 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 | ||
427 | U_CAPI const UChar* U_EXPORT2 | |
428 | ucurr_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 |
528 | U_NAMESPACE_BEGIN |
529 | ||
530 | void | |
531 | uprv_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 | ||
658 | U_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 | */ | |
670 | U_CAPI void | |
671 | uprv_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 | |
695 | U_CAPI int32_t U_EXPORT2 | |
374ca955 A |
696 | ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) { |
697 | return (_findMetaData(currency, *ec))[0]; | |
b75a7d8f A |
698 | } |
699 | ||
700 | U_CAPI double U_EXPORT2 | |
374ca955 A |
701 | ucurr_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 |
723 | U_CDECL_BEGIN |
724 | ||
725 | typedef struct UCurrencyContext { | |
726 | uint32_t currType; /* UCurrCurrencyType */ | |
727 | uint32_t listIdx; | |
728 | } UCurrencyContext; | |
729 | ||
730 | /* | |
731 | Please keep this list in alphabetical order. | |
732 | You can look at the CLDR supplemental data or ISO-4217 for the meaning of some | |
733 | of these items. | |
734 | ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html | |
735 | */ | |
736 | static 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 | ||
1013 | static int32_t U_CALLCONV | |
1014 | ucurr_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 | ||
1028 | static const char* U_CALLCONV | |
1029 | ucurr_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 | ||
1053 | static void U_CALLCONV | |
1054 | ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) { | |
1055 | ((UCurrencyContext *)(enumerator->context))->listIdx = 0; | |
1056 | } | |
1057 | ||
1058 | static void U_CALLCONV | |
1059 | ucurr_closeCurrencyList(UEnumeration *enumerator) { | |
1060 | uprv_free(enumerator->context); | |
1061 | uprv_free(enumerator); | |
1062 | } | |
1063 | ||
1064 | static const UEnumeration gEnumCurrencyList = { | |
1065 | NULL, | |
1066 | NULL, | |
1067 | ucurr_closeCurrencyList, | |
1068 | ucurr_countCurrencyList, | |
1069 | uenum_unextDefault, | |
1070 | ucurr_nextCurrencyList, | |
1071 | ucurr_resetCurrencyList | |
1072 | }; | |
1073 | U_CDECL_END | |
1074 | ||
1075 | U_CAPI UEnumeration * U_EXPORT2 | |
1076 | ucurr_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 |