• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
37 U_NAMESPACE_USE
38 
39 
40 U_CAPI UNumberFormat* U_EXPORT2
unum_open(UNumberFormatStyle style,const UChar * pattern,int32_t patternLength,const char * locale,UParseError * parseErr,UErrorCode * status)41 unum_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 
141 U_CAPI void U_EXPORT2
unum_close(UNumberFormat * fmt)142 unum_close(UNumberFormat* fmt)
143 {
144     delete (NumberFormat*) fmt;
145 }
146 
147 U_CAPI UNumberFormat* U_EXPORT2
unum_clone(const UNumberFormat * fmt,UErrorCode * status)148 unum_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 
173 U_CAPI int32_t U_EXPORT2
unum_format(const UNumberFormat * fmt,int32_t number,UChar * result,int32_t resultLength,UFieldPosition * pos,UErrorCode * status)174 unum_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 
184 U_CAPI int32_t U_EXPORT2
unum_formatInt64(const UNumberFormat * fmt,int64_t number,UChar * result,int32_t resultLength,UFieldPosition * pos,UErrorCode * status)185 unum_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 
217 U_CAPI int32_t U_EXPORT2
unum_formatDouble(const UNumberFormat * fmt,double number,UChar * result,int32_t resultLength,UFieldPosition * pos,UErrorCode * status)218 unum_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 
251 U_CAPI int32_t U_EXPORT2
unum_formatDecimal(const UNumberFormat * fmt,const char * number,int32_t length,UChar * result,int32_t resultLength,UFieldPosition * pos,UErrorCode * status)252 unum_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 
295 U_CAPI int32_t U_EXPORT2
unum_formatDoubleCurrency(const UNumberFormat * fmt,double number,UChar * currency,UChar * result,int32_t resultLength,UFieldPosition * pos,UErrorCode * status)296 unum_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 
333 static void
parseRes(Formattable & res,const UNumberFormat * fmt,const UChar * text,int32_t textLength,int32_t * parsePos,UErrorCode * status)334 parseRes(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 
362 U_CAPI int32_t U_EXPORT2
unum_parse(const UNumberFormat * fmt,const UChar * text,int32_t textLength,int32_t * parsePos,UErrorCode * status)363 unum_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 
374 U_CAPI int64_t U_EXPORT2
unum_parseInt64(const UNumberFormat * fmt,const UChar * text,int32_t textLength,int32_t * parsePos,UErrorCode * status)375 unum_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 
386 U_CAPI double U_EXPORT2
unum_parseDouble(const UNumberFormat * fmt,const UChar * text,int32_t textLength,int32_t * parsePos,UErrorCode * status)387 unum_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 
398 U_CAPI int32_t U_EXPORT2
unum_parseDecimal(const UNumberFormat * fmt,const UChar * text,int32_t textLength,int32_t * parsePos,char * outBuf,int32_t outBufLength,UErrorCode * status)399 unum_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 
431 U_CAPI double U_EXPORT2
unum_parseDoubleCurrency(const UNumberFormat * fmt,const UChar * text,int32_t textLength,int32_t * parsePos,UChar * currency,UErrorCode * status)432 unum_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 
467 U_CAPI const char* U_EXPORT2
unum_getAvailable(int32_t index)468 unum_getAvailable(int32_t index)
469 {
470     return uloc_getAvailable(index);
471 }
472 
473 U_CAPI int32_t U_EXPORT2
unum_countAvailable()474 unum_countAvailable()
475 {
476     return uloc_countAvailable();
477 }
478 
479 U_CAPI int32_t U_EXPORT2
unum_getAttribute(const UNumberFormat * fmt,UNumberFormatAttribute attr)480 unum_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 
499 U_CAPI void U_EXPORT2
unum_setAttribute(UNumberFormat * fmt,UNumberFormatAttribute attr,int32_t newValue)500 unum_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 
518 U_CAPI double U_EXPORT2
unum_getDoubleAttribute(const UNumberFormat * fmt,UNumberFormatAttribute attr)519 unum_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 
531 U_CAPI void U_EXPORT2
unum_setDoubleAttribute(UNumberFormat * fmt,UNumberFormatAttribute attr,double newValue)532 unum_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 
543 U_CAPI int32_t U_EXPORT2
unum_getTextAttribute(const UNumberFormat * fmt,UNumberFormatTextAttribute tag,UChar * result,int32_t resultLength,UErrorCode * status)544 unum_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 
612 U_CAPI void U_EXPORT2
unum_setTextAttribute(UNumberFormat * fmt,UNumberFormatTextAttribute tag,const UChar * newValue,int32_t newValueLength,UErrorCode * status)613 unum_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 
666 U_CAPI int32_t U_EXPORT2
unum_toPattern(const UNumberFormat * fmt,UBool isPatternLocalized,UChar * result,int32_t resultLength,UErrorCode * status)667 unum_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 
698 U_CAPI int32_t U_EXPORT2
unum_getSymbol(const UNumberFormat * fmt,UNumberFormatSymbol symbol,UChar * buffer,int32_t size,UErrorCode * status)699 unum_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 
725 U_CAPI void U_EXPORT2
unum_setSymbol(UNumberFormat * fmt,UNumberFormatSymbol symbol,const UChar * value,int32_t length,UErrorCode * status)726 unum_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 
752 U_CAPI void U_EXPORT2
unum_applyPattern(UNumberFormat * fmt,UBool localized,const UChar * pattern,int32_t patternLength,UParseError * parseError,UErrorCode * status)753 unum_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 
789 U_CAPI const char* U_EXPORT2
unum_getLocaleByType(const UNumberFormat * fmt,ULocDataLocaleType type,UErrorCode * status)790 unum_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 
803 U_CAPI void U_EXPORT2
unum_setContext(UNumberFormat * fmt,UDisplayContext value,UErrorCode * status)804 unum_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 
813 U_CAPI UDisplayContext U_EXPORT2
unum_getContext(const UNumberFormat * fmt,UDisplayContextType type,UErrorCode * status)814 unum_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 
822 U_INTERNAL UFormattable * U_EXPORT2
unum_parseToUFormattable(const UNumberFormat * fmt,UFormattable * result,const UChar * text,int32_t textLength,int32_t * parsePos,UErrorCode * status)823 unum_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 
846 U_INTERNAL int32_t U_EXPORT2
unum_formatUFormattable(const UNumberFormat * fmt,const UFormattable * number,UChar * result,int32_t resultLength,UFieldPosition * pos,UErrorCode * status)847 unum_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