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