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