1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4*******************************************************************************
5* Copyright (C) 1997-2016, International Business Machines Corporation and
6* others. All Rights Reserved.
7*******************************************************************************
8*
9* File DCFMTSYM.CPP
10*
11* Modification History:
12*
13* Date Name Description
14* 02/19/97 aliu Converted from java.
15* 03/18/97 clhuang Implemented with C++ APIs.
16* 03/27/97 helena Updated to pass the simple test after code review.
17* 08/26/97 aliu Added currency/intl currency symbol support.
18* 07/20/98 stephen Slightly modified initialization of monetarySeparator
19********************************************************************************
20*/
21
22#include "unicode/utypes.h"
23
24#if !UCONFIG_NO_FORMATTING
25
26#include "unicode/dcfmtsym.h"
27#include "unicode/ures.h"
28#include "unicode/decimfmt.h"
29#include "unicode/ucurr.h"
30#include "unicode/choicfmt.h"
31#include "unicode/unistr.h"
32#include "unicode/numsys.h"
33#include "unicode/unum.h"
34#include "unicode/utf16.h"
35#include "ucurrimp.h"
36#include "cstring.h"
37#include "locbased.h"
38#include "uresimp.h"
39#include "ureslocs.h"
40#include "charstr.h"
41#include "uassert.h"
42
43// *****************************************************************************
44// class DecimalFormatSymbols
45// *****************************************************************************
46
47U_NAMESPACE_BEGIN
48
49UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormatSymbols)
50
51static const char gNumberElements[] = "NumberElements";
52static const char gCurrencySpacingTag[] = "currencySpacing";
53static const char gBeforeCurrencyTag[] = "beforeCurrency";
54static const char gAfterCurrencyTag[] = "afterCurrency";
55static const char gCurrencyMatchTag[] = "currencyMatch";
56static const char gCurrencySudMatchTag[] = "surroundingMatch";
57static const char gCurrencyInsertBtnTag[] = "insertBetween";
58static const char gLatn[] = "latn";
59static const char gSymbols[] = "symbols";
60static const char gNumberElementsLatnSymbols[] = "NumberElements/latn/symbols";
61
62static const UChar INTL_CURRENCY_SYMBOL_STR[] = {0xa4, 0xa4, 0};
63
64// List of field names to be loaded from the data files.
65// These are parallel with the enum ENumberFormatSymbol in unicode/dcfmtsym.h.
66static const char *gNumberElementKeys[DecimalFormatSymbols::kFormatSymbolCount] = {
67 "decimal",
68 "group",
69 NULL, /* #11897: the <list> symbol is NOT the pattern separator symbol */
70 "percentSign",
71 NULL, /* Native zero digit is deprecated from CLDR - get it from the numbering system */
72 NULL, /* Pattern digit character is deprecated from CLDR - use # by default always */
73 "minusSign",
74 "plusSign",
75 NULL, /* currency symbol - Wait until we know the currency before loading from CLDR */
76 NULL, /* intl currency symbol - Wait until we know the currency before loading from CLDR */
77 "currencyDecimal",
78 "exponential",
79 "perMille",
80 NULL, /* Escape padding character - not in CLDR */
81 "infinity",
82 "nan",
83 NULL, /* Significant digit symbol - not in CLDR */
84 "currencyGroup",
85 NULL, /* one digit - get it from the numbering system */
86 NULL, /* two digit - get it from the numbering system */
87 NULL, /* three digit - get it from the numbering system */
88 NULL, /* four digit - get it from the numbering system */
89 NULL, /* five digit - get it from the numbering system */
90 NULL, /* six digit - get it from the numbering system */
91 NULL, /* seven digit - get it from the numbering system */
92 NULL, /* eight digit - get it from the numbering system */
93 NULL, /* nine digit - get it from the numbering system */
94 "superscriptingExponent", /* Multiplication (x) symbol for exponents */
95};
96
97// -------------------------------------
98// Initializes this with the decimal format symbols in the default locale.
99
100DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status)
101 : UObject(), locale(), currPattern(NULL) {
102 initialize(locale, status, TRUE);
103}
104
105// -------------------------------------
106// Initializes this with the decimal format symbols in the desired locale.
107
108DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, UErrorCode& status)
109 : UObject(), locale(loc), currPattern(NULL) {
110 initialize(locale, status);
111}
112
113DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, const NumberingSystem& ns, UErrorCode& status)
114 : UObject(), locale(loc), currPattern(NULL) {
115 initialize(locale, status, FALSE, &ns);
116}
117
118DecimalFormatSymbols::DecimalFormatSymbols()
119 : UObject(), locale(Locale::getRoot()), currPattern(NULL) {
120 *validLocale = *actualLocale = 0;
121 initialize();
122}
123
124DecimalFormatSymbols*
125DecimalFormatSymbols::createWithLastResortData(UErrorCode& status) {
126 if (U_FAILURE(status)) { return NULL; }
127 DecimalFormatSymbols* sym = new DecimalFormatSymbols();
128 if (sym == NULL) {
129 status = U_MEMORY_ALLOCATION_ERROR;
130 }
131 return sym;
132}
133
134// -------------------------------------
135
136DecimalFormatSymbols::~DecimalFormatSymbols()
137{
138}
139
140// -------------------------------------
141// copy constructor
142
143DecimalFormatSymbols::DecimalFormatSymbols(const DecimalFormatSymbols &source)
144 : UObject(source)
145{
146 *this = source;
147}
148
149// -------------------------------------
150// assignment operator
151
152DecimalFormatSymbols&
153DecimalFormatSymbols::operator=(const DecimalFormatSymbols& rhs)
154{
155 if (this != &rhs) {
156 for(int32_t i = 0; i < (int32_t)kFormatSymbolCount; ++i) {
157 // fastCopyFrom is safe, see docs on fSymbols
158 fSymbols[(ENumberFormatSymbol)i].fastCopyFrom(rhs.fSymbols[(ENumberFormatSymbol)i]);
159 }
160 for(int32_t i = 0; i < (int32_t)UNUM_CURRENCY_SPACING_COUNT; ++i) {
161 currencySpcBeforeSym[i].fastCopyFrom(rhs.currencySpcBeforeSym[i]);
162 currencySpcAfterSym[i].fastCopyFrom(rhs.currencySpcAfterSym[i]);
163 }
164 locale = rhs.locale;
165 uprv_strcpy(validLocale, rhs.validLocale);
166 uprv_strcpy(actualLocale, rhs.actualLocale);
167 fIsCustomCurrencySymbol = rhs.fIsCustomCurrencySymbol;
168 fIsCustomIntlCurrencySymbol = rhs.fIsCustomIntlCurrencySymbol;
169 fCodePointZero = rhs.fCodePointZero;
170 }
171 return *this;
172}
173
174// -------------------------------------
175
176UBool
177DecimalFormatSymbols::operator==(const DecimalFormatSymbols& that) const
178{
179 if (this == &that) {
180 return TRUE;
181 }
182 if (fIsCustomCurrencySymbol != that.fIsCustomCurrencySymbol) {
183 return FALSE;
184 }
185 if (fIsCustomIntlCurrencySymbol != that.fIsCustomIntlCurrencySymbol) {
186 return FALSE;
187 }
188 for(int32_t i = 0; i < (int32_t)kFormatSymbolCount; ++i) {
189 if(fSymbols[(ENumberFormatSymbol)i] != that.fSymbols[(ENumberFormatSymbol)i]) {
190 return FALSE;
191 }
192 }
193 for(int32_t i = 0; i < (int32_t)UNUM_CURRENCY_SPACING_COUNT; ++i) {
194 if(currencySpcBeforeSym[i] != that.currencySpcBeforeSym[i]) {
195 return FALSE;
196 }
197 if(currencySpcAfterSym[i] != that.currencySpcAfterSym[i]) {
198 return FALSE;
199 }
200 }
201 // No need to check fCodePointZero since it is based on fSymbols
202 return locale == that.locale &&
203 uprv_strcmp(validLocale, that.validLocale) == 0 &&
204 uprv_strcmp(actualLocale, that.actualLocale) == 0;
205}
206
207// -------------------------------------
208
209namespace {
210
211/**
212 * Sink for enumerating all of the decimal format symbols (more specifically, anything
213 * under the "NumberElements.symbols" tree).
214 *
215 * More specific bundles (en_GB) are enumerated before their parents (en_001, en, root):
216 * Only store a value if it is still missing, that is, it has not been overridden.
217 */
218struct DecFmtSymDataSink : public ResourceSink {
219
220 // Destination for data, modified via setters.
221 DecimalFormatSymbols& dfs;
222 // Boolean array of whether or not we have seen a particular symbol yet.
223 // Can't simpy check fSymbols because it is pre-populated with defaults.
224 UBool seenSymbol[DecimalFormatSymbols::kFormatSymbolCount];
225
226 // Constructor/Destructor
227 DecFmtSymDataSink(DecimalFormatSymbols& _dfs) : dfs(_dfs) {
228 uprv_memset(seenSymbol, FALSE, sizeof(seenSymbol));
229 }
230 virtual ~DecFmtSymDataSink();
231
232 virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
233 UErrorCode &errorCode) {
234 ResourceTable symbolsTable = value.getTable(errorCode);
235 if (U_FAILURE(errorCode)) { return; }
236 for (int32_t j = 0; symbolsTable.getKeyAndValue(j, key, value); ++j) {
237 for (int32_t i=0; i<DecimalFormatSymbols::kFormatSymbolCount; i++) {
238 if (gNumberElementKeys[i] != NULL && uprv_strcmp(key, gNumberElementKeys[i]) == 0) {
239 if (!seenSymbol[i]) {
240 seenSymbol[i] = TRUE;
241 dfs.setSymbol(
242 (DecimalFormatSymbols::ENumberFormatSymbol) i,
243 value.getUnicodeString(errorCode));
244 if (U_FAILURE(errorCode)) { return; }
245 }
246 break;
247 }
248 }
249 }
250 }
251
252 // Returns true if all the symbols have been seen.
253 UBool seenAll() {
254 for (int32_t i=0; i<DecimalFormatSymbols::kFormatSymbolCount; i++) {
255 if (!seenSymbol[i]) {
256 return FALSE;
257 }
258 }
259 return TRUE;
260 }
261
262 // If monetary decimal or grouping were not explicitly set, then set them to be the
263 // same as their non-monetary counterparts.
264 void resolveMissingMonetarySeparators(const UnicodeString* fSymbols) {
265 if (!seenSymbol[DecimalFormatSymbols::kMonetarySeparatorSymbol]) {
266 dfs.setSymbol(
267 DecimalFormatSymbols::kMonetarySeparatorSymbol,
268 fSymbols[DecimalFormatSymbols::kDecimalSeparatorSymbol]);
269 }
270 if (!seenSymbol[DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol]) {
271 dfs.setSymbol(
272 DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol,
273 fSymbols[DecimalFormatSymbols::kGroupingSeparatorSymbol]);
274 }
275 }
276};
277
278struct CurrencySpacingSink : public ResourceSink {
279 DecimalFormatSymbols& dfs;
280 UBool hasBeforeCurrency;
281 UBool hasAfterCurrency;
282
283 CurrencySpacingSink(DecimalFormatSymbols& _dfs)
284 : dfs(_dfs), hasBeforeCurrency(FALSE), hasAfterCurrency(FALSE) {}
285 virtual ~CurrencySpacingSink();
286
287 virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
288 UErrorCode &errorCode) {
289 ResourceTable spacingTypesTable = value.getTable(errorCode);
290 for (int32_t i = 0; spacingTypesTable.getKeyAndValue(i, key, value); ++i) {
291 UBool beforeCurrency;
292 if (uprv_strcmp(key, gBeforeCurrencyTag) == 0) {
293 beforeCurrency = TRUE;
294 hasBeforeCurrency = TRUE;
295 } else if (uprv_strcmp(key, gAfterCurrencyTag) == 0) {
296 beforeCurrency = FALSE;
297 hasAfterCurrency = TRUE;
298 } else {
299 continue;
300 }
301
302 ResourceTable patternsTable = value.getTable(errorCode);
303 for (int32_t j = 0; patternsTable.getKeyAndValue(j, key, value); ++j) {
304 UCurrencySpacing pattern;
305 if (uprv_strcmp(key, gCurrencyMatchTag) == 0) {
306 pattern = UNUM_CURRENCY_MATCH;
307 } else if (uprv_strcmp(key, gCurrencySudMatchTag) == 0) {
308 pattern = UNUM_CURRENCY_SURROUNDING_MATCH;
309 } else if (uprv_strcmp(key, gCurrencyInsertBtnTag) == 0) {
310 pattern = UNUM_CURRENCY_INSERT;
311 } else {
312 continue;
313 }
314
315 const UnicodeString& current = dfs.getPatternForCurrencySpacing(
316 pattern, beforeCurrency, errorCode);
317 if (current.isEmpty()) {
318 dfs.setPatternForCurrencySpacing(
319 pattern, beforeCurrency, value.getUnicodeString(errorCode));
320 }
321 }
322 }
323 }
324
325 void resolveMissing() {
326 // For consistency with Java, this method overwrites everything with the defaults unless
327 // both beforeCurrency and afterCurrency were found in CLDR.
328 static const char* defaults[] = { "[:letter:]", "[:digit:]", " " };
329 if (!hasBeforeCurrency || !hasAfterCurrency) {
330 for (UBool beforeCurrency = 0; beforeCurrency <= TRUE; beforeCurrency++) {
331 for (int32_t pattern = 0; pattern < UNUM_CURRENCY_SPACING_COUNT; pattern++) {
332 dfs.setPatternForCurrencySpacing((UCurrencySpacing)pattern,
333 beforeCurrency, UnicodeString(defaults[pattern], -1, US_INV));
334 }
335 }
336 }
337 }
338};
339
340// Virtual destructors must be defined out of line.
341DecFmtSymDataSink::~DecFmtSymDataSink() {}
342CurrencySpacingSink::~CurrencySpacingSink() {}
343
344} // namespace
345
346void
347DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
348 UBool useLastResortData, const NumberingSystem* ns)
349{
350 if (U_FAILURE(status)) { return; }
351 *validLocale = *actualLocale = 0;
352
353 // First initialize all the symbols to the fallbacks for anything we can't find
354 initialize();
355
356 //
357 // Next get the numbering system for this locale and set zero digit
358 // and the digit string based on the numbering system for the locale
359 //
360 LocalPointer<NumberingSystem> nsLocal;
361 if (ns == nullptr) {
362 // Use the numbering system according to the locale.
363 // Save it into a LocalPointer so it gets cleaned up.
364 nsLocal.adoptInstead(NumberingSystem::createInstance(loc, status));
365 ns = nsLocal.getAlias();
366 }
367 const char *nsName;
368 if (U_SUCCESS(status) && ns->getRadix() == 10 && !ns->isAlgorithmic()) {
369 nsName = ns->getName();
370 UnicodeString digitString(ns->getDescription());
371 int32_t digitIndex = 0;
372 UChar32 digit = digitString.char32At(0);
373 fSymbols[kZeroDigitSymbol].setTo(digit);
374 for (int32_t i = kOneDigitSymbol; i <= kNineDigitSymbol; ++i) {
375 digitIndex += U16_LENGTH(digit);
376 digit = digitString.char32At(digitIndex);
377 fSymbols[i].setTo(digit);
378 }
379 } else {
380 nsName = gLatn;
381 }
382
383 // Open resource bundles
384 const char* locStr = loc.getName();
385 LocalUResourceBundlePointer resource(ures_open(NULL, locStr, &status));
386 LocalUResourceBundlePointer numberElementsRes(
387 ures_getByKeyWithFallback(resource.getAlias(), gNumberElements, NULL, &status));
388
389 if (U_FAILURE(status)) {
390 if ( useLastResortData ) {
391 status = U_USING_DEFAULT_WARNING;
392 initialize();
393 }
394 return;
395 }
396
397 // Set locale IDs
398 // TODO: Is there a way to do this without depending on the resource bundle instance?
399 U_LOCALE_BASED(locBased, *this);
400 locBased.setLocaleIDs(
401 ures_getLocaleByType(
402 numberElementsRes.getAlias(),
403 ULOC_VALID_LOCALE, &status),
404 ures_getLocaleByType(
405 numberElementsRes.getAlias(),
406 ULOC_ACTUAL_LOCALE, &status));
407
408 // Now load the rest of the data from the data sink.
409 // Start with loading this nsName if it is not Latin.
410 DecFmtSymDataSink sink(*this);
411 if (uprv_strcmp(nsName, gLatn) != 0) {
412 CharString path;
413 path.append(gNumberElements, status)
414 .append('/', status)
415 .append(nsName, status)
416 .append('/', status)
417 .append(gSymbols, status);
418 ures_getAllItemsWithFallback(resource.getAlias(), path.data(), sink, status);
419
420 // If no symbols exist for the given nsName and resource bundle, silently ignore
421 // and fall back to Latin.
422 if (status == U_MISSING_RESOURCE_ERROR) {
423 status = U_ZERO_ERROR;
424 } else if (U_FAILURE(status)) {
425 return;
426 }
427 }
428
429 // Continue with Latin if necessary.
430 if (!sink.seenAll()) {
431 ures_getAllItemsWithFallback(resource.getAlias(), gNumberElementsLatnSymbols, sink, status);
432 if (U_FAILURE(status)) { return; }
433 }
434
435 // Let the monetary number separators equal the default number separators if necessary.
436 sink.resolveMissingMonetarySeparators(fSymbols);
437
438 // Resolve codePointZero
439 UChar32 tempCodePointZero = -1;
440 for (int32_t i=0; i<=9; i++) {
441 const UnicodeString& stringDigit = getConstDigitSymbol(i);
442 if (stringDigit.countChar32() != 1) {
443 tempCodePointZero = -1;
444 break;
445 }
446 UChar32 cp = stringDigit.char32At(0);
447 if (i == 0) {
448 tempCodePointZero = cp;
449 } else if (cp != tempCodePointZero + i) {
450 tempCodePointZero = -1;
451 break;
452 }
453 }
454 fCodePointZero = tempCodePointZero;
455
456 // Obtain currency data from the currency API. This is strictly
457 // for backward compatibility; we don't use DecimalFormatSymbols
458 // for currency data anymore.
459 UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out
460 UChar curriso[4];
461 UnicodeString tempStr;
462 int32_t currisoLength = ucurr_forLocale(locStr, curriso, UPRV_LENGTHOF(curriso), &internalStatus);
463 if (U_SUCCESS(internalStatus) && currisoLength == 3) {
464 uprv_getStaticCurrencyName(curriso, locStr, tempStr, internalStatus);
465 if (U_SUCCESS(internalStatus)) {
466 fSymbols[kIntlCurrencySymbol].setTo(curriso, currisoLength);
467 fSymbols[kCurrencySymbol] = tempStr;
468 }
469 }
470 /* else use the default values. */
471
472 //load the currency data
473 UChar ucc[4]={0}; //Currency Codes are always 3 chars long
474 int32_t uccLen = 4;
475 const char* locName = loc.getName();
476 UErrorCode localStatus = U_ZERO_ERROR;
477 uccLen = ucurr_forLocale(locName, ucc, uccLen, &localStatus);
478
479 // TODO: Currency pattern data loading is duplicated in number_formatimpl.cpp
480 if(U_SUCCESS(localStatus) && uccLen > 0) {
481 char cc[4]={0};
482 u_UCharsToChars(ucc, cc, uccLen);
483 /* An explicit currency was requested */
484 LocalUResourceBundlePointer currencyResource(ures_open(U_ICUDATA_CURR, locStr, &localStatus));
485 LocalUResourceBundlePointer currency(
486 ures_getByKeyWithFallback(currencyResource.getAlias(), "Currencies", NULL, &localStatus));
487 ures_getByKeyWithFallback(currency.getAlias(), cc, currency.getAlias(), &localStatus);
488 if(U_SUCCESS(localStatus) && ures_getSize(currency.getAlias())>2) { // the length is 3 if more data is present
489 ures_getByIndex(currency.getAlias(), 2, currency.getAlias(), &localStatus);
490 int32_t currPatternLen = 0;
491 currPattern =
492 ures_getStringByIndex(currency.getAlias(), (int32_t)0, &currPatternLen, &localStatus);
493 UnicodeString decimalSep =
494 ures_getUnicodeStringByIndex(currency.getAlias(), (int32_t)1, &localStatus);
495 UnicodeString groupingSep =
496 ures_getUnicodeStringByIndex(currency.getAlias(), (int32_t)2, &localStatus);
497 if(U_SUCCESS(localStatus)){
498 fSymbols[kMonetaryGroupingSeparatorSymbol] = groupingSep;
499 fSymbols[kMonetarySeparatorSymbol] = decimalSep;
500 //pattern.setTo(TRUE, currPattern, currPatternLen);
501 status = localStatus;
502 }
503 }
504 /* else An explicit currency was requested and is unknown or locale data is malformed. */
505 /* ucurr_* API will get the correct value later on. */
506 }
507 // else ignore the error if no currency
508
509 // Currency Spacing.
510 LocalUResourceBundlePointer currencyResource(ures_open(U_ICUDATA_CURR, locStr, &status));
511 CurrencySpacingSink currencySink(*this);
512 ures_getAllItemsWithFallback(currencyResource.getAlias(), gCurrencySpacingTag, currencySink, status);
513 currencySink.resolveMissing();
514 if (U_FAILURE(status)) { return; }
515}
516
517void
518DecimalFormatSymbols::initialize() {
519 /*
520 * These strings used to be in static arrays, but the HP/UX aCC compiler
521 * cannot initialize a static array with class constructors.
522 * markus 2000may25
523 */
524 fSymbols[kDecimalSeparatorSymbol] = (UChar)0x2e; // '.' decimal separator
525 fSymbols[kGroupingSeparatorSymbol].remove(); // group (thousands) separator
526 fSymbols[kPatternSeparatorSymbol] = (UChar)0x3b; // ';' pattern separator
527 fSymbols[kPercentSymbol] = (UChar)0x25; // '%' percent sign
528 fSymbols[kZeroDigitSymbol] = (UChar)0x30; // '0' native 0 digit
529 fSymbols[kOneDigitSymbol] = (UChar)0x31; // '1' native 1 digit
530 fSymbols[kTwoDigitSymbol] = (UChar)0x32; // '2' native 2 digit
531 fSymbols[kThreeDigitSymbol] = (UChar)0x33; // '3' native 3 digit
532 fSymbols[kFourDigitSymbol] = (UChar)0x34; // '4' native 4 digit
533 fSymbols[kFiveDigitSymbol] = (UChar)0x35; // '5' native 5 digit
534 fSymbols[kSixDigitSymbol] = (UChar)0x36; // '6' native 6 digit
535 fSymbols[kSevenDigitSymbol] = (UChar)0x37; // '7' native 7 digit
536 fSymbols[kEightDigitSymbol] = (UChar)0x38; // '8' native 8 digit
537 fSymbols[kNineDigitSymbol] = (UChar)0x39; // '9' native 9 digit
538 fSymbols[kDigitSymbol] = (UChar)0x23; // '#' pattern digit
539 fSymbols[kPlusSignSymbol] = (UChar)0x002b; // '+' plus sign
540 fSymbols[kMinusSignSymbol] = (UChar)0x2d; // '-' minus sign
541 fSymbols[kCurrencySymbol] = (UChar)0xa4; // 'OX' currency symbol
542 fSymbols[kIntlCurrencySymbol].setTo(TRUE, INTL_CURRENCY_SYMBOL_STR, 2);
543 fSymbols[kMonetarySeparatorSymbol] = (UChar)0x2e; // '.' monetary decimal separator
544 fSymbols[kExponentialSymbol] = (UChar)0x45; // 'E' exponential
545 fSymbols[kPerMillSymbol] = (UChar)0x2030; // '%o' per mill
546 fSymbols[kPadEscapeSymbol] = (UChar)0x2a; // '*' pad escape symbol
547 fSymbols[kInfinitySymbol] = (UChar)0x221e; // 'oo' infinite
548 fSymbols[kNaNSymbol] = (UChar)0xfffd; // SUB NaN
549 fSymbols[kSignificantDigitSymbol] = (UChar)0x0040; // '@' significant digit
550 fSymbols[kMonetaryGroupingSeparatorSymbol].remove(); //
551 fSymbols[kExponentMultiplicationSymbol] = (UChar)0xd7; // 'x' multiplication symbol for exponents
552 fIsCustomCurrencySymbol = FALSE;
553 fIsCustomIntlCurrencySymbol = FALSE;
554 fCodePointZero = 0x30;
555 U_ASSERT(fCodePointZero == fSymbols[kZeroDigitSymbol].char32At(0));
556
557}
558
559Locale
560DecimalFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
561 U_LOCALE_BASED(locBased, *this);
562 return locBased.getLocale(type, status);
563}
564
565const UnicodeString&
566DecimalFormatSymbols::getPatternForCurrencySpacing(UCurrencySpacing type,
567 UBool beforeCurrency,
568 UErrorCode& status) const {
569 if (U_FAILURE(status)) {
570 return fNoSymbol; // always empty.
571 }
572 if (beforeCurrency) {
573 return currencySpcBeforeSym[(int32_t)type];
574 } else {
575 return currencySpcAfterSym[(int32_t)type];
576 }
577}
578
579void
580DecimalFormatSymbols::setPatternForCurrencySpacing(UCurrencySpacing type,
581 UBool beforeCurrency,
582 const UnicodeString& pattern) {
583 if (beforeCurrency) {
584 currencySpcBeforeSym[(int32_t)type] = pattern;
585 } else {
586 currencySpcAfterSym[(int32_t)type] = pattern;
587 }
588}
589U_NAMESPACE_END
590
591#endif /* #if !UCONFIG_NO_FORMATTING */
592
593//eof
594