1 | // © 2016 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html |
3 | /* |
4 | ******************************************************************************* |
5 | * Copyright (C) 1996-2015, International Business Machines |
6 | * Corporation and others. All Rights Reserved. |
7 | ******************************************************************************* |
8 | * Modification History: |
9 | * |
10 | * Date Name Description |
11 | * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes |
12 | ******************************************************************************* |
13 | */ |
14 | |
15 | #include "unicode/utypes.h" |
16 | |
17 | #if !UCONFIG_NO_FORMATTING |
18 | |
19 | #include "unicode/unum.h" |
20 | |
21 | #include "unicode/uloc.h" |
22 | #include "unicode/numfmt.h" |
23 | #include "unicode/decimfmt.h" |
24 | #include "unicode/rbnf.h" |
25 | #include "unicode/compactdecimalformat.h" |
26 | #include "unicode/ustring.h" |
27 | #include "unicode/fmtable.h" |
28 | #include "unicode/dcfmtsym.h" |
29 | #include "unicode/curramt.h" |
30 | #include "unicode/localpointer.h" |
31 | #include "unicode/udisplaycontext.h" |
32 | #include "uassert.h" |
33 | #include "cpputils.h" |
34 | #include "cstring.h" |
35 | |
36 | |
37 | U_NAMESPACE_USE |
38 | |
39 | |
40 | U_CAPI UNumberFormat* U_EXPORT2 |
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 | if (U_FAILURE(*status) && retVal != NULL) { |
139 | delete retVal; |
140 | retVal = NULL; |
141 | } |
142 | |
143 | return reinterpret_cast<UNumberFormat *>(retVal); |
144 | } |
145 | |
146 | U_CAPI void U_EXPORT2 |
147 | unum_close(UNumberFormat* fmt) |
148 | { |
149 | delete (NumberFormat*) fmt; |
150 | } |
151 | |
152 | U_CAPI UNumberFormat* U_EXPORT2 |
153 | unum_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 | |
178 | U_CAPI int32_t U_EXPORT2 |
179 | unum_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 | |
189 | U_CAPI int32_t U_EXPORT2 |
190 | unum_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 | |
222 | U_CAPI int32_t U_EXPORT2 |
223 | unum_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 | |
255 | U_CAPI int32_t U_EXPORT2 |
256 | unum_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 | |
283 | U_CAPI int32_t U_EXPORT2 |
284 | unum_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 | |
327 | U_CAPI int32_t U_EXPORT2 |
328 | unum_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 | |
365 | static void |
366 | parseRes(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 | |
394 | U_CAPI int32_t U_EXPORT2 |
395 | unum_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 | |
406 | U_CAPI int64_t U_EXPORT2 |
407 | unum_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 | |
418 | U_CAPI double U_EXPORT2 |
419 | unum_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 | |
430 | U_CAPI int32_t U_EXPORT2 |
431 | unum_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 | |
463 | U_CAPI double U_EXPORT2 |
464 | unum_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 | |
499 | U_CAPI const char* U_EXPORT2 |
500 | unum_getAvailable(int32_t index) |
501 | { |
502 | return uloc_getAvailable(index); |
503 | } |
504 | |
505 | U_CAPI int32_t U_EXPORT2 |
506 | unum_countAvailable() |
507 | { |
508 | return uloc_countAvailable(); |
509 | } |
510 | |
511 | U_CAPI int32_t U_EXPORT2 |
512 | unum_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 | |
554 | U_CAPI void U_EXPORT2 |
555 | unum_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 | |
597 | U_CAPI double U_EXPORT2 |
598 | unum_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 | |
610 | U_CAPI void U_EXPORT2 |
611 | unum_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 | |
622 | U_CAPI int32_t U_EXPORT2 |
623 | unum_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 | |
691 | U_CAPI void U_EXPORT2 |
692 | unum_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 | |
745 | U_CAPI int32_t U_EXPORT2 |
746 | unum_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 | |
777 | U_CAPI int32_t U_EXPORT2 |
778 | unum_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 | |
804 | U_CAPI void U_EXPORT2 |
805 | unum_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 | |
831 | U_CAPI void U_EXPORT2 |
832 | unum_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 | |
868 | U_CAPI const char* U_EXPORT2 |
869 | unum_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 | |
882 | U_CAPI void U_EXPORT2 |
883 | unum_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 | |
892 | U_CAPI UDisplayContext U_EXPORT2 |
893 | unum_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 | |
901 | U_INTERNAL UFormattable * U_EXPORT2 |
902 | unum_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 | |
925 | U_INTERNAL int32_t U_EXPORT2 |
926 | unum_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 | |