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