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