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