2 *******************************************************************************
3 * Copyright (C) 1997-2009, 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) /*-*/
60 #define INFINITY ((UChar)0x221E)
62 static const UChar gPositiveInfinity
[] = {INFINITY
, 0};
63 static const UChar gNegativeInfinity
[] = {MINUS
, INFINITY
, 0};
64 #define POSITIVE_INF_STRLEN 1
65 #define NEGATIVE_INF_STRLEN 2
67 // -------------------------------------
68 // Creates a ChoiceFormat instance based on the pattern.
70 ChoiceFormat::ChoiceFormat(const UnicodeString
& newPattern
,
77 applyPattern(newPattern
, status
);
80 // -------------------------------------
81 // Creates a ChoiceFormat instance with the limit array and
82 // format strings for each limit.
84 ChoiceFormat::ChoiceFormat(const double* limits
,
85 const UnicodeString
* formats
,
92 setChoices(limits
, formats
, cnt
);
95 // -------------------------------------
97 ChoiceFormat::ChoiceFormat(const double* limits
,
98 const UBool
* closures
,
99 const UnicodeString
* formats
,
106 setChoices(limits
, closures
, formats
, cnt
);
109 // -------------------------------------
112 ChoiceFormat::ChoiceFormat(const ChoiceFormat
& that
)
113 : NumberFormat(that
),
121 // -------------------------------------
122 // Private constructor that creates a
123 // ChoiceFormat instance based on the
124 // pattern and populates UParseError
126 ChoiceFormat::ChoiceFormat(const UnicodeString
& newPattern
,
127 UParseError
& parseError
,
134 applyPattern(newPattern
,parseError
, status
);
136 // -------------------------------------
139 ChoiceFormat::operator==(const Format
& that
) const
141 if (this == &that
) return TRUE
;
142 if (!NumberFormat::operator==(that
)) return FALSE
;
143 ChoiceFormat
& thatAlias
= (ChoiceFormat
&)that
;
144 if (fCount
!= thatAlias
.fCount
) return FALSE
;
145 // Checks the limits, the corresponding format string and LE or LT flags.
146 // LE means less than and equal to, LT means less than.
147 for (int32_t i
= 0; i
< fCount
; i
++) {
148 if ((fChoiceLimits
[i
] != thatAlias
.fChoiceLimits
[i
]) ||
149 (fClosures
[i
] != thatAlias
.fClosures
[i
]) ||
150 (fChoiceFormats
[i
] != thatAlias
.fChoiceFormats
[i
]))
156 // -------------------------------------
160 ChoiceFormat::operator=(const ChoiceFormat
& that
)
163 NumberFormat::operator=(that
);
164 fCount
= that
.fCount
;
165 uprv_free(fChoiceLimits
);
166 fChoiceLimits
= NULL
;
167 uprv_free(fClosures
);
169 delete [] fChoiceFormats
;
170 fChoiceFormats
= NULL
;
172 fChoiceLimits
= (double*) uprv_malloc( sizeof(double) * fCount
);
173 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
174 fChoiceFormats
= new UnicodeString
[fCount
];
176 // check for memory allocation error
177 if (!fChoiceLimits
|| !fClosures
|| !fChoiceFormats
) {
179 uprv_free(fChoiceLimits
);
180 fChoiceLimits
= NULL
;
183 uprv_free(fClosures
);
186 if (fChoiceFormats
) {
187 delete[] fChoiceFormats
;
188 fChoiceFormats
= NULL
;
191 uprv_arrayCopy(that
.fChoiceLimits
, fChoiceLimits
, fCount
);
192 uprv_arrayCopy(that
.fClosures
, fClosures
, fCount
);
193 uprv_arrayCopy(that
.fChoiceFormats
, fChoiceFormats
, fCount
);
199 // -------------------------------------
201 ChoiceFormat::~ChoiceFormat()
203 uprv_free(fChoiceLimits
);
204 fChoiceLimits
= NULL
;
205 uprv_free(fClosures
);
207 delete [] fChoiceFormats
;
208 fChoiceFormats
= NULL
;
213 * Convert a string to a double value
216 ChoiceFormat::stod(const UnicodeString
& string
)
221 string
.extract(0, string
.length(), source
, (int32_t)sizeof(source
), US_INV
); /* invariant codepage */
222 return uprv_strtod(source
,&end
);
225 // -------------------------------------
228 * Convert a double value to a string without the overhead of ICU.
231 ChoiceFormat::dtos(double value
,
232 UnicodeString
& string
)
234 /* Buffer to contain the digits and any extra formatting stuff. */
235 char temp
[DBL_DIG
+ 16];
239 sprintf(temp
, "%.*g", DBL_DIG
, value
);
241 /* Find and convert the decimal point.
242 Using setlocale on some machines will cause sprintf to use a comma for certain locales.
244 while (*itrPtr
&& (*itrPtr
== '-' || isdigit(*itrPtr
))) {
247 if (*itrPtr
!= 0 && *itrPtr
!= 'e') {
248 /* We reached something that looks like a decimal point.
249 In case someone used setlocale(), which changes the decimal point. */
253 /* Search for the exponent */
254 while (*itrPtr
&& *itrPtr
!= 'e') {
257 if (*itrPtr
== 'e') {
259 /* Verify the exponent sign */
260 if (*itrPtr
== '+' || *itrPtr
== '-') {
263 /* Remove leading zeros. You will see this on Windows machines. */
265 while (*itrPtr
== '0') {
268 if (*itrPtr
&& expPtr
!= itrPtr
) {
269 /* Shift the exponent without zeros. */
271 *(expPtr
++) = *(itrPtr
++);
278 string
= UnicodeString(temp
, -1, US_INV
); /* invariant codepage */
282 // -------------------------------------
283 // calls the overloaded applyPattern method.
286 ChoiceFormat::applyPattern(const UnicodeString
& pattern
,
289 UParseError parseError
;
290 applyPattern(pattern
, parseError
, status
);
293 // -------------------------------------
294 // Applies the pattern to this ChoiceFormat instance.
297 ChoiceFormat::applyPattern(const UnicodeString
& pattern
,
298 UParseError
& parseError
,
301 if (U_FAILURE(status
))
306 // Clear error struct
307 parseError
.offset
= -1;
308 parseError
.preContext
[0] = parseError
.postContext
[0] = (UChar
)0;
310 // Perform 2 passes. The first computes the number of limits in
311 // this pattern (fCount), which is 1 more than the number of
312 // literal VERTICAL_BAR characters.
315 for (i
=0; i
<pattern
.length(); ++i
) {
316 UChar c
= pattern
[i
];
317 if (c
== SINGLE_QUOTE
) {
318 // Skip over the entire quote, including embedded
319 // contiguous pairs of SINGLE_QUOTE.
323 } while (i
<pattern
.length() &&
324 pattern
[i
] != SINGLE_QUOTE
);
325 if ((i
+1)<pattern
.length() &&
326 pattern
[i
+1] == SINGLE_QUOTE
) {
327 // SINGLE_QUOTE pair; skip over it
333 } else if (c
== VERTICAL_BAR
) {
338 // Allocate the required storage.
339 double *newLimits
= (double*) uprv_malloc( sizeof(double) * count
);
341 if (newLimits
== 0) {
342 status
= U_MEMORY_ALLOCATION_ERROR
;
345 UBool
*newClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * count
);
347 if (newClosures
== 0) {
348 status
= U_MEMORY_ALLOCATION_ERROR
;
349 uprv_free(newLimits
);
352 UnicodeString
*newFormats
= new UnicodeString
[count
];
354 if (newFormats
== 0) {
355 status
= U_MEMORY_ALLOCATION_ERROR
;
356 uprv_free(newLimits
);
357 uprv_free(newClosures
);
361 // Perform the second pass
362 int32_t k
= 0; // index into newXxx[] arrays
363 UnicodeString buf
; // scratch buffer
364 UBool inQuote
= FALSE
;
365 UBool inNumber
= TRUE
; // TRUE before < or #, FALSE after
367 for (i
=0; i
<pattern
.length(); ++i
) {
368 UChar c
= pattern
[i
];
369 if (c
== SINGLE_QUOTE
) {
370 // Check for SINGLE_QUOTE pair indicating a literal quote
371 if ((i
+1) < pattern
.length() &&
372 pattern
[i
+1] == SINGLE_QUOTE
) {
378 } else if (inQuote
) {
380 } else if (c
== LESS_THAN
|| c
== LESS_EQUAL
|| c
== LESS_EQUAL2
) {
381 if (!inNumber
|| buf
.length() == 0) {
388 if (!buf
.compare(gPositiveInfinity
, POSITIVE_INF_STRLEN
)) {
389 limit
= uprv_getInfinity();
390 } else if (!buf
.compare(gNegativeInfinity
, NEGATIVE_INF_STRLEN
)) {
391 limit
= -uprv_getInfinity();
397 // This shouldn't happen. If it does, it means that
398 // the count determined in the first pass did not
399 // match the number of elements found in the second
403 newLimits
[k
] = limit
;
404 newClosures
[k
] = (c
== LESS_THAN
);
406 if (k
> 0 && limit
<= newLimits
[k
-1]) {
407 // Each limit must be strictly > than the previous
408 // limit. One exception: Two subsequent limits may be
409 // == if the first closure is FALSE and the second
410 // closure is TRUE. This places the limit value in
411 // the second interval.
412 if (!(limit
== newLimits
[k
-1] &&
420 } else if (c
== VERTICAL_BAR
) {
434 if (k
!= (count
-1) || inNumber
|| inQuote
) {
439 // Don't modify this object until the parse succeeds
440 uprv_free(fChoiceLimits
);
441 uprv_free(fClosures
);
442 delete[] fChoiceFormats
;
444 fChoiceLimits
= newLimits
;
445 fClosures
= newClosures
;
446 fChoiceFormats
= newFormats
;
450 status
= U_ILLEGAL_ARGUMENT_ERROR
;
451 syntaxError(pattern
,i
,parseError
);
452 uprv_free(newLimits
);
453 uprv_free(newClosures
);
458 // -------------------------------------
459 // Reconstruct the original input pattern.
462 ChoiceFormat::toPattern(UnicodeString
& result
) const
465 for (int32_t i
= 0; i
< fCount
; ++i
) {
467 result
+= VERTICAL_BAR
;
470 if (uprv_isPositiveInfinity(fChoiceLimits
[i
])) {
472 } else if (uprv_isNegativeInfinity(fChoiceLimits
[i
])) {
476 result
+= dtos(fChoiceLimits
[i
], buf
);
481 result
+= LESS_EQUAL
;
483 // Append fChoiceFormats[i], using quotes if there are special
484 // characters. Single quotes themselves must be escaped in
486 const UnicodeString
& text
= fChoiceFormats
[i
];
487 UBool needQuote
= text
.indexOf(LESS_THAN
) >= 0
488 || text
.indexOf(LESS_EQUAL
) >= 0
489 || text
.indexOf(LESS_EQUAL2
) >= 0
490 || text
.indexOf(VERTICAL_BAR
) >= 0;
492 result
+= SINGLE_QUOTE
;
494 if (text
.indexOf(SINGLE_QUOTE
) < 0) {
498 for (int32_t j
= 0; j
< text
.length(); ++j
) {
501 if (c
== SINGLE_QUOTE
) {
507 result
+= SINGLE_QUOTE
;
514 // -------------------------------------
515 // Sets the limit and format arrays.
517 ChoiceFormat::setChoices( const double* limits
,
518 const UnicodeString
* formats
,
521 setChoices(limits
, 0, formats
, cnt
);
524 // -------------------------------------
525 // Sets the limit and format arrays.
527 ChoiceFormat::setChoices( const double* limits
,
528 const UBool
* closures
,
529 const UnicodeString
* formats
,
532 if(limits
== 0 || formats
== 0)
536 uprv_free(fChoiceLimits
);
539 uprv_free(fClosures
);
541 if (fChoiceFormats
) {
542 delete [] fChoiceFormats
;
545 // Note that the old arrays are deleted and this owns
546 // the created array.
548 fChoiceLimits
= (double*) uprv_malloc( sizeof(double) * fCount
);
549 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
550 fChoiceFormats
= new UnicodeString
[fCount
];
552 //check for memory allocation error
553 if (!fChoiceLimits
|| !fClosures
|| !fChoiceFormats
) {
555 uprv_free(fChoiceLimits
);
556 fChoiceLimits
= NULL
;
559 uprv_free(fClosures
);
562 if (fChoiceFormats
) {
563 delete[] fChoiceFormats
;
564 fChoiceFormats
= NULL
;
569 uprv_arrayCopy(limits
, fChoiceLimits
, fCount
);
570 uprv_arrayCopy(formats
, fChoiceFormats
, fCount
);
573 uprv_arrayCopy(closures
, fClosures
, fCount
);
576 for (i
=0; i
<fCount
; ++i
) {
577 fClosures
[i
] = FALSE
;
582 // -------------------------------------
583 // Gets the limit array.
586 ChoiceFormat::getLimits(int32_t& cnt
) const
589 return fChoiceLimits
;
592 // -------------------------------------
593 // Gets the closures array.
596 ChoiceFormat::getClosures(int32_t& cnt
) const
602 // -------------------------------------
603 // Gets the format array.
606 ChoiceFormat::getFormats(int32_t& cnt
) const
609 return fChoiceFormats
;
612 // -------------------------------------
613 // Formats an int64 number, it's actually formatted as
614 // a double. The returned format string may differ
615 // from the input number because of this.
618 ChoiceFormat::format(int64_t number
,
619 UnicodeString
& appendTo
,
620 FieldPosition
& status
) const
622 return format((double) number
, appendTo
, status
);
625 // -------------------------------------
626 // Formats a long number, it's actually formatted as
627 // a double. The returned format string may differ
628 // from the input number because of this.
631 ChoiceFormat::format(int32_t number
,
632 UnicodeString
& appendTo
,
633 FieldPosition
& status
) const
635 return format((double) number
, appendTo
, status
);
638 // -------------------------------------
639 // Formats a double number.
642 ChoiceFormat::format(double number
,
643 UnicodeString
& appendTo
,
644 FieldPosition
& /*pos*/) const
648 for (i
= 0; i
< fCount
; ++i
) {
650 if (!(number
> fChoiceLimits
[i
])) {
651 // same as number <= fChoiceLimits, except catches NaN
654 } else if (!(number
>= fChoiceLimits
[i
])) {
655 // same as number < fChoiceLimits, except catches NaN
663 // return either a formatted number, or a string
664 appendTo
+= fChoiceFormats
[i
];
668 // -------------------------------------
669 // Formats an array of objects. Checks if the data type of the objects
670 // to get the right value for formatting.
673 ChoiceFormat::format(const Formattable
* objs
,
675 UnicodeString
& appendTo
,
677 UErrorCode
& status
) const
680 status
= U_ILLEGAL_ARGUMENT_ERROR
;
684 UnicodeString buffer
;
685 for (int32_t i
= 0; i
< cnt
; i
++) {
686 double objDouble
= objs
[i
].getDouble(status
);
687 if (U_SUCCESS(status
)) {
689 appendTo
+= format(objDouble
, buffer
, pos
);
696 // -------------------------------------
697 // Formats an array of objects. Checks if the data type of the objects
698 // to get the right value for formatting.
701 ChoiceFormat::format(const Formattable
& obj
,
702 UnicodeString
& appendTo
,
704 UErrorCode
& status
) const
706 return NumberFormat::format(obj
, appendTo
, pos
, status
);
708 // -------------------------------------
711 ChoiceFormat::parse(const UnicodeString
& text
,
713 ParsePosition
& status
) const
715 // find the best number (defined as the one with the longest parse)
716 int32_t start
= status
.getIndex();
717 int32_t furthest
= start
;
718 double bestNumber
= uprv_getNaN();
719 double tempNumber
= 0.0;
720 for (int i
= 0; i
< fCount
; ++i
) {
721 int32_t len
= fChoiceFormats
[i
].length();
722 if (text
.compare(start
, len
, fChoiceFormats
[i
]) == 0) {
723 status
.setIndex(start
+ len
);
724 tempNumber
= fChoiceLimits
[i
];
725 if (status
.getIndex() > furthest
) {
726 furthest
= status
.getIndex();
727 bestNumber
= tempNumber
;
728 if (furthest
== text
.length())
733 status
.setIndex(furthest
);
734 if (status
.getIndex() == start
) {
735 status
.setErrorIndex(furthest
);
737 result
.setDouble(bestNumber
);
740 // -------------------------------------
741 // Parses the text and return the Formattable object.
744 ChoiceFormat::parse(const UnicodeString
& text
,
746 UErrorCode
& status
) const
748 NumberFormat::parse(text
, result
, status
);
751 // -------------------------------------
754 ChoiceFormat::clone() const
756 ChoiceFormat
*aCopy
= new ChoiceFormat(*this);
762 #endif /* #if !UCONFIG_NO_FORMATTING */