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