1// Copyright (C) 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4*******************************************************************************
5*   Copyright (C) 1996-2015, International Business Machines
6*   Corporation and others.  All Rights Reserved.
7*******************************************************************************
8* Modification History:
9*
10*   Date        Name        Description
11*   06/24/99    helena      Integrated Alan's NF enhancements and Java2 bug fixes
12*******************************************************************************
13*/
14
15#include "unicode/utypes.h"
16
17#if !UCONFIG_NO_FORMATTING
18
19#include "unicode/unum.h"
20
21#include "unicode/uloc.h"
22#include "unicode/numfmt.h"
23#include "unicode/decimfmt.h"
24#include "unicode/rbnf.h"
25#include "unicode/compactdecimalformat.h"
26#include "unicode/ustring.h"
27#include "unicode/fmtable.h"
28#include "unicode/dcfmtsym.h"
29#include "unicode/curramt.h"
30#include "unicode/localpointer.h"
31#include "unicode/udisplaycontext.h"
32#include "uassert.h"
33#include "cpputils.h"
34#include "cstring.h"
35
36
37U_NAMESPACE_USE
38
39
40U_CAPI UNumberFormat* U_EXPORT2
41unum_open(  UNumberFormatStyle    style,
42            const    UChar*    pattern,
43            int32_t            patternLength,
44            const    char*     locale,
45            UParseError*       parseErr,
46            UErrorCode*        status) {
47    if(U_FAILURE(*status)) {
48        return NULL;
49    }
50
51    NumberFormat *retVal = NULL;
52
53    switch(style) {
54    case UNUM_DECIMAL:
55    case UNUM_CURRENCY:
56    case UNUM_PERCENT:
57    case UNUM_SCIENTIFIC:
58    case UNUM_CURRENCY_ISO:
59    case UNUM_CURRENCY_PLURAL:
60    case UNUM_CURRENCY_ACCOUNTING:
61    case UNUM_CASH_CURRENCY:
62    case UNUM_CURRENCY_STANDARD:
63        retVal = NumberFormat::createInstance(Locale(locale), style, *status);
64        break;
65
66    case UNUM_PATTERN_DECIMAL: {
67        UParseError tErr;
68        /* UnicodeString can handle the case when patternLength = -1. */
69        const UnicodeString pat(pattern, patternLength);
70
71        if(parseErr==NULL){
72            parseErr = &tErr;
73        }
74
75        DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale(locale), *status);
76        if(syms == NULL) {
77            *status = U_MEMORY_ALLOCATION_ERROR;
78            return NULL;
79        }
80        if (U_FAILURE(*status)) {
81            delete syms;
82            return NULL;
83        }
84
85        retVal = new DecimalFormat(pat, syms, *parseErr, *status);
86        if(retVal == NULL) {
87            delete syms;
88        }
89    } break;
90
91#if U_HAVE_RBNF
92    case UNUM_PATTERN_RULEBASED: {
93        UParseError tErr;
94        /* UnicodeString can handle the case when patternLength = -1. */
95        const UnicodeString pat(pattern, patternLength);
96
97        if(parseErr==NULL){
98            parseErr = &tErr;
99        }
100
101        retVal = new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
102    } break;
103
104    case UNUM_SPELLOUT:
105        retVal = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
106        break;
107
108    case UNUM_ORDINAL:
109        retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
110        break;
111
112    case UNUM_DURATION:
113        retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
114        break;
115
116    case UNUM_NUMBERING_SYSTEM:
117        retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status);
118        break;
119#endif
120
121    case UNUM_DECIMAL_COMPACT_SHORT:
122        retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_SHORT, *status);
123        break;
124
125    case UNUM_DECIMAL_COMPACT_LONG:
126        retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_LONG, *status);
127        break;
128
129    default:
130        *status = U_UNSUPPORTED_ERROR;
131        return NULL;
132    }
133
134    if(retVal == NULL && U_SUCCESS(*status)) {
135        *status = U_MEMORY_ALLOCATION_ERROR;
136    }
137
138    return reinterpret_cast<UNumberFormat *>(retVal);
139}
140
141U_CAPI void U_EXPORT2
142unum_close(UNumberFormat* fmt)
143{
144    delete (NumberFormat*) fmt;
145}
146
147U_CAPI UNumberFormat* U_EXPORT2
148unum_clone(const UNumberFormat *fmt,
149       UErrorCode *status)
150{
151    if(U_FAILURE(*status))
152        return 0;
153
154    Format *res = 0;
155    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
156    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
157    if (df != NULL) {
158        res = df->clone();
159    } else {
160        const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
161        U_ASSERT(rbnf != NULL);
162        res = rbnf->clone();
163    }
164
165    if(res == 0) {
166        *status = U_MEMORY_ALLOCATION_ERROR;
167        return 0;
168    }
169
170    return (UNumberFormat*) res;
171}
172
173U_CAPI int32_t U_EXPORT2
174unum_format(    const    UNumberFormat*    fmt,
175        int32_t           number,
176        UChar*            result,
177        int32_t           resultLength,
178        UFieldPosition    *pos,
179        UErrorCode*       status)
180{
181        return unum_formatInt64(fmt, number, result, resultLength, pos, status);
182}
183
184U_CAPI int32_t U_EXPORT2
185unum_formatInt64(const UNumberFormat* fmt,
186        int64_t         number,
187        UChar*          result,
188        int32_t         resultLength,
189        UFieldPosition *pos,
190        UErrorCode*     status)
191{
192    if(U_FAILURE(*status))
193        return -1;
194
195    UnicodeString res;
196    if(!(result==NULL && resultLength==0)) {
197        // NULL destination for pure preflighting: empty dummy string
198        // otherwise, alias the destination buffer
199        res.setTo(result, 0, resultLength);
200    }
201
202    FieldPosition fp;
203
204    if(pos != 0)
205        fp.setField(pos->field);
206
207    ((const NumberFormat*)fmt)->format(number, res, fp, *status);
208
209    if(pos != 0) {
210        pos->beginIndex = fp.getBeginIndex();
211        pos->endIndex = fp.getEndIndex();
212    }
213
214    return res.extract(result, resultLength, *status);
215}
216
217U_CAPI int32_t U_EXPORT2
218unum_formatDouble(    const    UNumberFormat*  fmt,
219            double          number,
220            UChar*          result,
221            int32_t         resultLength,
222            UFieldPosition  *pos, /* 0 if ignore */
223            UErrorCode*     status)
224{
225
226  if(U_FAILURE(*status)) return -1;
227
228  UnicodeString res;
229  if(!(result==NULL && resultLength==0)) {
230    // NULL destination for pure preflighting: empty dummy string
231    // otherwise, alias the destination buffer
232    res.setTo(result, 0, resultLength);
233  }
234
235  FieldPosition fp;
236
237  if(pos != 0)
238    fp.setField(pos->field);
239
240  ((const NumberFormat*)fmt)->format(number, res, fp, *status);
241
242  if(pos != 0) {
243    pos->beginIndex = fp.getBeginIndex();
244    pos->endIndex = fp.getEndIndex();
245  }
246
247  return res.extract(result, resultLength, *status);
248}
249
250
251U_CAPI int32_t U_EXPORT2
252unum_formatDecimal(const    UNumberFormat*  fmt,
253            const char *    number,
254            int32_t         length,
255            UChar*          result,
256            int32_t         resultLength,
257            UFieldPosition  *pos, /* 0 if ignore */
258            UErrorCode*     status) {
259
260    if(U_FAILURE(*status)) {
261        return -1;
262    }
263    if ((result == NULL && resultLength != 0) || resultLength < 0) {
264        *status = U_ILLEGAL_ARGUMENT_ERROR;
265        return -1;
266    }
267
268    FieldPosition fp;
269    if(pos != 0) {
270        fp.setField(pos->field);
271    }
272
273    if (length < 0) {
274        length = uprv_strlen(number);
275    }
276    StringPiece numSP(number, length);
277    Formattable numFmtbl(numSP, *status);
278
279    UnicodeString resultStr;
280    if (resultLength > 0) {
281        // Alias the destination buffer.
282        resultStr.setTo(result, 0, resultLength);
283    }
284    ((const NumberFormat*)fmt)->format(numFmtbl, resultStr, fp, *status);
285    if(pos != 0) {
286        pos->beginIndex = fp.getBeginIndex();
287        pos->endIndex = fp.getEndIndex();
288    }
289    return resultStr.extract(result, resultLength, *status);
290}
291
292
293
294
295U_CAPI int32_t U_EXPORT2
296unum_formatDoubleCurrency(const UNumberFormat* fmt,
297                          double number,
298                          UChar* currency,
299                          UChar* result,
300                          int32_t resultLength,
301                          UFieldPosition* pos, /* ignored if 0 */
302                          UErrorCode* status) {
303    if (U_FAILURE(*status)) return -1;
304
305    UnicodeString res;
306    if (!(result==NULL && resultLength==0)) {
307        // NULL destination for pure preflighting: empty dummy string
308        // otherwise, alias the destination buffer
309        res.setTo(result, 0, resultLength);
310    }
311
312    FieldPosition fp;
313    if (pos != 0) {
314        fp.setField(pos->field);
315    }
316    CurrencyAmount *tempCurrAmnt = new CurrencyAmount(number, currency, *status);
317    // Check for null pointer.
318    if (tempCurrAmnt == NULL) {
319        *status = U_MEMORY_ALLOCATION_ERROR;
320        return -1;
321    }
322    Formattable n(tempCurrAmnt);
323    ((const NumberFormat*)fmt)->format(n, res, fp, *status);
324
325    if (pos != 0) {
326        pos->beginIndex = fp.getBeginIndex();
327        pos->endIndex = fp.getEndIndex();
328    }
329
330    return res.extract(result, resultLength, *status);
331}
332
333static void
334parseRes(Formattable& res,
335         const   UNumberFormat*  fmt,
336         const   UChar*          text,
337         int32_t         textLength,
338         int32_t         *parsePos /* 0 = start */,
339         UErrorCode      *status)
340{
341    if(U_FAILURE(*status))
342        return;
343
344    const UnicodeString src((UBool)(textLength == -1), text, textLength);
345    ParsePosition pp;
346
347    if(parsePos != 0)
348        pp.setIndex(*parsePos);
349
350    ((const NumberFormat*)fmt)->parse(src, res, pp);
351
352    if(pp.getErrorIndex() != -1) {
353        *status = U_PARSE_ERROR;
354        if(parsePos != 0) {
355            *parsePos = pp.getErrorIndex();
356        }
357    } else if(parsePos != 0) {
358        *parsePos = pp.getIndex();
359    }
360}
361
362U_CAPI int32_t U_EXPORT2
363unum_parse(    const   UNumberFormat*  fmt,
364        const   UChar*          text,
365        int32_t         textLength,
366        int32_t         *parsePos /* 0 = start */,
367        UErrorCode      *status)
368{
369    Formattable res;
370    parseRes(res, fmt, text, textLength, parsePos, status);
371    return res.getLong(*status);
372}
373
374U_CAPI int64_t U_EXPORT2
375unum_parseInt64(    const   UNumberFormat*  fmt,
376        const   UChar*          text,
377        int32_t         textLength,
378        int32_t         *parsePos /* 0 = start */,
379        UErrorCode      *status)
380{
381    Formattable res;
382    parseRes(res, fmt, text, textLength, parsePos, status);
383    return res.getInt64(*status);
384}
385
386U_CAPI double U_EXPORT2
387unum_parseDouble(    const   UNumberFormat*  fmt,
388            const   UChar*          text,
389            int32_t         textLength,
390            int32_t         *parsePos /* 0 = start */,
391            UErrorCode      *status)
392{
393    Formattable res;
394    parseRes(res, fmt, text, textLength, parsePos, status);
395    return res.getDouble(*status);
396}
397
398U_CAPI int32_t U_EXPORT2
399unum_parseDecimal(const UNumberFormat*  fmt,
400            const UChar*    text,
401            int32_t         textLength,
402            int32_t         *parsePos /* 0 = start */,
403            char            *outBuf,
404            int32_t         outBufLength,
405            UErrorCode      *status)
406{
407    if (U_FAILURE(*status)) {
408        return -1;
409    }
410    if ((outBuf == NULL && outBufLength != 0) || outBufLength < 0) {
411        *status = U_ILLEGAL_ARGUMENT_ERROR;
412        return -1;
413    }
414    Formattable res;
415    parseRes(res, fmt, text, textLength, parsePos, status);
416    StringPiece sp = res.getDecimalNumber(*status);
417    if (U_FAILURE(*status)) {
418       return -1;
419    } else if (sp.size() > outBufLength) {
420        *status = U_BUFFER_OVERFLOW_ERROR;
421    } else if (sp.size() == outBufLength) {
422        uprv_strncpy(outBuf, sp.data(), sp.size());
423        *status = U_STRING_NOT_TERMINATED_WARNING;
424    } else {
425        U_ASSERT(outBufLength > 0);
426        uprv_strcpy(outBuf, sp.data());
427    }
428    return sp.size();
429}
430
431U_CAPI double U_EXPORT2
432unum_parseDoubleCurrency(const UNumberFormat* fmt,
433                         const UChar* text,
434                         int32_t textLength,
435                         int32_t* parsePos, /* 0 = start */
436                         UChar* currency,
437                         UErrorCode* status) {
438    double doubleVal = 0.0;
439    currency[0] = 0;
440    if (U_FAILURE(*status)) {
441        return doubleVal;
442    }
443    const UnicodeString src((UBool)(textLength == -1), text, textLength);
444    ParsePosition pp;
445    if (parsePos != NULL) {
446        pp.setIndex(*parsePos);
447    }
448    *status = U_PARSE_ERROR; // assume failure, reset if succeed
449    LocalPointer<CurrencyAmount> currAmt(((const NumberFormat*)fmt)->parseCurrency(src, pp));
450    if (pp.getErrorIndex() != -1) {
451        if (parsePos != NULL) {
452            *parsePos = pp.getErrorIndex();
453        }
454    } else {
455        if (parsePos != NULL) {
456            *parsePos = pp.getIndex();
457        }
458        if (pp.getIndex() > 0) {
459            *status = U_ZERO_ERROR;
460            u_strcpy(currency, currAmt->getISOCurrency());
461            doubleVal = currAmt->getNumber().getDouble(*status);
462        }
463    }
464    return doubleVal;
465}
466
467U_CAPI const char* U_EXPORT2
468unum_getAvailable(int32_t index)
469{
470    return uloc_getAvailable(index);
471}
472
473U_CAPI int32_t U_EXPORT2
474unum_countAvailable()
475{
476    return uloc_countAvailable();
477}
478
479U_CAPI int32_t U_EXPORT2
480unum_getAttribute(const UNumberFormat*          fmt,
481          UNumberFormatAttribute  attr)
482{
483  const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
484  if ( attr == UNUM_LENIENT_PARSE ) {
485    // Supported for all subclasses
486    return nf->isLenient();
487  }
488
489  // The remaining attributea are only supported for DecimalFormat
490  const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
491  if (df != NULL) {
492    UErrorCode ignoredStatus = U_ZERO_ERROR;
493    return df->getAttribute( attr, ignoredStatus );
494  }
495
496  return -1;
497}
498
499U_CAPI void U_EXPORT2
500unum_setAttribute(    UNumberFormat*          fmt,
501            UNumberFormatAttribute  attr,
502            int32_t                 newValue)
503{
504  NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
505  if ( attr == UNUM_LENIENT_PARSE ) {
506    // Supported for all subclasses
507    // keep this here as the class may not be a DecimalFormat
508    return nf->setLenient(newValue != 0);
509  }
510  // The remaining attributea are only supported for DecimalFormat
511  DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
512  if (df != NULL) {
513    UErrorCode ignoredStatus = U_ZERO_ERROR;
514    df->setAttribute(attr, newValue, ignoredStatus);
515  }
516}
517
518U_CAPI double U_EXPORT2
519unum_getDoubleAttribute(const UNumberFormat*          fmt,
520          UNumberFormatAttribute  attr)
521{
522    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
523    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
524    if (df != NULL &&  attr == UNUM_ROUNDING_INCREMENT) {
525        return df->getRoundingIncrement();
526    } else {
527        return -1.0;
528    }
529}
530
531U_CAPI void U_EXPORT2
532unum_setDoubleAttribute(    UNumberFormat*          fmt,
533            UNumberFormatAttribute  attr,
534            double                 newValue)
535{
536    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
537    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
538    if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) {
539        df->setRoundingIncrement(newValue);
540    }
541}
542
543U_CAPI int32_t U_EXPORT2
544unum_getTextAttribute(const UNumberFormat*  fmt,
545            UNumberFormatTextAttribute      tag,
546            UChar*                          result,
547            int32_t                         resultLength,
548            UErrorCode*                     status)
549{
550    if(U_FAILURE(*status))
551        return -1;
552
553    UnicodeString res;
554    if(!(result==NULL && resultLength==0)) {
555        // NULL destination for pure preflighting: empty dummy string
556        // otherwise, alias the destination buffer
557        res.setTo(result, 0, resultLength);
558    }
559
560    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
561    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
562    if (df != NULL) {
563        switch(tag) {
564        case UNUM_POSITIVE_PREFIX:
565            df->getPositivePrefix(res);
566            break;
567
568        case UNUM_POSITIVE_SUFFIX:
569            df->getPositiveSuffix(res);
570            break;
571
572        case UNUM_NEGATIVE_PREFIX:
573            df->getNegativePrefix(res);
574            break;
575
576        case UNUM_NEGATIVE_SUFFIX:
577            df->getNegativeSuffix(res);
578            break;
579
580        case UNUM_PADDING_CHARACTER:
581            res = df->getPadCharacterString();
582            break;
583
584        case UNUM_CURRENCY_CODE:
585            res = UnicodeString(df->getCurrency());
586            break;
587
588        default:
589            *status = U_UNSUPPORTED_ERROR;
590            return -1;
591        }
592    } else {
593        const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
594        U_ASSERT(rbnf != NULL);
595        if (tag == UNUM_DEFAULT_RULESET) {
596            res = rbnf->getDefaultRuleSetName();
597        } else if (tag == UNUM_PUBLIC_RULESETS) {
598            int32_t count = rbnf->getNumberOfRuleSetNames();
599            for (int i = 0; i < count; ++i) {
600                res += rbnf->getRuleSetName(i);
601                res += (UChar)0x003b; // semicolon
602            }
603        } else {
604            *status = U_UNSUPPORTED_ERROR;
605            return -1;
606        }
607    }
608
609    return res.extract(result, resultLength, *status);
610}
611
612U_CAPI void U_EXPORT2
613unum_setTextAttribute(    UNumberFormat*                    fmt,
614            UNumberFormatTextAttribute      tag,
615            const    UChar*                            newValue,
616            int32_t                            newValueLength,
617            UErrorCode                        *status)
618{
619    if(U_FAILURE(*status))
620        return;
621
622    UnicodeString val(newValue, newValueLength);
623    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
624    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
625    if (df != NULL) {
626      switch(tag) {
627      case UNUM_POSITIVE_PREFIX:
628        df->setPositivePrefix(val);
629        break;
630
631      case UNUM_POSITIVE_SUFFIX:
632        df->setPositiveSuffix(val);
633        break;
634
635      case UNUM_NEGATIVE_PREFIX:
636        df->setNegativePrefix(val);
637        break;
638
639      case UNUM_NEGATIVE_SUFFIX:
640        df->setNegativeSuffix(val);
641        break;
642
643      case UNUM_PADDING_CHARACTER:
644        df->setPadCharacter(val);
645        break;
646
647      case UNUM_CURRENCY_CODE:
648        df->setCurrency(val.getTerminatedBuffer(), *status);
649        break;
650
651      default:
652        *status = U_UNSUPPORTED_ERROR;
653        break;
654      }
655    } else {
656      RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf);
657      U_ASSERT(rbnf != NULL);
658      if (tag == UNUM_DEFAULT_RULESET) {
659        rbnf->setDefaultRuleSet(val, *status);
660      } else {
661        *status = U_UNSUPPORTED_ERROR;
662      }
663    }
664}
665
666U_CAPI int32_t U_EXPORT2
667unum_toPattern(    const    UNumberFormat*          fmt,
668        UBool                  isPatternLocalized,
669        UChar*                  result,
670        int32_t                 resultLength,
671        UErrorCode*             status)
672{
673    if(U_FAILURE(*status))
674        return -1;
675
676    UnicodeString pat;
677    if(!(result==NULL && resultLength==0)) {
678        // NULL destination for pure preflighting: empty dummy string
679        // otherwise, alias the destination buffer
680        pat.setTo(result, 0, resultLength);
681    }
682
683    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
684    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
685    if (df != NULL) {
686      if(isPatternLocalized)
687        df->toLocalizedPattern(pat);
688      else
689        df->toPattern(pat);
690    } else {
691      const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
692      U_ASSERT(rbnf != NULL);
693      pat = rbnf->getRules();
694    }
695    return pat.extract(result, resultLength, *status);
696}
697
698U_CAPI int32_t U_EXPORT2
699unum_getSymbol(const UNumberFormat *fmt,
700               UNumberFormatSymbol symbol,
701               UChar *buffer,
702               int32_t size,
703               UErrorCode *status)
704{
705    if(status==NULL || U_FAILURE(*status)) {
706        return 0;
707    }
708    if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
709        *status=U_ILLEGAL_ARGUMENT_ERROR;
710        return 0;
711    }
712    const NumberFormat *nf = reinterpret_cast<const NumberFormat *>(fmt);
713    const DecimalFormat *dcf = dynamic_cast<const DecimalFormat *>(nf);
714    if (dcf == NULL) {
715      *status = U_UNSUPPORTED_ERROR;
716      return 0;
717    }
718
719    return dcf->
720      getDecimalFormatSymbols()->
721        getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol).
722          extract(buffer, size, *status);
723}
724
725U_CAPI void U_EXPORT2
726unum_setSymbol(UNumberFormat *fmt,
727               UNumberFormatSymbol symbol,
728               const UChar *value,
729               int32_t length,
730               UErrorCode *status)
731{
732    if(status==NULL || U_FAILURE(*status)) {
733        return;
734    }
735    if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) {
736        *status=U_ILLEGAL_ARGUMENT_ERROR;
737        return;
738    }
739    NumberFormat *nf = reinterpret_cast<NumberFormat *>(fmt);
740    DecimalFormat *dcf = dynamic_cast<DecimalFormat *>(nf);
741    if (dcf == NULL) {
742      *status = U_UNSUPPORTED_ERROR;
743      return;
744    }
745
746    DecimalFormatSymbols symbols(*dcf->getDecimalFormatSymbols());
747    symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol,
748        UnicodeString(value, length));  /* UnicodeString can handle the case when length = -1. */
749    dcf->setDecimalFormatSymbols(symbols);
750}
751
752U_CAPI void U_EXPORT2
753unum_applyPattern(  UNumberFormat  *fmt,
754                    UBool          localized,
755                    const UChar    *pattern,
756                    int32_t        patternLength,
757                    UParseError    *parseError,
758                    UErrorCode*    status)
759{
760    UErrorCode tStatus = U_ZERO_ERROR;
761    UParseError tParseError;
762
763    if(parseError == NULL){
764        parseError = &tParseError;
765    }
766
767    if(status==NULL){
768        status = &tStatus;
769    }
770
771    int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
772    const UnicodeString pat((UChar*)pattern, len, len);
773
774    // Verify if the object passed is a DecimalFormat object
775    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
776    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
777    if (df != NULL) {
778      if(localized) {
779        df->applyLocalizedPattern(pat,*parseError, *status);
780      } else {
781        df->applyPattern(pat,*parseError, *status);
782      }
783    } else {
784      *status = U_UNSUPPORTED_ERROR;
785      return;
786    }
787}
788
789U_CAPI const char* U_EXPORT2
790unum_getLocaleByType(const UNumberFormat *fmt,
791                     ULocDataLocaleType type,
792                     UErrorCode* status)
793{
794    if (fmt == NULL) {
795        if (U_SUCCESS(*status)) {
796            *status = U_ILLEGAL_ARGUMENT_ERROR;
797        }
798        return NULL;
799    }
800    return ((const Format*)fmt)->getLocaleID(type, *status);
801}
802
803U_CAPI void U_EXPORT2
804unum_setContext(UNumberFormat* fmt, UDisplayContext value, UErrorCode* status)
805{
806    if (U_FAILURE(*status)) {
807        return;
808    }
809    ((NumberFormat*)fmt)->setContext(value, *status);
810    return;
811}
812
813U_CAPI UDisplayContext U_EXPORT2
814unum_getContext(const UNumberFormat *fmt, UDisplayContextType type, UErrorCode* status)
815{
816    if (U_FAILURE(*status)) {
817        return (UDisplayContext)0;
818    }
819    return ((const NumberFormat*)fmt)->getContext(type, *status);
820}
821
822U_INTERNAL UFormattable * U_EXPORT2
823unum_parseToUFormattable(const UNumberFormat* fmt,
824                         UFormattable *result,
825                         const UChar* text,
826                         int32_t textLength,
827                         int32_t* parsePos, /* 0 = start */
828                         UErrorCode* status) {
829  UFormattable *newFormattable = NULL;
830  if (U_FAILURE(*status)) return result;
831  if (fmt == NULL || (text==NULL && textLength!=0)) {
832    *status = U_ILLEGAL_ARGUMENT_ERROR;
833    return result;
834  }
835  if (result == NULL) { // allocate if not allocated.
836    newFormattable = result = ufmt_open(status);
837  }
838  parseRes(*(Formattable::fromUFormattable(result)), fmt, text, textLength, parsePos, status);
839  if (U_FAILURE(*status) && newFormattable != NULL) {
840    ufmt_close(newFormattable);
841    result = NULL; // deallocate if there was a parse error
842  }
843  return result;
844}
845
846U_INTERNAL int32_t U_EXPORT2
847unum_formatUFormattable(const UNumberFormat* fmt,
848                        const UFormattable *number,
849                        UChar *result,
850                        int32_t resultLength,
851                        UFieldPosition *pos, /* ignored if 0 */
852                        UErrorCode *status) {
853    if (U_FAILURE(*status)) {
854      return 0;
855    }
856    if (fmt == NULL || number==NULL ||
857        (result==NULL ? resultLength!=0 : resultLength<0)) {
858      *status = U_ILLEGAL_ARGUMENT_ERROR;
859      return 0;
860    }
861    UnicodeString res(result, 0, resultLength);
862
863    FieldPosition fp;
864
865    if(pos != 0)
866        fp.setField(pos->field);
867
868    ((const NumberFormat*)fmt)->format(*(Formattable::fromUFormattable(number)), res, fp, *status);
869
870    if(pos != 0) {
871        pos->beginIndex = fp.getBeginIndex();
872        pos->endIndex = fp.getEndIndex();
873    }
874
875    return res.extract(result, resultLength, *status);
876}
877
878#endif /* #if !UCONFIG_NO_FORMATTING */
879