1 // Copyright (C) 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
251 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)252 unum_formatDecimal(const UNumberFormat* fmt,
253 const char * number,
254 int32_t length,
255 UChar* result,
256 int32_t resultLength,
257 UFieldPosition *pos, /* 0 if ignore */
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 FieldPosition fp;
269 if(pos != 0) {
270 fp.setField(pos->field);
271 }
272
273 if (length < 0) {
274 length = uprv_strlen(number);
275 }
276 StringPiece numSP(number, length);
277 Formattable numFmtbl(numSP, *status);
278
279 UnicodeString resultStr;
280 if (resultLength > 0) {
281 // Alias the destination buffer.
282 resultStr.setTo(result, 0, resultLength);
283 }
284 ((const NumberFormat*)fmt)->format(numFmtbl, resultStr, fp, *status);
285 if(pos != 0) {
286 pos->beginIndex = fp.getBeginIndex();
287 pos->endIndex = fp.getEndIndex();
288 }
289 return resultStr.extract(result, resultLength, *status);
290 }
291
292
293
294
295 U_CAPI int32_t U_EXPORT2
unum_formatDoubleCurrency(const UNumberFormat * fmt,double number,UChar * currency,UChar * result,int32_t resultLength,UFieldPosition * pos,UErrorCode * status)296 unum_formatDoubleCurrency(const UNumberFormat* fmt,
297 double number,
298 UChar* currency,
299 UChar* result,
300 int32_t resultLength,
301 UFieldPosition* pos, /* ignored if 0 */
302 UErrorCode* status) {
303 if (U_FAILURE(*status)) return -1;
304
305 UnicodeString res;
306 if (!(result==NULL && resultLength==0)) {
307 // NULL destination for pure preflighting: empty dummy string
308 // otherwise, alias the destination buffer
309 res.setTo(result, 0, resultLength);
310 }
311
312 FieldPosition fp;
313 if (pos != 0) {
314 fp.setField(pos->field);
315 }
316 CurrencyAmount *tempCurrAmnt = new CurrencyAmount(number, currency, *status);
317 // Check for null pointer.
318 if (tempCurrAmnt == NULL) {
319 *status = U_MEMORY_ALLOCATION_ERROR;
320 return -1;
321 }
322 Formattable n(tempCurrAmnt);
323 ((const NumberFormat*)fmt)->format(n, res, fp, *status);
324
325 if (pos != 0) {
326 pos->beginIndex = fp.getBeginIndex();
327 pos->endIndex = fp.getEndIndex();
328 }
329
330 return res.extract(result, resultLength, *status);
331 }
332
333 static void
parseRes(Formattable & res,const UNumberFormat * fmt,const UChar * text,int32_t textLength,int32_t * parsePos,UErrorCode * status)334 parseRes(Formattable& res,
335 const UNumberFormat* fmt,
336 const UChar* text,
337 int32_t textLength,
338 int32_t *parsePos /* 0 = start */,
339 UErrorCode *status)
340 {
341 if(U_FAILURE(*status))
342 return;
343
344 const UnicodeString src((UBool)(textLength == -1), text, textLength);
345 ParsePosition pp;
346
347 if(parsePos != 0)
348 pp.setIndex(*parsePos);
349
350 ((const NumberFormat*)fmt)->parse(src, res, pp);
351
352 if(pp.getErrorIndex() != -1) {
353 *status = U_PARSE_ERROR;
354 if(parsePos != 0) {
355 *parsePos = pp.getErrorIndex();
356 }
357 } else if(parsePos != 0) {
358 *parsePos = pp.getIndex();
359 }
360 }
361
362 U_CAPI int32_t U_EXPORT2
unum_parse(const UNumberFormat * fmt,const UChar * text,int32_t textLength,int32_t * parsePos,UErrorCode * status)363 unum_parse( const UNumberFormat* fmt,
364 const UChar* text,
365 int32_t textLength,
366 int32_t *parsePos /* 0 = start */,
367 UErrorCode *status)
368 {
369 Formattable res;
370 parseRes(res, fmt, text, textLength, parsePos, status);
371 return res.getLong(*status);
372 }
373
374 U_CAPI int64_t U_EXPORT2
unum_parseInt64(const UNumberFormat * fmt,const UChar * text,int32_t textLength,int32_t * parsePos,UErrorCode * status)375 unum_parseInt64( const UNumberFormat* fmt,
376 const UChar* text,
377 int32_t textLength,
378 int32_t *parsePos /* 0 = start */,
379 UErrorCode *status)
380 {
381 Formattable res;
382 parseRes(res, fmt, text, textLength, parsePos, status);
383 return res.getInt64(*status);
384 }
385
386 U_CAPI double U_EXPORT2
unum_parseDouble(const UNumberFormat * fmt,const UChar * text,int32_t textLength,int32_t * parsePos,UErrorCode * status)387 unum_parseDouble( const UNumberFormat* fmt,
388 const UChar* text,
389 int32_t textLength,
390 int32_t *parsePos /* 0 = start */,
391 UErrorCode *status)
392 {
393 Formattable res;
394 parseRes(res, fmt, text, textLength, parsePos, status);
395 return res.getDouble(*status);
396 }
397
398 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)399 unum_parseDecimal(const UNumberFormat* fmt,
400 const UChar* text,
401 int32_t textLength,
402 int32_t *parsePos /* 0 = start */,
403 char *outBuf,
404 int32_t outBufLength,
405 UErrorCode *status)
406 {
407 if (U_FAILURE(*status)) {
408 return -1;
409 }
410 if ((outBuf == NULL && outBufLength != 0) || outBufLength < 0) {
411 *status = U_ILLEGAL_ARGUMENT_ERROR;
412 return -1;
413 }
414 Formattable res;
415 parseRes(res, fmt, text, textLength, parsePos, status);
416 StringPiece sp = res.getDecimalNumber(*status);
417 if (U_FAILURE(*status)) {
418 return -1;
419 } else if (sp.size() > outBufLength) {
420 *status = U_BUFFER_OVERFLOW_ERROR;
421 } else if (sp.size() == outBufLength) {
422 uprv_strncpy(outBuf, sp.data(), sp.size());
423 *status = U_STRING_NOT_TERMINATED_WARNING;
424 } else {
425 U_ASSERT(outBufLength > 0);
426 uprv_strcpy(outBuf, sp.data());
427 }
428 return sp.size();
429 }
430
431 U_CAPI double U_EXPORT2
unum_parseDoubleCurrency(const UNumberFormat * fmt,const UChar * text,int32_t textLength,int32_t * parsePos,UChar * currency,UErrorCode * status)432 unum_parseDoubleCurrency(const UNumberFormat* fmt,
433 const UChar* text,
434 int32_t textLength,
435 int32_t* parsePos, /* 0 = start */
436 UChar* currency,
437 UErrorCode* status) {
438 double doubleVal = 0.0;
439 currency[0] = 0;
440 if (U_FAILURE(*status)) {
441 return doubleVal;
442 }
443 const UnicodeString src((UBool)(textLength == -1), text, textLength);
444 ParsePosition pp;
445 if (parsePos != NULL) {
446 pp.setIndex(*parsePos);
447 }
448 *status = U_PARSE_ERROR; // assume failure, reset if succeed
449 LocalPointer<CurrencyAmount> currAmt(((const NumberFormat*)fmt)->parseCurrency(src, pp));
450 if (pp.getErrorIndex() != -1) {
451 if (parsePos != NULL) {
452 *parsePos = pp.getErrorIndex();
453 }
454 } else {
455 if (parsePos != NULL) {
456 *parsePos = pp.getIndex();
457 }
458 if (pp.getIndex() > 0) {
459 *status = U_ZERO_ERROR;
460 u_strcpy(currency, currAmt->getISOCurrency());
461 doubleVal = currAmt->getNumber().getDouble(*status);
462 }
463 }
464 return doubleVal;
465 }
466
467 U_CAPI const char* U_EXPORT2
unum_getAvailable(int32_t index)468 unum_getAvailable(int32_t index)
469 {
470 return uloc_getAvailable(index);
471 }
472
473 U_CAPI int32_t U_EXPORT2
unum_countAvailable()474 unum_countAvailable()
475 {
476 return uloc_countAvailable();
477 }
478
479 U_CAPI int32_t U_EXPORT2
unum_getAttribute(const UNumberFormat * fmt,UNumberFormatAttribute attr)480 unum_getAttribute(const UNumberFormat* fmt,
481 UNumberFormatAttribute attr)
482 {
483 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
484 if ( attr == UNUM_LENIENT_PARSE ) {
485 // Supported for all subclasses
486 return nf->isLenient();
487 }
488
489 // The remaining attributea are only supported for DecimalFormat
490 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
491 if (df != NULL) {
492 UErrorCode ignoredStatus = U_ZERO_ERROR;
493 return df->getAttribute( attr, ignoredStatus );
494 }
495
496 return -1;
497 }
498
499 U_CAPI void U_EXPORT2
unum_setAttribute(UNumberFormat * fmt,UNumberFormatAttribute attr,int32_t newValue)500 unum_setAttribute( UNumberFormat* fmt,
501 UNumberFormatAttribute attr,
502 int32_t newValue)
503 {
504 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
505 if ( attr == UNUM_LENIENT_PARSE ) {
506 // Supported for all subclasses
507 // keep this here as the class may not be a DecimalFormat
508 return nf->setLenient(newValue != 0);
509 }
510 // The remaining attributea are only supported for DecimalFormat
511 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
512 if (df != NULL) {
513 UErrorCode ignoredStatus = U_ZERO_ERROR;
514 df->setAttribute(attr, newValue, ignoredStatus);
515 }
516 }
517
518 U_CAPI double U_EXPORT2
unum_getDoubleAttribute(const UNumberFormat * fmt,UNumberFormatAttribute attr)519 unum_getDoubleAttribute(const UNumberFormat* fmt,
520 UNumberFormatAttribute attr)
521 {
522 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
523 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
524 if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) {
525 return df->getRoundingIncrement();
526 } else {
527 return -1.0;
528 }
529 }
530
531 U_CAPI void U_EXPORT2
unum_setDoubleAttribute(UNumberFormat * fmt,UNumberFormatAttribute attr,double newValue)532 unum_setDoubleAttribute( UNumberFormat* fmt,
533 UNumberFormatAttribute attr,
534 double newValue)
535 {
536 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
537 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
538 if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) {
539 df->setRoundingIncrement(newValue);
540 }
541 }
542
543 U_CAPI int32_t U_EXPORT2
unum_getTextAttribute(const UNumberFormat * fmt,UNumberFormatTextAttribute tag,UChar * result,int32_t resultLength,UErrorCode * status)544 unum_getTextAttribute(const UNumberFormat* fmt,
545 UNumberFormatTextAttribute tag,
546 UChar* result,
547 int32_t resultLength,
548 UErrorCode* status)
549 {
550 if(U_FAILURE(*status))
551 return -1;
552
553 UnicodeString res;
554 if(!(result==NULL && resultLength==0)) {
555 // NULL destination for pure preflighting: empty dummy string
556 // otherwise, alias the destination buffer
557 res.setTo(result, 0, resultLength);
558 }
559
560 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
561 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
562 if (df != NULL) {
563 switch(tag) {
564 case UNUM_POSITIVE_PREFIX:
565 df->getPositivePrefix(res);
566 break;
567
568 case UNUM_POSITIVE_SUFFIX:
569 df->getPositiveSuffix(res);
570 break;
571
572 case UNUM_NEGATIVE_PREFIX:
573 df->getNegativePrefix(res);
574 break;
575
576 case UNUM_NEGATIVE_SUFFIX:
577 df->getNegativeSuffix(res);
578 break;
579
580 case UNUM_PADDING_CHARACTER:
581 res = df->getPadCharacterString();
582 break;
583
584 case UNUM_CURRENCY_CODE:
585 res = UnicodeString(df->getCurrency());
586 break;
587
588 default:
589 *status = U_UNSUPPORTED_ERROR;
590 return -1;
591 }
592 } else {
593 const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
594 U_ASSERT(rbnf != NULL);
595 if (tag == UNUM_DEFAULT_RULESET) {
596 res = rbnf->getDefaultRuleSetName();
597 } else if (tag == UNUM_PUBLIC_RULESETS) {
598 int32_t count = rbnf->getNumberOfRuleSetNames();
599 for (int i = 0; i < count; ++i) {
600 res += rbnf->getRuleSetName(i);
601 res += (UChar)0x003b; // semicolon
602 }
603 } else {
604 *status = U_UNSUPPORTED_ERROR;
605 return -1;
606 }
607 }
608
609 return res.extract(result, resultLength, *status);
610 }
611
612 U_CAPI void U_EXPORT2
unum_setTextAttribute(UNumberFormat * fmt,UNumberFormatTextAttribute tag,const UChar * newValue,int32_t newValueLength,UErrorCode * status)613 unum_setTextAttribute( UNumberFormat* fmt,
614 UNumberFormatTextAttribute tag,
615 const UChar* newValue,
616 int32_t newValueLength,
617 UErrorCode *status)
618 {
619 if(U_FAILURE(*status))
620 return;
621
622 UnicodeString val(newValue, newValueLength);
623 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
624 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
625 if (df != NULL) {
626 switch(tag) {
627 case UNUM_POSITIVE_PREFIX:
628 df->setPositivePrefix(val);
629 break;
630
631 case UNUM_POSITIVE_SUFFIX:
632 df->setPositiveSuffix(val);
633 break;
634
635 case UNUM_NEGATIVE_PREFIX:
636 df->setNegativePrefix(val);
637 break;
638
639 case UNUM_NEGATIVE_SUFFIX:
640 df->setNegativeSuffix(val);
641 break;
642
643 case UNUM_PADDING_CHARACTER:
644 df->setPadCharacter(val);
645 break;
646
647 case UNUM_CURRENCY_CODE:
648 df->setCurrency(val.getTerminatedBuffer(), *status);
649 break;
650
651 default:
652 *status = U_UNSUPPORTED_ERROR;
653 break;
654 }
655 } else {
656 RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf);
657 U_ASSERT(rbnf != NULL);
658 if (tag == UNUM_DEFAULT_RULESET) {
659 rbnf->setDefaultRuleSet(val, *status);
660 } else {
661 *status = U_UNSUPPORTED_ERROR;
662 }
663 }
664 }
665
666 U_CAPI int32_t U_EXPORT2
unum_toPattern(const UNumberFormat * fmt,UBool isPatternLocalized,UChar * result,int32_t resultLength,UErrorCode * status)667 unum_toPattern( const UNumberFormat* fmt,
668 UBool isPatternLocalized,
669 UChar* result,
670 int32_t resultLength,
671 UErrorCode* status)
672 {
673 if(U_FAILURE(*status))
674 return -1;
675
676 UnicodeString pat;
677 if(!(result==NULL && resultLength==0)) {
678 // NULL destination for pure preflighting: empty dummy string
679 // otherwise, alias the destination buffer
680 pat.setTo(result, 0, resultLength);
681 }
682
683 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
684 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
685 if (df != NULL) {
686 if(isPatternLocalized)
687 df->toLocalizedPattern(pat);
688 else
689 df->toPattern(pat);
690 } else {
691 const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
692 U_ASSERT(rbnf != NULL);
693 pat = rbnf->getRules();
694 }
695 return pat.extract(result, resultLength, *status);
696 }
697
698 U_CAPI int32_t U_EXPORT2
unum_getSymbol(const UNumberFormat * fmt,UNumberFormatSymbol symbol,UChar * buffer,int32_t size,UErrorCode * status)699 unum_getSymbol(const UNumberFormat *fmt,
700 UNumberFormatSymbol symbol,
701 UChar *buffer,
702 int32_t size,
703 UErrorCode *status)
704 {
705 if(status==NULL || U_FAILURE(*status)) {
706 return 0;
707 }
708 if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
709 *status=U_ILLEGAL_ARGUMENT_ERROR;
710 return 0;
711 }
712 const NumberFormat *nf = reinterpret_cast<const NumberFormat *>(fmt);
713 const DecimalFormat *dcf = dynamic_cast<const DecimalFormat *>(nf);
714 if (dcf == NULL) {
715 *status = U_UNSUPPORTED_ERROR;
716 return 0;
717 }
718
719 return dcf->
720 getDecimalFormatSymbols()->
721 getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol).
722 extract(buffer, size, *status);
723 }
724
725 U_CAPI void U_EXPORT2
unum_setSymbol(UNumberFormat * fmt,UNumberFormatSymbol symbol,const UChar * value,int32_t length,UErrorCode * status)726 unum_setSymbol(UNumberFormat *fmt,
727 UNumberFormatSymbol symbol,
728 const UChar *value,
729 int32_t length,
730 UErrorCode *status)
731 {
732 if(status==NULL || U_FAILURE(*status)) {
733 return;
734 }
735 if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) {
736 *status=U_ILLEGAL_ARGUMENT_ERROR;
737 return;
738 }
739 NumberFormat *nf = reinterpret_cast<NumberFormat *>(fmt);
740 DecimalFormat *dcf = dynamic_cast<DecimalFormat *>(nf);
741 if (dcf == NULL) {
742 *status = U_UNSUPPORTED_ERROR;
743 return;
744 }
745
746 DecimalFormatSymbols symbols(*dcf->getDecimalFormatSymbols());
747 symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol,
748 UnicodeString(value, length)); /* UnicodeString can handle the case when length = -1. */
749 dcf->setDecimalFormatSymbols(symbols);
750 }
751
752 U_CAPI void U_EXPORT2
unum_applyPattern(UNumberFormat * fmt,UBool localized,const UChar * pattern,int32_t patternLength,UParseError * parseError,UErrorCode * status)753 unum_applyPattern( UNumberFormat *fmt,
754 UBool localized,
755 const UChar *pattern,
756 int32_t patternLength,
757 UParseError *parseError,
758 UErrorCode* status)
759 {
760 UErrorCode tStatus = U_ZERO_ERROR;
761 UParseError tParseError;
762
763 if(parseError == NULL){
764 parseError = &tParseError;
765 }
766
767 if(status==NULL){
768 status = &tStatus;
769 }
770
771 int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
772 const UnicodeString pat((UChar*)pattern, len, len);
773
774 // Verify if the object passed is a DecimalFormat object
775 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
776 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
777 if (df != NULL) {
778 if(localized) {
779 df->applyLocalizedPattern(pat,*parseError, *status);
780 } else {
781 df->applyPattern(pat,*parseError, *status);
782 }
783 } else {
784 *status = U_UNSUPPORTED_ERROR;
785 return;
786 }
787 }
788
789 U_CAPI const char* U_EXPORT2
unum_getLocaleByType(const UNumberFormat * fmt,ULocDataLocaleType type,UErrorCode * status)790 unum_getLocaleByType(const UNumberFormat *fmt,
791 ULocDataLocaleType type,
792 UErrorCode* status)
793 {
794 if (fmt == NULL) {
795 if (U_SUCCESS(*status)) {
796 *status = U_ILLEGAL_ARGUMENT_ERROR;
797 }
798 return NULL;
799 }
800 return ((const Format*)fmt)->getLocaleID(type, *status);
801 }
802
803 U_CAPI void U_EXPORT2
unum_setContext(UNumberFormat * fmt,UDisplayContext value,UErrorCode * status)804 unum_setContext(UNumberFormat* fmt, UDisplayContext value, UErrorCode* status)
805 {
806 if (U_FAILURE(*status)) {
807 return;
808 }
809 ((NumberFormat*)fmt)->setContext(value, *status);
810 return;
811 }
812
813 U_CAPI UDisplayContext U_EXPORT2
unum_getContext(const UNumberFormat * fmt,UDisplayContextType type,UErrorCode * status)814 unum_getContext(const UNumberFormat *fmt, UDisplayContextType type, UErrorCode* status)
815 {
816 if (U_FAILURE(*status)) {
817 return (UDisplayContext)0;
818 }
819 return ((const NumberFormat*)fmt)->getContext(type, *status);
820 }
821
822 U_INTERNAL UFormattable * U_EXPORT2
unum_parseToUFormattable(const UNumberFormat * fmt,UFormattable * result,const UChar * text,int32_t textLength,int32_t * parsePos,UErrorCode * status)823 unum_parseToUFormattable(const UNumberFormat* fmt,
824 UFormattable *result,
825 const UChar* text,
826 int32_t textLength,
827 int32_t* parsePos, /* 0 = start */
828 UErrorCode* status) {
829 UFormattable *newFormattable = NULL;
830 if (U_FAILURE(*status)) return result;
831 if (fmt == NULL || (text==NULL && textLength!=0)) {
832 *status = U_ILLEGAL_ARGUMENT_ERROR;
833 return result;
834 }
835 if (result == NULL) { // allocate if not allocated.
836 newFormattable = result = ufmt_open(status);
837 }
838 parseRes(*(Formattable::fromUFormattable(result)), fmt, text, textLength, parsePos, status);
839 if (U_FAILURE(*status) && newFormattable != NULL) {
840 ufmt_close(newFormattable);
841 result = NULL; // deallocate if there was a parse error
842 }
843 return result;
844 }
845
846 U_INTERNAL int32_t U_EXPORT2
unum_formatUFormattable(const UNumberFormat * fmt,const UFormattable * number,UChar * result,int32_t resultLength,UFieldPosition * pos,UErrorCode * status)847 unum_formatUFormattable(const UNumberFormat* fmt,
848 const UFormattable *number,
849 UChar *result,
850 int32_t resultLength,
851 UFieldPosition *pos, /* ignored if 0 */
852 UErrorCode *status) {
853 if (U_FAILURE(*status)) {
854 return 0;
855 }
856 if (fmt == NULL || number==NULL ||
857 (result==NULL ? resultLength!=0 : resultLength<0)) {
858 *status = U_ILLEGAL_ARGUMENT_ERROR;
859 return 0;
860 }
861 UnicodeString res(result, 0, resultLength);
862
863 FieldPosition fp;
864
865 if(pos != 0)
866 fp.setField(pos->field);
867
868 ((const NumberFormat*)fmt)->format(*(Formattable::fromUFormattable(number)), res, fp, *status);
869
870 if(pos != 0) {
871 pos->beginIndex = fp.getBeginIndex();
872 pos->endIndex = fp.getEndIndex();
873 }
874
875 return res.extract(result, resultLength, *status);
876 }
877
878 #endif /* #if !UCONFIG_NO_FORMATTING */
879