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