2 *******************************************************************************
3 * Copyright (C) 1997-2008, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
9 * Modification History:
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
16 * 4/10/97 aliu Clean up. Modified to work on AIX.
17 * 06/04/97 helena Fixed applyPattern(), toPattern() and not to include
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 ********************************************************************************
26 #include "unicode/utypes.h"
28 #if !UCONFIG_NO_FORMATTING
30 #include "unicode/choicfmt.h"
31 #include "unicode/numfmt.h"
32 #include "unicode/locid.h"
39 // *****************************************************************************
41 // *****************************************************************************
45 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChoiceFormat
)
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)
58 static const UChar gPositiveInfinity
[] = {INFINITY
, 0};
59 static const UChar gNegativeInfinity
[] = {MINUS
, INFINITY
, 0};
60 #define POSITIVE_INF_STRLEN 1
61 #define NEGATIVE_INF_STRLEN 2
63 // -------------------------------------
64 // Creates a ChoiceFormat instance based on the pattern.
66 ChoiceFormat::ChoiceFormat(const UnicodeString
& newPattern
,
73 applyPattern(newPattern
, status
);
76 // -------------------------------------
77 // Creates a ChoiceFormat instance with the limit array and
78 // format strings for each limit.
80 ChoiceFormat::ChoiceFormat(const double* limits
,
81 const UnicodeString
* formats
,
88 setChoices(limits
, formats
, cnt
);
91 // -------------------------------------
93 ChoiceFormat::ChoiceFormat(const double* limits
,
94 const UBool
* closures
,
95 const UnicodeString
* formats
,
102 setChoices(limits
, closures
, formats
, cnt
);
105 // -------------------------------------
108 ChoiceFormat::ChoiceFormat(const ChoiceFormat
& that
)
109 : NumberFormat(that
),
117 // -------------------------------------
118 // Private constructor that creates a
119 // ChoiceFormat instance based on the
120 // pattern and populates UParseError
122 ChoiceFormat::ChoiceFormat(const UnicodeString
& newPattern
,
123 UParseError
& parseError
,
130 applyPattern(newPattern
,parseError
, status
);
132 // -------------------------------------
135 ChoiceFormat::operator==(const Format
& that
) const
137 if (this == &that
) return TRUE
;
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
]))
152 // -------------------------------------
156 ChoiceFormat::operator=(const ChoiceFormat
& that
)
159 NumberFormat::operator=(that
);
160 fCount
= that
.fCount
;
161 uprv_free(fChoiceLimits
);
162 fChoiceLimits
= NULL
;
163 uprv_free(fClosures
);
165 delete [] fChoiceFormats
;
166 fChoiceFormats
= NULL
;
168 fChoiceLimits
= (double*) uprv_malloc( sizeof(double) * fCount
);
169 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
170 fChoiceFormats
= new UnicodeString
[fCount
];
172 // check for memory allocation error
173 if (!fChoiceLimits
|| !fClosures
|| !fChoiceFormats
) {
175 uprv_free(fChoiceLimits
);
176 fChoiceLimits
= NULL
;
179 uprv_free(fClosures
);
182 if (fChoiceFormats
) {
183 delete[] fChoiceFormats
;
184 fChoiceFormats
= NULL
;
187 uprv_arrayCopy(that
.fChoiceLimits
, fChoiceLimits
, fCount
);
188 uprv_arrayCopy(that
.fClosures
, fClosures
, fCount
);
189 uprv_arrayCopy(that
.fChoiceFormats
, fChoiceFormats
, fCount
);
195 // -------------------------------------
197 ChoiceFormat::~ChoiceFormat()
199 uprv_free(fChoiceLimits
);
200 fChoiceLimits
= NULL
;
201 uprv_free(fClosures
);
203 delete [] fChoiceFormats
;
204 fChoiceFormats
= NULL
;
209 * Convert a string to a double value
212 ChoiceFormat::stod(const UnicodeString
& string
)
217 string
.extract(0, string
.length(), source
, (int32_t)sizeof(source
), US_INV
); /* invariant codepage */
218 return uprv_strtod(source
,&end
);
221 // -------------------------------------
224 * Convert a double value to a string without the overhead of ICU.
227 ChoiceFormat::dtos(double value
,
228 UnicodeString
& string
)
230 /* Buffer to contain the digits and any extra formatting stuff. */
231 char temp
[DBL_DIG
+ 16];
235 sprintf(temp
, "%.*g", DBL_DIG
, value
);
237 /* Find and convert the decimal point.
238 Using setlocale on some machines will cause sprintf to use a comma for certain locales.
240 while (*itrPtr
&& (*itrPtr
== '-' || isdigit(*itrPtr
))) {
243 if (*itrPtr
!= 0 && *itrPtr
!= 'e') {
244 /* We reached something that looks like a decimal point.
245 In case someone used setlocale(), which changes the decimal point. */
249 /* Search for the exponent */
250 while (*itrPtr
&& *itrPtr
!= 'e') {
253 if (*itrPtr
== 'e') {
255 /* Verify the exponent sign */
256 if (*itrPtr
== '+' || *itrPtr
== '-') {
259 /* Remove leading zeros. You will see this on Windows machines. */
261 while (*itrPtr
== '0') {
264 if (*itrPtr
&& expPtr
!= itrPtr
) {
265 /* Shift the exponent without zeros. */
267 *(expPtr
++) = *(itrPtr
++);
274 string
= UnicodeString(temp
, -1, US_INV
); /* invariant codepage */
278 // -------------------------------------
279 // calls the overloaded applyPattern method.
282 ChoiceFormat::applyPattern(const UnicodeString
& pattern
,
285 UParseError parseError
;
286 applyPattern(pattern
, parseError
, status
);
289 // -------------------------------------
290 // Applies the pattern to this ChoiceFormat instance.
293 ChoiceFormat::applyPattern(const UnicodeString
& pattern
,
294 UParseError
& parseError
,
297 if (U_FAILURE(status
))
302 // Clear error struct
303 parseError
.offset
= -1;
304 parseError
.preContext
[0] = parseError
.postContext
[0] = (UChar
)0;
306 // Perform 2 passes. The first computes the number of limits in
307 // this pattern (fCount), which is 1 more than the number of
308 // literal VERTICAL_BAR characters.
311 for (i
=0; i
<pattern
.length(); ++i
) {
312 UChar c
= pattern
[i
];
313 if (c
== SINGLE_QUOTE
) {
314 // Skip over the entire quote, including embedded
315 // contiguous pairs of SINGLE_QUOTE.
319 } while (i
<pattern
.length() &&
320 pattern
[i
] != SINGLE_QUOTE
);
321 if ((i
+1)<pattern
.length() &&
322 pattern
[i
+1] == SINGLE_QUOTE
) {
323 // SINGLE_QUOTE pair; skip over it
329 } else if (c
== VERTICAL_BAR
) {
334 // Allocate the required storage.
335 double *newLimits
= (double*) uprv_malloc( sizeof(double) * count
);
337 if (newLimits
== 0) {
338 status
= U_MEMORY_ALLOCATION_ERROR
;
341 UBool
*newClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * count
);
343 if (newClosures
== 0) {
344 status
= U_MEMORY_ALLOCATION_ERROR
;
345 uprv_free(newLimits
);
348 UnicodeString
*newFormats
= new UnicodeString
[count
];
350 if (newFormats
== 0) {
351 status
= U_MEMORY_ALLOCATION_ERROR
;
352 uprv_free(newLimits
);
353 uprv_free(newClosures
);
357 // Perform the second pass
358 int32_t k
= 0; // index into newXxx[] arrays
359 UnicodeString buf
; // scratch buffer
360 UBool inQuote
= FALSE
;
361 UBool inNumber
= TRUE
; // TRUE before < or #, FALSE after
363 for (i
=0; i
<pattern
.length(); ++i
) {
364 UChar c
= pattern
[i
];
365 if (c
== SINGLE_QUOTE
) {
366 // Check for SINGLE_QUOTE pair indicating a literal quote
367 if ((i
+1) < pattern
.length() &&
368 pattern
[i
+1] == SINGLE_QUOTE
) {
374 } else if (inQuote
) {
376 } else if (c
== LESS_THAN
|| c
== LESS_EQUAL
|| c
== LESS_EQUAL2
) {
377 if (!inNumber
|| buf
.length() == 0) {
384 if (!buf
.compare(gPositiveInfinity
, POSITIVE_INF_STRLEN
)) {
385 limit
= uprv_getInfinity();
386 } else if (!buf
.compare(gNegativeInfinity
, NEGATIVE_INF_STRLEN
)) {
387 limit
= -uprv_getInfinity();
393 // This shouldn't happen. If it does, it means that
394 // the count determined in the first pass did not
395 // match the number of elements found in the second
399 newLimits
[k
] = limit
;
400 newClosures
[k
] = (c
== LESS_THAN
);
402 if (k
> 0 && limit
<= newLimits
[k
-1]) {
403 // Each limit must be strictly > than the previous
404 // limit. One exception: Two subsequent limits may be
405 // == if the first closure is FALSE and the second
406 // closure is TRUE. This places the limit value in
407 // the second interval.
408 if (!(limit
== newLimits
[k
-1] &&
416 } else if (c
== VERTICAL_BAR
) {
430 if (k
!= (count
-1) || inNumber
|| inQuote
) {
435 // Don't modify this object until the parse succeeds
436 uprv_free(fChoiceLimits
);
437 uprv_free(fClosures
);
438 delete[] fChoiceFormats
;
440 fChoiceLimits
= newLimits
;
441 fClosures
= newClosures
;
442 fChoiceFormats
= newFormats
;
446 status
= U_ILLEGAL_ARGUMENT_ERROR
;
447 syntaxError(pattern
,i
,parseError
);
448 uprv_free(newLimits
);
449 uprv_free(newClosures
);
454 // -------------------------------------
455 // Reconstruct the original input pattern.
458 ChoiceFormat::toPattern(UnicodeString
& result
) const
461 for (int32_t i
= 0; i
< fCount
; ++i
) {
463 result
+= VERTICAL_BAR
;
466 if (uprv_isPositiveInfinity(fChoiceLimits
[i
])) {
468 } else if (uprv_isNegativeInfinity(fChoiceLimits
[i
])) {
472 result
+= dtos(fChoiceLimits
[i
], buf
);
477 result
+= LESS_EQUAL
;
479 // Append fChoiceFormats[i], using quotes if there are special
480 // characters. Single quotes themselves must be escaped in
482 const UnicodeString
& text
= fChoiceFormats
[i
];
483 UBool needQuote
= text
.indexOf(LESS_THAN
) >= 0
484 || text
.indexOf(LESS_EQUAL
) >= 0
485 || text
.indexOf(LESS_EQUAL2
) >= 0
486 || text
.indexOf(VERTICAL_BAR
) >= 0;
488 result
+= SINGLE_QUOTE
;
490 if (text
.indexOf(SINGLE_QUOTE
) < 0) {
494 for (int32_t j
= 0; j
< text
.length(); ++j
) {
497 if (c
== SINGLE_QUOTE
) {
503 result
+= SINGLE_QUOTE
;
510 // -------------------------------------
511 // Sets the limit and format arrays.
513 ChoiceFormat::setChoices( const double* limits
,
514 const UnicodeString
* formats
,
517 setChoices(limits
, 0, formats
, cnt
);
520 // -------------------------------------
521 // Sets the limit and format arrays.
523 ChoiceFormat::setChoices( const double* limits
,
524 const UBool
* closures
,
525 const UnicodeString
* formats
,
528 if(limits
== 0 || formats
== 0)
532 uprv_free(fChoiceLimits
);
535 uprv_free(fClosures
);
537 if (fChoiceFormats
) {
538 delete [] fChoiceFormats
;
541 // Note that the old arrays are deleted and this owns
542 // the created array.
544 fChoiceLimits
= (double*) uprv_malloc( sizeof(double) * fCount
);
545 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
546 fChoiceFormats
= new UnicodeString
[fCount
];
548 //check for memory allocation error
549 if (!fChoiceLimits
|| !fClosures
|| !fChoiceFormats
) {
551 uprv_free(fChoiceLimits
);
552 fChoiceLimits
= NULL
;
555 uprv_free(fClosures
);
558 if (fChoiceFormats
) {
559 delete[] fChoiceFormats
;
560 fChoiceFormats
= NULL
;
565 uprv_arrayCopy(limits
, fChoiceLimits
, fCount
);
566 uprv_arrayCopy(formats
, fChoiceFormats
, fCount
);
569 uprv_arrayCopy(closures
, fClosures
, fCount
);
572 for (i
=0; i
<fCount
; ++i
) {
573 fClosures
[i
] = FALSE
;
578 // -------------------------------------
579 // Gets the limit array.
582 ChoiceFormat::getLimits(int32_t& cnt
) const
585 return fChoiceLimits
;
588 // -------------------------------------
589 // Gets the closures array.
592 ChoiceFormat::getClosures(int32_t& cnt
) const
598 // -------------------------------------
599 // Gets the format array.
602 ChoiceFormat::getFormats(int32_t& cnt
) const
605 return fChoiceFormats
;
608 // -------------------------------------
609 // Formats an int64 number, it's actually formatted as
610 // a double. The returned format string may differ
611 // from the input number because of this.
614 ChoiceFormat::format(int64_t number
,
615 UnicodeString
& appendTo
,
616 FieldPosition
& status
) const
618 return format((double) number
, appendTo
, status
);
621 // -------------------------------------
622 // Formats a long number, it's actually formatted as
623 // a double. The returned format string may differ
624 // from the input number because of this.
627 ChoiceFormat::format(int32_t number
,
628 UnicodeString
& appendTo
,
629 FieldPosition
& status
) const
631 return format((double) number
, appendTo
, status
);
634 // -------------------------------------
635 // Formats a double number.
638 ChoiceFormat::format(double number
,
639 UnicodeString
& appendTo
,
640 FieldPosition
& /*pos*/) const
644 for (i
= 0; i
< fCount
; ++i
) {
646 if (!(number
> fChoiceLimits
[i
])) {
647 // same as number <= fChoiceLimits, except catches NaN
650 } else if (!(number
>= fChoiceLimits
[i
])) {
651 // same as number < fChoiceLimits, except catches NaN
659 // return either a formatted number, or a string
660 appendTo
+= fChoiceFormats
[i
];
664 // -------------------------------------
665 // Formats an array of objects. Checks if the data type of the objects
666 // to get the right value for formatting.
669 ChoiceFormat::format(const Formattable
* objs
,
671 UnicodeString
& appendTo
,
673 UErrorCode
& status
) const
676 status
= U_ILLEGAL_ARGUMENT_ERROR
;
680 UnicodeString buffer
;
681 for (int32_t i
= 0; i
< cnt
; i
++) {
682 double objDouble
= objs
[i
].getDouble(status
);
683 if (U_SUCCESS(status
)) {
685 appendTo
+= format(objDouble
, buffer
, pos
);
692 // -------------------------------------
693 // Formats an array of objects. Checks if the data type of the objects
694 // to get the right value for formatting.
697 ChoiceFormat::format(const Formattable
& obj
,
698 UnicodeString
& appendTo
,
700 UErrorCode
& status
) const
702 return NumberFormat::format(obj
, appendTo
, pos
, status
);
704 // -------------------------------------
707 ChoiceFormat::parse(const UnicodeString
& text
,
709 ParsePosition
& status
) const
711 // find the best number (defined as the one with the longest parse)
712 int32_t start
= status
.getIndex();
713 int32_t furthest
= start
;
714 double bestNumber
= uprv_getNaN();
715 double tempNumber
= 0.0;
716 for (int i
= 0; i
< fCount
; ++i
) {
717 int32_t len
= fChoiceFormats
[i
].length();
718 if (text
.compare(start
, len
, fChoiceFormats
[i
]) == 0) {
719 status
.setIndex(start
+ len
);
720 tempNumber
= fChoiceLimits
[i
];
721 if (status
.getIndex() > furthest
) {
722 furthest
= status
.getIndex();
723 bestNumber
= tempNumber
;
724 if (furthest
== text
.length())
729 status
.setIndex(furthest
);
730 if (status
.getIndex() == start
) {
731 status
.setErrorIndex(furthest
);
733 result
.setDouble(bestNumber
);
736 // -------------------------------------
737 // Parses the text and return the Formattable object.
740 ChoiceFormat::parse(const UnicodeString
& text
,
742 UErrorCode
& status
) const
744 NumberFormat::parse(text
, result
, status
);
747 // -------------------------------------
750 ChoiceFormat::clone() const
752 ChoiceFormat
*aCopy
= new ChoiceFormat(*this);
758 #endif /* #if !UCONFIG_NO_FORMATTING */