]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /* |
2 | ******************************************************************************* | |
73c04bcf | 3 | * Copyright (C) 1997-2006, International Business Machines Corporation and * |
b75a7d8f A |
4 | * others. All Rights Reserved. * |
5 | ******************************************************************************* | |
6 | * | |
7 | * File CHOICFMT.CPP | |
8 | * | |
9 | * Modification History: | |
10 | * | |
11 | * Date Name Description | |
12 | * 02/19/97 aliu Converted from java. | |
13 | * 03/20/97 helena Finished first cut of implementation and got rid | |
14 | * of nextDouble/previousDouble and replaced with | |
15 | * boolean array. | |
16 | * 4/10/97 aliu Clean up. Modified to work on AIX. | |
17 | * 06/04/97 helena Fixed applyPattern(), toPattern() and not to include | |
18 | * wchar.h. | |
19 | * 07/09/97 helena Made ParsePosition into a class. | |
20 | * 08/06/97 nos removed overloaded constructor, fixed 'format(array)' | |
21 | * 07/22/98 stephen JDK 1.2 Sync - removed UBool array (doubleFlags) | |
22 | * 02/22/99 stephen Removed character literals for EBCDIC safety | |
23 | ******************************************************************************** | |
24 | */ | |
25 | ||
26 | #include "unicode/utypes.h" | |
27 | ||
28 | #if !UCONFIG_NO_FORMATTING | |
29 | ||
30 | #include "unicode/choicfmt.h" | |
31 | #include "unicode/numfmt.h" | |
32 | #include "unicode/locid.h" | |
33 | #include "cpputils.h" | |
374ca955 A |
34 | #include "cstring.h" |
35 | #include "putilimp.h" | |
73c04bcf A |
36 | #include <stdio.h> |
37 | #include <float.h> | |
b75a7d8f A |
38 | |
39 | // ***************************************************************************** | |
40 | // class ChoiceFormat | |
41 | // ***************************************************************************** | |
42 | ||
43 | U_NAMESPACE_BEGIN | |
44 | ||
374ca955 | 45 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChoiceFormat) |
b75a7d8f A |
46 | |
47 | // Special characters used by ChoiceFormat. There are two characters | |
48 | // used interchangeably to indicate <=. Either is parsed, but only | |
49 | // LESS_EQUAL is generated by toPattern(). | |
50 | #define SINGLE_QUOTE ((UChar)0x0027) /*'*/ | |
51 | #define LESS_THAN ((UChar)0x003C) /*<*/ | |
52 | #define LESS_EQUAL ((UChar)0x0023) /*#*/ | |
53 | #define LESS_EQUAL2 ((UChar)0x2264) | |
54 | #define VERTICAL_BAR ((UChar)0x007C) /*|*/ | |
55 | #define MINUS ((UChar)0x002D) /*-*/ | |
56 | #define INFINITY ((UChar)0x221E) | |
57 | ||
374ca955 A |
58 | static const UChar gPositiveInfinity[] = {INFINITY, 0}; |
59 | static const UChar gNegativeInfinity[] = {MINUS, INFINITY, 0}; | |
b75a7d8f A |
60 | #define POSITIVE_INF_STRLEN 1 |
61 | #define NEGATIVE_INF_STRLEN 2 | |
62 | ||
63 | // ------------------------------------- | |
64 | // Creates a ChoiceFormat instance based on the pattern. | |
65 | ||
66 | ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern, | |
67 | UErrorCode& status) | |
68 | : fChoiceLimits(0), | |
69 | fClosures(0), | |
70 | fChoiceFormats(0), | |
71 | fCount(0) | |
72 | { | |
73 | applyPattern(newPattern, status); | |
74 | } | |
75 | ||
76 | // ------------------------------------- | |
77 | // Creates a ChoiceFormat instance with the limit array and | |
78 | // format strings for each limit. | |
79 | ||
80 | ChoiceFormat::ChoiceFormat(const double* limits, | |
81 | const UnicodeString* formats, | |
82 | int32_t cnt ) | |
83 | : fChoiceLimits(0), | |
84 | fClosures(0), | |
85 | fChoiceFormats(0), | |
86 | fCount(0) | |
87 | { | |
88 | setChoices(limits, formats, cnt ); | |
89 | } | |
90 | ||
91 | // ------------------------------------- | |
92 | ||
93 | ChoiceFormat::ChoiceFormat(const double* limits, | |
94 | const UBool* closures, | |
95 | const UnicodeString* formats, | |
96 | int32_t cnt ) | |
97 | : fChoiceLimits(0), | |
98 | fClosures(0), | |
99 | fChoiceFormats(0), | |
100 | fCount(0) | |
101 | { | |
102 | setChoices(limits, closures, formats, cnt ); | |
103 | } | |
104 | ||
105 | // ------------------------------------- | |
106 | // copy constructor | |
107 | ||
108 | ChoiceFormat::ChoiceFormat(const ChoiceFormat& that) | |
109 | : NumberFormat(that), | |
110 | fChoiceLimits(0), | |
111 | fClosures(0), | |
112 | fChoiceFormats(0) | |
113 | { | |
114 | *this = that; | |
115 | } | |
116 | ||
117 | // ------------------------------------- | |
118 | // Private constructor that creates a | |
119 | // ChoiceFormat instance based on the | |
120 | // pattern and populates UParseError | |
121 | ||
122 | ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern, | |
123 | UParseError& parseError, | |
124 | UErrorCode& status) | |
125 | : fChoiceLimits(0), | |
126 | fClosures(0), | |
127 | fChoiceFormats(0), | |
128 | fCount(0) | |
129 | { | |
130 | applyPattern(newPattern,parseError, status); | |
131 | } | |
132 | // ------------------------------------- | |
133 | ||
134 | UBool | |
135 | ChoiceFormat::operator==(const Format& that) const | |
136 | { | |
137 | if (this == &that) return TRUE; | |
b75a7d8f A |
138 | if (!NumberFormat::operator==(that)) return FALSE; |
139 | ChoiceFormat& thatAlias = (ChoiceFormat&)that; | |
140 | if (fCount != thatAlias.fCount) return FALSE; | |
141 | // Checks the limits, the corresponding format string and LE or LT flags. | |
142 | // LE means less than and equal to, LT means less than. | |
143 | for (int32_t i = 0; i < fCount; i++) { | |
144 | if ((fChoiceLimits[i] != thatAlias.fChoiceLimits[i]) || | |
145 | (fClosures[i] != thatAlias.fClosures[i]) || | |
146 | (fChoiceFormats[i] != thatAlias.fChoiceFormats[i])) | |
147 | return FALSE; | |
148 | } | |
149 | return TRUE; | |
150 | } | |
151 | ||
152 | // ------------------------------------- | |
153 | // copy constructor | |
154 | ||
155 | const ChoiceFormat& | |
156 | ChoiceFormat::operator=(const ChoiceFormat& that) | |
157 | { | |
158 | if (this != &that) { | |
159 | NumberFormat::operator=(that); | |
160 | fCount = that.fCount; | |
161 | uprv_free(fChoiceLimits); | |
162 | fChoiceLimits = NULL; | |
163 | uprv_free(fClosures); | |
164 | fClosures = NULL; | |
165 | delete [] fChoiceFormats; | |
166 | fChoiceFormats = NULL; | |
167 | ||
168 | fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount); | |
169 | fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount); | |
170 | fChoiceFormats = new UnicodeString[fCount]; | |
171 | ||
172 | uprv_arrayCopy(that.fChoiceLimits, fChoiceLimits, fCount); | |
173 | uprv_arrayCopy(that.fClosures, fClosures, fCount); | |
174 | uprv_arrayCopy(that.fChoiceFormats, fChoiceFormats, fCount); | |
175 | } | |
176 | return *this; | |
177 | } | |
178 | ||
179 | // ------------------------------------- | |
180 | ||
181 | ChoiceFormat::~ChoiceFormat() | |
182 | { | |
183 | uprv_free(fChoiceLimits); | |
184 | fChoiceLimits = NULL; | |
185 | uprv_free(fClosures); | |
186 | fClosures = NULL; | |
187 | delete [] fChoiceFormats; | |
188 | fChoiceFormats = NULL; | |
189 | fCount = 0; | |
190 | } | |
191 | ||
192 | /** | |
193 | * Convert a string to a double value | |
194 | */ | |
195 | double | |
196 | ChoiceFormat::stod(const UnicodeString& string) | |
197 | { | |
198 | char source[256]; | |
199 | char* end; | |
200 | ||
374ca955 | 201 | string.extract(0, string.length(), source, (int32_t)sizeof(source), US_INV); /* invariant codepage */ |
b75a7d8f A |
202 | return uprv_strtod(source,&end); |
203 | } | |
204 | ||
205 | // ------------------------------------- | |
206 | ||
207 | /** | |
208 | * Convert a double value to a string | |
209 | */ | |
210 | UnicodeString& | |
211 | ChoiceFormat::dtos(double value, | |
212 | UnicodeString& string) | |
213 | { | |
73c04bcf A |
214 | /* Buffer to contain the digits and any extra formatting stuff. */ |
215 | char temp[DBL_DIG + 16]; | |
216 | char *itrPtr = temp; | |
217 | char *startPtr; | |
218 | ||
219 | sprintf(temp, "%.*f", DBL_DIG, value); | |
220 | ||
221 | /* Find and convert the decimal point. | |
222 | Using setlocale on some machines will cause sprintf to use a comma for certain locales. | |
223 | */ | |
224 | while (*itrPtr && (*itrPtr == '-' || isdigit(*itrPtr))) { | |
225 | itrPtr++; | |
226 | } | |
227 | if (*itrPtr) { | |
228 | *itrPtr = '.'; | |
229 | } | |
b75a7d8f | 230 | |
73c04bcf A |
231 | /* remove trailing zeros, except the one after '.' */ |
232 | startPtr = itrPtr + 1; | |
233 | itrPtr = uprv_strchr(startPtr, 0); | |
234 | while(--itrPtr > startPtr){ | |
235 | if(*itrPtr == '0'){ | |
236 | *itrPtr = 0; | |
237 | }else{ | |
238 | break; | |
239 | } | |
240 | } | |
374ca955 | 241 | string = UnicodeString(temp, -1, US_INV); /* invariant codepage */ |
b75a7d8f A |
242 | return string; |
243 | } | |
244 | ||
245 | // ------------------------------------- | |
246 | // calls the overloaded applyPattern method. | |
247 | ||
248 | void | |
249 | ChoiceFormat::applyPattern(const UnicodeString& pattern, | |
250 | UErrorCode& status) | |
251 | { | |
252 | UParseError parseError; | |
253 | applyPattern(pattern, parseError, status); | |
254 | } | |
255 | ||
256 | // ------------------------------------- | |
257 | // Applies the pattern to this ChoiceFormat instance. | |
258 | ||
259 | void | |
260 | ChoiceFormat::applyPattern(const UnicodeString& pattern, | |
261 | UParseError& parseError, | |
262 | UErrorCode& status) | |
263 | { | |
264 | if (U_FAILURE(status)) | |
265 | { | |
266 | return; | |
267 | } | |
268 | ||
269 | // Clear error struct | |
270 | parseError.offset = -1; | |
271 | parseError.preContext[0] = parseError.postContext[0] = (UChar)0; | |
272 | ||
273 | // Perform 2 passes. The first computes the number of limits in | |
274 | // this pattern (fCount), which is 1 more than the number of | |
275 | // literal VERTICAL_BAR characters. | |
276 | int32_t count = 1; | |
277 | int32_t i; | |
278 | for (i=0; i<pattern.length(); ++i) { | |
279 | UChar c = pattern[i]; | |
280 | if (c == SINGLE_QUOTE) { | |
281 | // Skip over the entire quote, including embedded | |
282 | // contiguous pairs of SINGLE_QUOTE. | |
283 | for (;;) { | |
284 | do { | |
285 | ++i; | |
286 | } while (i<pattern.length() && | |
287 | pattern[i] != SINGLE_QUOTE); | |
288 | if ((i+1)<pattern.length() && | |
289 | pattern[i+1] == SINGLE_QUOTE) { | |
290 | // SINGLE_QUOTE pair; skip over it | |
291 | ++i; | |
292 | } else { | |
293 | break; | |
294 | } | |
295 | } | |
296 | } else if (c == VERTICAL_BAR) { | |
297 | ++count; | |
298 | } | |
299 | } | |
300 | ||
301 | // Allocate the required storage. | |
302 | double *newLimits = (double*) uprv_malloc( sizeof(double) * count); | |
303 | /* test for NULL */ | |
304 | if (newLimits == 0) { | |
305 | status = U_MEMORY_ALLOCATION_ERROR; | |
306 | return; | |
307 | } | |
308 | UBool *newClosures = (UBool*) uprv_malloc( sizeof(UBool) * count); | |
309 | /* test for NULL */ | |
310 | if (newClosures == 0) { | |
311 | status = U_MEMORY_ALLOCATION_ERROR; | |
312 | uprv_free(newLimits); | |
313 | return; | |
314 | } | |
315 | UnicodeString *newFormats = new UnicodeString[count]; | |
316 | /* test for NULL */ | |
317 | if (newFormats == 0) { | |
318 | status = U_MEMORY_ALLOCATION_ERROR; | |
319 | uprv_free(newLimits); | |
320 | uprv_free(newClosures); | |
321 | return; | |
322 | } | |
323 | ||
324 | // Perform the second pass | |
325 | int32_t k = 0; // index into newXxx[] arrays | |
326 | UnicodeString buf; // scratch buffer | |
327 | UBool inQuote = FALSE; | |
328 | UBool inNumber = TRUE; // TRUE before < or #, FALSE after | |
329 | ||
330 | for (i=0; i<pattern.length(); ++i) { | |
331 | UChar c = pattern[i]; | |
332 | if (c == SINGLE_QUOTE) { | |
333 | // Check for SINGLE_QUOTE pair indicating a literal quote | |
334 | if ((i+1) < pattern.length() && | |
335 | pattern[i+1] == SINGLE_QUOTE) { | |
336 | buf += SINGLE_QUOTE; | |
337 | ++i; | |
338 | } else { | |
339 | inQuote = !inQuote; | |
340 | } | |
341 | } else if (inQuote) { | |
342 | buf += c; | |
343 | } else if (c == LESS_THAN || c == LESS_EQUAL || c == LESS_EQUAL2) { | |
344 | if (!inNumber || buf.length() == 0) { | |
345 | goto error; | |
346 | } | |
347 | inNumber = FALSE; | |
348 | ||
349 | double limit; | |
350 | buf.trim(); | |
374ca955 | 351 | if (!buf.compare(gPositiveInfinity, POSITIVE_INF_STRLEN)) { |
b75a7d8f | 352 | limit = uprv_getInfinity(); |
374ca955 | 353 | } else if (!buf.compare(gNegativeInfinity, NEGATIVE_INF_STRLEN)) { |
b75a7d8f A |
354 | limit = -uprv_getInfinity(); |
355 | } else { | |
356 | limit = stod(buf); | |
357 | } | |
358 | ||
359 | if (k == count) { | |
360 | // This shouldn't happen. If it does, it means that | |
361 | // the count determined in the first pass did not | |
362 | // match the number of elements found in the second | |
363 | // pass. | |
364 | goto error; | |
365 | } | |
366 | newLimits[k] = limit; | |
367 | newClosures[k] = (c == LESS_THAN); | |
368 | ||
369 | if (k > 0 && limit <= newLimits[k-1]) { | |
370 | // Each limit must be strictly > than the previous | |
371 | // limit. One exception: Two subsequent limits may be | |
372 | // == if the first closure is FALSE and the second | |
373 | // closure is TRUE. This places the limit value in | |
374 | // the second interval. | |
375 | if (!(limit == newLimits[k-1] && | |
376 | !newClosures[k-1] && | |
377 | newClosures[k])) { | |
378 | goto error; | |
379 | } | |
380 | } | |
381 | ||
382 | buf.truncate(0); | |
383 | } else if (c == VERTICAL_BAR) { | |
384 | if (inNumber) { | |
385 | goto error; | |
386 | } | |
387 | inNumber = TRUE; | |
388 | ||
389 | newFormats[k] = buf; | |
390 | ++k; | |
391 | buf.truncate(0); | |
392 | } else { | |
393 | buf += c; | |
394 | } | |
395 | } | |
396 | ||
397 | if (k != (count-1) || inNumber || inQuote) { | |
398 | goto error; | |
399 | } | |
400 | newFormats[k] = buf; | |
401 | ||
402 | // Don't modify this object until the parse succeeds | |
403 | uprv_free(fChoiceLimits); | |
404 | uprv_free(fClosures); | |
405 | delete[] fChoiceFormats; | |
406 | fCount = count; | |
407 | fChoiceLimits = newLimits; | |
408 | fClosures = newClosures; | |
409 | fChoiceFormats = newFormats; | |
410 | return; | |
411 | ||
412 | error: | |
413 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
414 | syntaxError(pattern,i,parseError); | |
415 | uprv_free(newLimits); | |
416 | uprv_free(newClosures); | |
417 | delete[] newFormats; | |
418 | return; | |
419 | ||
420 | } | |
421 | // ------------------------------------- | |
422 | // Reconstruct the original input pattern. | |
423 | ||
424 | UnicodeString& | |
425 | ChoiceFormat::toPattern(UnicodeString& result) const | |
426 | { | |
427 | result.remove(); | |
428 | for (int32_t i = 0; i < fCount; ++i) { | |
429 | if (i != 0) { | |
430 | result += VERTICAL_BAR; | |
431 | } | |
432 | UnicodeString buf; | |
433 | if (uprv_isPositiveInfinity(fChoiceLimits[i])) { | |
434 | result += INFINITY; | |
435 | } else if (uprv_isNegativeInfinity(fChoiceLimits[i])) { | |
436 | result += MINUS; | |
437 | result += INFINITY; | |
438 | } else { | |
439 | result += dtos(fChoiceLimits[i], buf); | |
440 | } | |
441 | if (fClosures[i]) { | |
442 | result += LESS_THAN; | |
443 | } else { | |
444 | result += LESS_EQUAL; | |
445 | } | |
446 | // Append fChoiceFormats[i], using quotes if there are special | |
447 | // characters. Single quotes themselves must be escaped in | |
448 | // either case. | |
449 | const UnicodeString& text = fChoiceFormats[i]; | |
450 | UBool needQuote = text.indexOf(LESS_THAN) >= 0 | |
451 | || text.indexOf(LESS_EQUAL) >= 0 | |
452 | || text.indexOf(LESS_EQUAL2) >= 0 | |
453 | || text.indexOf(VERTICAL_BAR) >= 0; | |
454 | if (needQuote) { | |
455 | result += SINGLE_QUOTE; | |
456 | } | |
457 | if (text.indexOf(SINGLE_QUOTE) < 0) { | |
458 | result += text; | |
459 | } | |
460 | else { | |
461 | for (int32_t j = 0; j < text.length(); ++j) { | |
462 | UChar c = text[j]; | |
463 | result += c; | |
464 | if (c == SINGLE_QUOTE) { | |
465 | result += c; | |
466 | } | |
467 | } | |
468 | } | |
469 | if (needQuote) { | |
470 | result += SINGLE_QUOTE; | |
471 | } | |
472 | } | |
473 | ||
474 | return result; | |
475 | } | |
476 | ||
477 | #ifdef U_USE_CHOICE_FORMAT_DEPRECATES | |
478 | // ------------------------------------- | |
479 | // Adopts the limit and format arrays. | |
480 | ||
481 | void | |
482 | ChoiceFormat::adoptChoices(double *limits, | |
483 | UnicodeString *formats, | |
484 | int32_t cnt ) | |
485 | { | |
486 | adoptChoices(limits, (UBool *)0, formats, cnt); | |
487 | } | |
488 | ||
489 | // ------------------------------------- | |
490 | // Adopts the limit and format arrays. | |
491 | ||
492 | void | |
493 | ChoiceFormat::adoptChoices(double *limits, | |
494 | UBool *closures, | |
495 | UnicodeString *formats, | |
496 | int32_t cnt ) | |
497 | { | |
498 | if(limits == 0 || formats == 0) | |
499 | return; | |
500 | ||
501 | uprv_free(fChoiceLimits); | |
502 | uprv_free(fClosures); | |
503 | delete [] fChoiceFormats; | |
504 | fChoiceLimits = limits; | |
505 | fClosures = closures; | |
506 | fChoiceFormats = formats; | |
507 | fCount = cnt; | |
508 | ||
509 | if (fClosures == 0) { | |
510 | fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount); | |
511 | int32_t i; | |
512 | for (i=0; i<fCount; ++i) { | |
513 | fClosures[i] = FALSE; | |
514 | } | |
515 | } | |
516 | } | |
517 | #endif | |
518 | ||
519 | // ------------------------------------- | |
520 | // Sets the limit and format arrays. | |
521 | void | |
522 | ChoiceFormat::setChoices( const double* limits, | |
523 | const UnicodeString* formats, | |
524 | int32_t cnt ) | |
525 | { | |
526 | setChoices(limits, 0, formats, cnt); | |
527 | } | |
528 | ||
529 | // ------------------------------------- | |
530 | // Sets the limit and format arrays. | |
531 | void | |
532 | ChoiceFormat::setChoices( const double* limits, | |
533 | const UBool* closures, | |
534 | const UnicodeString* formats, | |
535 | int32_t cnt ) | |
536 | { | |
537 | if(limits == 0 || formats == 0) | |
538 | return; | |
539 | ||
540 | uprv_free(fChoiceLimits); | |
541 | uprv_free(fClosures); | |
542 | delete [] fChoiceFormats; | |
543 | ||
544 | // Note that the old arrays are deleted and this owns | |
545 | // the created array. | |
546 | fCount = cnt; | |
547 | fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount); | |
548 | fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount); | |
549 | fChoiceFormats = new UnicodeString[fCount]; | |
550 | ||
551 | uprv_arrayCopy(limits, fChoiceLimits, fCount); | |
552 | uprv_arrayCopy(formats, fChoiceFormats, fCount); | |
553 | ||
554 | if (closures != 0) { | |
555 | uprv_arrayCopy(closures, fClosures, fCount); | |
556 | } else { | |
557 | int32_t i; | |
558 | for (i=0; i<fCount; ++i) { | |
559 | fClosures[i] = FALSE; | |
560 | } | |
561 | } | |
562 | } | |
563 | ||
564 | // ------------------------------------- | |
565 | // Gets the limit array. | |
566 | ||
567 | const double* | |
568 | ChoiceFormat::getLimits(int32_t& cnt) const | |
569 | { | |
570 | cnt = fCount; | |
571 | return fChoiceLimits; | |
572 | } | |
573 | ||
574 | // ------------------------------------- | |
575 | // Gets the closures array. | |
576 | ||
577 | const UBool* | |
578 | ChoiceFormat::getClosures(int32_t& cnt) const | |
579 | { | |
580 | cnt = fCount; | |
581 | return fClosures; | |
582 | } | |
583 | ||
584 | // ------------------------------------- | |
585 | // Gets the format array. | |
586 | ||
587 | const UnicodeString* | |
588 | ChoiceFormat::getFormats(int32_t& cnt) const | |
589 | { | |
590 | cnt = fCount; | |
591 | return fChoiceFormats; | |
592 | } | |
593 | ||
374ca955 A |
594 | // ------------------------------------- |
595 | // Formats an int64 number, it's actually formatted as | |
596 | // a double. The returned format string may differ | |
597 | // from the input number because of this. | |
598 | ||
599 | UnicodeString& | |
600 | ChoiceFormat::format(int64_t number, | |
601 | UnicodeString& appendTo, | |
602 | FieldPosition& status) const | |
603 | { | |
604 | return format((double) number, appendTo, status); | |
605 | } | |
606 | ||
b75a7d8f A |
607 | // ------------------------------------- |
608 | // Formats a long number, it's actually formatted as | |
609 | // a double. The returned format string may differ | |
610 | // from the input number because of this. | |
611 | ||
612 | UnicodeString& | |
613 | ChoiceFormat::format(int32_t number, | |
614 | UnicodeString& appendTo, | |
615 | FieldPosition& status) const | |
616 | { | |
617 | return format((double) number, appendTo, status); | |
618 | } | |
619 | ||
620 | // ------------------------------------- | |
621 | // Formats a double number. | |
622 | ||
623 | UnicodeString& | |
624 | ChoiceFormat::format(double number, | |
625 | UnicodeString& appendTo, | |
626 | FieldPosition& /*pos*/) const | |
627 | { | |
628 | // find the number | |
629 | int32_t i; | |
630 | for (i = 0; i < fCount; ++i) { | |
631 | if (fClosures[i]) { | |
632 | if (!(number > fChoiceLimits[i])) { | |
633 | // same as number <= fChoiceLimits, except catches NaN | |
634 | break; | |
635 | } | |
636 | } else if (!(number >= fChoiceLimits[i])) { | |
637 | // same as number < fChoiceLimits, except catches NaN | |
638 | break; | |
639 | } | |
640 | } | |
641 | --i; | |
642 | if (i < 0) { | |
643 | i = 0; | |
644 | } | |
645 | // return either a formatted number, or a string | |
646 | appendTo += fChoiceFormats[i]; | |
647 | return appendTo; | |
648 | } | |
649 | ||
650 | // ------------------------------------- | |
651 | // Formats an array of objects. Checks if the data type of the objects | |
652 | // to get the right value for formatting. | |
653 | ||
654 | UnicodeString& | |
655 | ChoiceFormat::format(const Formattable* objs, | |
656 | int32_t cnt, | |
657 | UnicodeString& appendTo, | |
658 | FieldPosition& pos, | |
659 | UErrorCode& status) const | |
660 | { | |
661 | if(cnt < 0) { | |
662 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
663 | return appendTo; | |
664 | } | |
665 | ||
666 | UnicodeString buffer; | |
667 | for (int32_t i = 0; i < cnt; i++) { | |
374ca955 A |
668 | double objDouble = objs[i].getDouble(status); |
669 | if (U_SUCCESS(status)) { | |
670 | buffer.remove(); | |
671 | appendTo += format(objDouble, buffer, pos); | |
672 | } | |
b75a7d8f A |
673 | } |
674 | ||
675 | return appendTo; | |
676 | } | |
677 | ||
678 | // ------------------------------------- | |
679 | // Formats an array of objects. Checks if the data type of the objects | |
680 | // to get the right value for formatting. | |
681 | ||
682 | UnicodeString& | |
683 | ChoiceFormat::format(const Formattable& obj, | |
684 | UnicodeString& appendTo, | |
685 | FieldPosition& pos, | |
686 | UErrorCode& status) const | |
687 | { | |
688 | return NumberFormat::format(obj, appendTo, pos, status); | |
689 | } | |
690 | // ------------------------------------- | |
691 | ||
692 | void | |
693 | ChoiceFormat::parse(const UnicodeString& text, | |
694 | Formattable& result, | |
695 | ParsePosition& status) const | |
696 | { | |
697 | // find the best number (defined as the one with the longest parse) | |
698 | int32_t start = status.getIndex(); | |
699 | int32_t furthest = start; | |
700 | double bestNumber = uprv_getNaN(); | |
701 | double tempNumber = 0.0; | |
702 | for (int i = 0; i < fCount; ++i) { | |
703 | int32_t len = fChoiceFormats[i].length(); | |
704 | if (text.compare(start, len, fChoiceFormats[i]) == 0) { | |
705 | status.setIndex(start + len); | |
706 | tempNumber = fChoiceLimits[i]; | |
707 | if (status.getIndex() > furthest) { | |
708 | furthest = status.getIndex(); | |
709 | bestNumber = tempNumber; | |
710 | if (furthest == text.length()) | |
711 | break; | |
712 | } | |
713 | } | |
714 | } | |
715 | status.setIndex(furthest); | |
716 | if (status.getIndex() == start) { | |
717 | status.setErrorIndex(furthest); | |
718 | } | |
719 | result.setDouble(bestNumber); | |
720 | } | |
721 | ||
722 | // ------------------------------------- | |
723 | // Parses the text and return the Formattable object. | |
724 | ||
725 | void | |
726 | ChoiceFormat::parse(const UnicodeString& text, | |
727 | Formattable& result, | |
728 | UErrorCode& status) const | |
729 | { | |
730 | NumberFormat::parse(text, result, status); | |
731 | } | |
732 | ||
733 | // ------------------------------------- | |
734 | ||
735 | Format* | |
736 | ChoiceFormat::clone() const | |
737 | { | |
738 | ChoiceFormat *aCopy = new ChoiceFormat(*this); | |
739 | return aCopy; | |
740 | } | |
741 | ||
742 | U_NAMESPACE_END | |
743 | ||
744 | #endif /* #if !UCONFIG_NO_FORMATTING */ | |
745 | ||
746 | //eof |