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