2 *******************************************************************************
3 * Copyright (C) 1997-2004, 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"
38 // *****************************************************************************
40 // *****************************************************************************
44 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChoiceFormat
)
46 // Special characters used by ChoiceFormat. There are two characters
47 // used interchangeably to indicate <=. Either is parsed, but only
48 // LESS_EQUAL is generated by toPattern().
49 #define SINGLE_QUOTE ((UChar)0x0027) /*'*/
50 #define LESS_THAN ((UChar)0x003C) /*<*/
51 #define LESS_EQUAL ((UChar)0x0023) /*#*/
52 #define LESS_EQUAL2 ((UChar)0x2264)
53 #define VERTICAL_BAR ((UChar)0x007C) /*|*/
54 #define MINUS ((UChar)0x002D) /*-*/
55 #define INFINITY ((UChar)0x221E)
57 static const UChar gPositiveInfinity
[] = {INFINITY
, 0};
58 static const UChar gNegativeInfinity
[] = {MINUS
, INFINITY
, 0};
59 #define POSITIVE_INF_STRLEN 1
60 #define NEGATIVE_INF_STRLEN 2
62 // -------------------------------------
63 // Creates a ChoiceFormat instance based on the pattern.
65 ChoiceFormat::ChoiceFormat(const UnicodeString
& newPattern
,
72 applyPattern(newPattern
, status
);
75 // -------------------------------------
76 // Creates a ChoiceFormat instance with the limit array and
77 // format strings for each limit.
79 ChoiceFormat::ChoiceFormat(const double* limits
,
80 const UnicodeString
* formats
,
87 setChoices(limits
, formats
, cnt
);
90 // -------------------------------------
92 ChoiceFormat::ChoiceFormat(const double* limits
,
93 const UBool
* closures
,
94 const UnicodeString
* formats
,
101 setChoices(limits
, closures
, formats
, cnt
);
104 // -------------------------------------
107 ChoiceFormat::ChoiceFormat(const ChoiceFormat
& that
)
108 : NumberFormat(that
),
116 // -------------------------------------
117 // Private constructor that creates a
118 // ChoiceFormat instance based on the
119 // pattern and populates UParseError
121 ChoiceFormat::ChoiceFormat(const UnicodeString
& newPattern
,
122 UParseError
& parseError
,
129 applyPattern(newPattern
,parseError
, status
);
131 // -------------------------------------
134 ChoiceFormat::operator==(const Format
& that
) const
136 if (this == &that
) return TRUE
;
137 if (!NumberFormat::operator==(that
)) return FALSE
;
138 ChoiceFormat
& thatAlias
= (ChoiceFormat
&)that
;
139 if (fCount
!= thatAlias
.fCount
) return FALSE
;
140 // Checks the limits, the corresponding format string and LE or LT flags.
141 // LE means less than and equal to, LT means less than.
142 for (int32_t i
= 0; i
< fCount
; i
++) {
143 if ((fChoiceLimits
[i
] != thatAlias
.fChoiceLimits
[i
]) ||
144 (fClosures
[i
] != thatAlias
.fClosures
[i
]) ||
145 (fChoiceFormats
[i
] != thatAlias
.fChoiceFormats
[i
]))
151 // -------------------------------------
155 ChoiceFormat::operator=(const ChoiceFormat
& that
)
158 NumberFormat::operator=(that
);
159 fCount
= that
.fCount
;
160 uprv_free(fChoiceLimits
);
161 fChoiceLimits
= NULL
;
162 uprv_free(fClosures
);
164 delete [] fChoiceFormats
;
165 fChoiceFormats
= NULL
;
167 fChoiceLimits
= (double*) uprv_malloc( sizeof(double) * fCount
);
168 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
169 fChoiceFormats
= new UnicodeString
[fCount
];
171 uprv_arrayCopy(that
.fChoiceLimits
, fChoiceLimits
, fCount
);
172 uprv_arrayCopy(that
.fClosures
, fClosures
, fCount
);
173 uprv_arrayCopy(that
.fChoiceFormats
, fChoiceFormats
, fCount
);
178 // -------------------------------------
180 ChoiceFormat::~ChoiceFormat()
182 uprv_free(fChoiceLimits
);
183 fChoiceLimits
= NULL
;
184 uprv_free(fClosures
);
186 delete [] fChoiceFormats
;
187 fChoiceFormats
= NULL
;
192 * Convert a string to a double value
195 ChoiceFormat::stod(const UnicodeString
& string
)
200 string
.extract(0, string
.length(), source
, (int32_t)sizeof(source
), US_INV
); /* invariant codepage */
201 return uprv_strtod(source
,&end
);
204 // -------------------------------------
207 * Convert a double value to a string
210 ChoiceFormat::dtos(double value
,
211 UnicodeString
& string
)
215 uprv_dtostr(value
, temp
, 3, TRUE
);
216 string
= UnicodeString(temp
, -1, US_INV
); /* invariant codepage */
220 // -------------------------------------
221 // calls the overloaded applyPattern method.
224 ChoiceFormat::applyPattern(const UnicodeString
& pattern
,
227 UParseError parseError
;
228 applyPattern(pattern
, parseError
, status
);
231 // -------------------------------------
232 // Applies the pattern to this ChoiceFormat instance.
235 ChoiceFormat::applyPattern(const UnicodeString
& pattern
,
236 UParseError
& parseError
,
239 if (U_FAILURE(status
))
244 // Clear error struct
245 parseError
.offset
= -1;
246 parseError
.preContext
[0] = parseError
.postContext
[0] = (UChar
)0;
248 // Perform 2 passes. The first computes the number of limits in
249 // this pattern (fCount), which is 1 more than the number of
250 // literal VERTICAL_BAR characters.
253 for (i
=0; i
<pattern
.length(); ++i
) {
254 UChar c
= pattern
[i
];
255 if (c
== SINGLE_QUOTE
) {
256 // Skip over the entire quote, including embedded
257 // contiguous pairs of SINGLE_QUOTE.
261 } while (i
<pattern
.length() &&
262 pattern
[i
] != SINGLE_QUOTE
);
263 if ((i
+1)<pattern
.length() &&
264 pattern
[i
+1] == SINGLE_QUOTE
) {
265 // SINGLE_QUOTE pair; skip over it
271 } else if (c
== VERTICAL_BAR
) {
276 // Allocate the required storage.
277 double *newLimits
= (double*) uprv_malloc( sizeof(double) * count
);
279 if (newLimits
== 0) {
280 status
= U_MEMORY_ALLOCATION_ERROR
;
283 UBool
*newClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * count
);
285 if (newClosures
== 0) {
286 status
= U_MEMORY_ALLOCATION_ERROR
;
287 uprv_free(newLimits
);
290 UnicodeString
*newFormats
= new UnicodeString
[count
];
292 if (newFormats
== 0) {
293 status
= U_MEMORY_ALLOCATION_ERROR
;
294 uprv_free(newLimits
);
295 uprv_free(newClosures
);
299 // Perform the second pass
300 int32_t k
= 0; // index into newXxx[] arrays
301 UnicodeString buf
; // scratch buffer
302 UBool inQuote
= FALSE
;
303 UBool inNumber
= TRUE
; // TRUE before < or #, FALSE after
305 for (i
=0; i
<pattern
.length(); ++i
) {
306 UChar c
= pattern
[i
];
307 if (c
== SINGLE_QUOTE
) {
308 // Check for SINGLE_QUOTE pair indicating a literal quote
309 if ((i
+1) < pattern
.length() &&
310 pattern
[i
+1] == SINGLE_QUOTE
) {
316 } else if (inQuote
) {
318 } else if (c
== LESS_THAN
|| c
== LESS_EQUAL
|| c
== LESS_EQUAL2
) {
319 if (!inNumber
|| buf
.length() == 0) {
326 if (!buf
.compare(gPositiveInfinity
, POSITIVE_INF_STRLEN
)) {
327 limit
= uprv_getInfinity();
328 } else if (!buf
.compare(gNegativeInfinity
, NEGATIVE_INF_STRLEN
)) {
329 limit
= -uprv_getInfinity();
335 // This shouldn't happen. If it does, it means that
336 // the count determined in the first pass did not
337 // match the number of elements found in the second
341 newLimits
[k
] = limit
;
342 newClosures
[k
] = (c
== LESS_THAN
);
344 if (k
> 0 && limit
<= newLimits
[k
-1]) {
345 // Each limit must be strictly > than the previous
346 // limit. One exception: Two subsequent limits may be
347 // == if the first closure is FALSE and the second
348 // closure is TRUE. This places the limit value in
349 // the second interval.
350 if (!(limit
== newLimits
[k
-1] &&
358 } else if (c
== VERTICAL_BAR
) {
372 if (k
!= (count
-1) || inNumber
|| inQuote
) {
377 // Don't modify this object until the parse succeeds
378 uprv_free(fChoiceLimits
);
379 uprv_free(fClosures
);
380 delete[] fChoiceFormats
;
382 fChoiceLimits
= newLimits
;
383 fClosures
= newClosures
;
384 fChoiceFormats
= newFormats
;
388 status
= U_ILLEGAL_ARGUMENT_ERROR
;
389 syntaxError(pattern
,i
,parseError
);
390 uprv_free(newLimits
);
391 uprv_free(newClosures
);
396 // -------------------------------------
397 // Reconstruct the original input pattern.
400 ChoiceFormat::toPattern(UnicodeString
& result
) const
403 for (int32_t i
= 0; i
< fCount
; ++i
) {
405 result
+= VERTICAL_BAR
;
408 if (uprv_isPositiveInfinity(fChoiceLimits
[i
])) {
410 } else if (uprv_isNegativeInfinity(fChoiceLimits
[i
])) {
414 result
+= dtos(fChoiceLimits
[i
], buf
);
419 result
+= LESS_EQUAL
;
421 // Append fChoiceFormats[i], using quotes if there are special
422 // characters. Single quotes themselves must be escaped in
424 const UnicodeString
& text
= fChoiceFormats
[i
];
425 UBool needQuote
= text
.indexOf(LESS_THAN
) >= 0
426 || text
.indexOf(LESS_EQUAL
) >= 0
427 || text
.indexOf(LESS_EQUAL2
) >= 0
428 || text
.indexOf(VERTICAL_BAR
) >= 0;
430 result
+= SINGLE_QUOTE
;
432 if (text
.indexOf(SINGLE_QUOTE
) < 0) {
436 for (int32_t j
= 0; j
< text
.length(); ++j
) {
439 if (c
== SINGLE_QUOTE
) {
445 result
+= SINGLE_QUOTE
;
452 #ifdef U_USE_CHOICE_FORMAT_DEPRECATES
453 // -------------------------------------
454 // Adopts the limit and format arrays.
457 ChoiceFormat::adoptChoices(double *limits
,
458 UnicodeString
*formats
,
461 adoptChoices(limits
, (UBool
*)0, formats
, cnt
);
464 // -------------------------------------
465 // Adopts the limit and format arrays.
468 ChoiceFormat::adoptChoices(double *limits
,
470 UnicodeString
*formats
,
473 if(limits
== 0 || formats
== 0)
476 uprv_free(fChoiceLimits
);
477 uprv_free(fClosures
);
478 delete [] fChoiceFormats
;
479 fChoiceLimits
= limits
;
480 fClosures
= closures
;
481 fChoiceFormats
= formats
;
484 if (fClosures
== 0) {
485 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
487 for (i
=0; i
<fCount
; ++i
) {
488 fClosures
[i
] = FALSE
;
494 // -------------------------------------
495 // Sets the limit and format arrays.
497 ChoiceFormat::setChoices( const double* limits
,
498 const UnicodeString
* formats
,
501 setChoices(limits
, 0, formats
, cnt
);
504 // -------------------------------------
505 // Sets the limit and format arrays.
507 ChoiceFormat::setChoices( const double* limits
,
508 const UBool
* closures
,
509 const UnicodeString
* formats
,
512 if(limits
== 0 || formats
== 0)
515 uprv_free(fChoiceLimits
);
516 uprv_free(fClosures
);
517 delete [] fChoiceFormats
;
519 // Note that the old arrays are deleted and this owns
520 // the created array.
522 fChoiceLimits
= (double*) uprv_malloc( sizeof(double) * fCount
);
523 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
524 fChoiceFormats
= new UnicodeString
[fCount
];
526 uprv_arrayCopy(limits
, fChoiceLimits
, fCount
);
527 uprv_arrayCopy(formats
, fChoiceFormats
, fCount
);
530 uprv_arrayCopy(closures
, fClosures
, fCount
);
533 for (i
=0; i
<fCount
; ++i
) {
534 fClosures
[i
] = FALSE
;
539 // -------------------------------------
540 // Gets the limit array.
543 ChoiceFormat::getLimits(int32_t& cnt
) const
546 return fChoiceLimits
;
549 // -------------------------------------
550 // Gets the closures array.
553 ChoiceFormat::getClosures(int32_t& cnt
) const
559 // -------------------------------------
560 // Gets the format array.
563 ChoiceFormat::getFormats(int32_t& cnt
) const
566 return fChoiceFormats
;
569 // -------------------------------------
570 // Formats an int64 number, it's actually formatted as
571 // a double. The returned format string may differ
572 // from the input number because of this.
575 ChoiceFormat::format(int64_t number
,
576 UnicodeString
& appendTo
,
577 FieldPosition
& status
) const
579 return format((double) number
, appendTo
, status
);
582 // -------------------------------------
583 // Formats a long number, it's actually formatted as
584 // a double. The returned format string may differ
585 // from the input number because of this.
588 ChoiceFormat::format(int32_t number
,
589 UnicodeString
& appendTo
,
590 FieldPosition
& status
) const
592 return format((double) number
, appendTo
, status
);
595 // -------------------------------------
596 // Formats a double number.
599 ChoiceFormat::format(double number
,
600 UnicodeString
& appendTo
,
601 FieldPosition
& /*pos*/) const
605 for (i
= 0; i
< fCount
; ++i
) {
607 if (!(number
> fChoiceLimits
[i
])) {
608 // same as number <= fChoiceLimits, except catches NaN
611 } else if (!(number
>= fChoiceLimits
[i
])) {
612 // same as number < fChoiceLimits, except catches NaN
620 // return either a formatted number, or a string
621 appendTo
+= fChoiceFormats
[i
];
625 // -------------------------------------
626 // Formats an array of objects. Checks if the data type of the objects
627 // to get the right value for formatting.
630 ChoiceFormat::format(const Formattable
* objs
,
632 UnicodeString
& appendTo
,
634 UErrorCode
& status
) const
637 status
= U_ILLEGAL_ARGUMENT_ERROR
;
641 UnicodeString buffer
;
642 for (int32_t i
= 0; i
< cnt
; i
++) {
643 double objDouble
= objs
[i
].getDouble(status
);
644 if (U_SUCCESS(status
)) {
646 appendTo
+= format(objDouble
, buffer
, pos
);
653 // -------------------------------------
654 // Formats an array of objects. Checks if the data type of the objects
655 // to get the right value for formatting.
658 ChoiceFormat::format(const Formattable
& obj
,
659 UnicodeString
& appendTo
,
661 UErrorCode
& status
) const
663 return NumberFormat::format(obj
, appendTo
, pos
, status
);
665 // -------------------------------------
668 ChoiceFormat::parse(const UnicodeString
& text
,
670 ParsePosition
& status
) const
672 // find the best number (defined as the one with the longest parse)
673 int32_t start
= status
.getIndex();
674 int32_t furthest
= start
;
675 double bestNumber
= uprv_getNaN();
676 double tempNumber
= 0.0;
677 for (int i
= 0; i
< fCount
; ++i
) {
678 int32_t len
= fChoiceFormats
[i
].length();
679 if (text
.compare(start
, len
, fChoiceFormats
[i
]) == 0) {
680 status
.setIndex(start
+ len
);
681 tempNumber
= fChoiceLimits
[i
];
682 if (status
.getIndex() > furthest
) {
683 furthest
= status
.getIndex();
684 bestNumber
= tempNumber
;
685 if (furthest
== text
.length())
690 status
.setIndex(furthest
);
691 if (status
.getIndex() == start
) {
692 status
.setErrorIndex(furthest
);
694 result
.setDouble(bestNumber
);
697 // -------------------------------------
698 // Parses the text and return the Formattable object.
701 ChoiceFormat::parse(const UnicodeString
& text
,
703 UErrorCode
& status
) const
705 NumberFormat::parse(text
, result
, status
);
708 // -------------------------------------
711 ChoiceFormat::clone() const
713 ChoiceFormat
*aCopy
= new ChoiceFormat(*this);
719 #endif /* #if !UCONFIG_NO_FORMATTING */