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