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