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