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