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