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