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