2 *******************************************************************************
3 * Copyright (C) 1997-2006, 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 uprv_arrayCopy(that
.fChoiceLimits
, fChoiceLimits
, fCount
);
173 uprv_arrayCopy(that
.fClosures
, fClosures
, fCount
);
174 uprv_arrayCopy(that
.fChoiceFormats
, fChoiceFormats
, fCount
);
179 // -------------------------------------
181 ChoiceFormat::~ChoiceFormat()
183 uprv_free(fChoiceLimits
);
184 fChoiceLimits
= NULL
;
185 uprv_free(fClosures
);
187 delete [] fChoiceFormats
;
188 fChoiceFormats
= NULL
;
193 * Convert a string to a double value
196 ChoiceFormat::stod(const UnicodeString
& string
)
201 string
.extract(0, string
.length(), source
, (int32_t)sizeof(source
), US_INV
); /* invariant codepage */
202 return uprv_strtod(source
,&end
);
205 // -------------------------------------
208 * Convert a double value to a string
211 ChoiceFormat::dtos(double value
,
212 UnicodeString
& string
)
214 /* Buffer to contain the digits and any extra formatting stuff. */
215 char temp
[DBL_DIG
+ 16];
219 sprintf(temp
, "%.*f", DBL_DIG
, value
);
221 /* Find and convert the decimal point.
222 Using setlocale on some machines will cause sprintf to use a comma for certain locales.
224 while (*itrPtr
&& (*itrPtr
== '-' || isdigit(*itrPtr
))) {
231 /* remove trailing zeros, except the one after '.' */
232 startPtr
= itrPtr
+ 1;
233 itrPtr
= uprv_strchr(startPtr
, 0);
234 while(--itrPtr
> startPtr
){
241 string
= UnicodeString(temp
, -1, US_INV
); /* invariant codepage */
245 // -------------------------------------
246 // calls the overloaded applyPattern method.
249 ChoiceFormat::applyPattern(const UnicodeString
& pattern
,
252 UParseError parseError
;
253 applyPattern(pattern
, parseError
, status
);
256 // -------------------------------------
257 // Applies the pattern to this ChoiceFormat instance.
260 ChoiceFormat::applyPattern(const UnicodeString
& pattern
,
261 UParseError
& parseError
,
264 if (U_FAILURE(status
))
269 // Clear error struct
270 parseError
.offset
= -1;
271 parseError
.preContext
[0] = parseError
.postContext
[0] = (UChar
)0;
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.
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.
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
296 } else if (c
== VERTICAL_BAR
) {
301 // Allocate the required storage.
302 double *newLimits
= (double*) uprv_malloc( sizeof(double) * count
);
304 if (newLimits
== 0) {
305 status
= U_MEMORY_ALLOCATION_ERROR
;
308 UBool
*newClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * count
);
310 if (newClosures
== 0) {
311 status
= U_MEMORY_ALLOCATION_ERROR
;
312 uprv_free(newLimits
);
315 UnicodeString
*newFormats
= new UnicodeString
[count
];
317 if (newFormats
== 0) {
318 status
= U_MEMORY_ALLOCATION_ERROR
;
319 uprv_free(newLimits
);
320 uprv_free(newClosures
);
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
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
) {
341 } else if (inQuote
) {
343 } else if (c
== LESS_THAN
|| c
== LESS_EQUAL
|| c
== LESS_EQUAL2
) {
344 if (!inNumber
|| buf
.length() == 0) {
351 if (!buf
.compare(gPositiveInfinity
, POSITIVE_INF_STRLEN
)) {
352 limit
= uprv_getInfinity();
353 } else if (!buf
.compare(gNegativeInfinity
, NEGATIVE_INF_STRLEN
)) {
354 limit
= -uprv_getInfinity();
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
366 newLimits
[k
] = limit
;
367 newClosures
[k
] = (c
== LESS_THAN
);
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] &&
383 } else if (c
== VERTICAL_BAR
) {
397 if (k
!= (count
-1) || inNumber
|| inQuote
) {
402 // Don't modify this object until the parse succeeds
403 uprv_free(fChoiceLimits
);
404 uprv_free(fClosures
);
405 delete[] fChoiceFormats
;
407 fChoiceLimits
= newLimits
;
408 fClosures
= newClosures
;
409 fChoiceFormats
= newFormats
;
413 status
= U_ILLEGAL_ARGUMENT_ERROR
;
414 syntaxError(pattern
,i
,parseError
);
415 uprv_free(newLimits
);
416 uprv_free(newClosures
);
421 // -------------------------------------
422 // Reconstruct the original input pattern.
425 ChoiceFormat::toPattern(UnicodeString
& result
) const
428 for (int32_t i
= 0; i
< fCount
; ++i
) {
430 result
+= VERTICAL_BAR
;
433 if (uprv_isPositiveInfinity(fChoiceLimits
[i
])) {
435 } else if (uprv_isNegativeInfinity(fChoiceLimits
[i
])) {
439 result
+= dtos(fChoiceLimits
[i
], buf
);
444 result
+= LESS_EQUAL
;
446 // Append fChoiceFormats[i], using quotes if there are special
447 // characters. Single quotes themselves must be escaped in
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;
455 result
+= SINGLE_QUOTE
;
457 if (text
.indexOf(SINGLE_QUOTE
) < 0) {
461 for (int32_t j
= 0; j
< text
.length(); ++j
) {
464 if (c
== SINGLE_QUOTE
) {
470 result
+= SINGLE_QUOTE
;
477 #ifdef U_USE_CHOICE_FORMAT_DEPRECATES
478 // -------------------------------------
479 // Adopts the limit and format arrays.
482 ChoiceFormat::adoptChoices(double *limits
,
483 UnicodeString
*formats
,
486 adoptChoices(limits
, (UBool
*)0, formats
, cnt
);
489 // -------------------------------------
490 // Adopts the limit and format arrays.
493 ChoiceFormat::adoptChoices(double *limits
,
495 UnicodeString
*formats
,
498 if(limits
== 0 || formats
== 0)
501 uprv_free(fChoiceLimits
);
502 uprv_free(fClosures
);
503 delete [] fChoiceFormats
;
504 fChoiceLimits
= limits
;
505 fClosures
= closures
;
506 fChoiceFormats
= formats
;
509 if (fClosures
== 0) {
510 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
512 for (i
=0; i
<fCount
; ++i
) {
513 fClosures
[i
] = FALSE
;
519 // -------------------------------------
520 // Sets the limit and format arrays.
522 ChoiceFormat::setChoices( const double* limits
,
523 const UnicodeString
* formats
,
526 setChoices(limits
, 0, formats
, cnt
);
529 // -------------------------------------
530 // Sets the limit and format arrays.
532 ChoiceFormat::setChoices( const double* limits
,
533 const UBool
* closures
,
534 const UnicodeString
* formats
,
537 if(limits
== 0 || formats
== 0)
540 uprv_free(fChoiceLimits
);
541 uprv_free(fClosures
);
542 delete [] fChoiceFormats
;
544 // Note that the old arrays are deleted and this owns
545 // the created array.
547 fChoiceLimits
= (double*) uprv_malloc( sizeof(double) * fCount
);
548 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
549 fChoiceFormats
= new UnicodeString
[fCount
];
551 uprv_arrayCopy(limits
, fChoiceLimits
, fCount
);
552 uprv_arrayCopy(formats
, fChoiceFormats
, fCount
);
555 uprv_arrayCopy(closures
, fClosures
, fCount
);
558 for (i
=0; i
<fCount
; ++i
) {
559 fClosures
[i
] = FALSE
;
564 // -------------------------------------
565 // Gets the limit array.
568 ChoiceFormat::getLimits(int32_t& cnt
) const
571 return fChoiceLimits
;
574 // -------------------------------------
575 // Gets the closures array.
578 ChoiceFormat::getClosures(int32_t& cnt
) const
584 // -------------------------------------
585 // Gets the format array.
588 ChoiceFormat::getFormats(int32_t& cnt
) const
591 return fChoiceFormats
;
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.
600 ChoiceFormat::format(int64_t number
,
601 UnicodeString
& appendTo
,
602 FieldPosition
& status
) const
604 return format((double) number
, appendTo
, status
);
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.
613 ChoiceFormat::format(int32_t number
,
614 UnicodeString
& appendTo
,
615 FieldPosition
& status
) const
617 return format((double) number
, appendTo
, status
);
620 // -------------------------------------
621 // Formats a double number.
624 ChoiceFormat::format(double number
,
625 UnicodeString
& appendTo
,
626 FieldPosition
& /*pos*/) const
630 for (i
= 0; i
< fCount
; ++i
) {
632 if (!(number
> fChoiceLimits
[i
])) {
633 // same as number <= fChoiceLimits, except catches NaN
636 } else if (!(number
>= fChoiceLimits
[i
])) {
637 // same as number < fChoiceLimits, except catches NaN
645 // return either a formatted number, or a string
646 appendTo
+= fChoiceFormats
[i
];
650 // -------------------------------------
651 // Formats an array of objects. Checks if the data type of the objects
652 // to get the right value for formatting.
655 ChoiceFormat::format(const Formattable
* objs
,
657 UnicodeString
& appendTo
,
659 UErrorCode
& status
) const
662 status
= U_ILLEGAL_ARGUMENT_ERROR
;
666 UnicodeString buffer
;
667 for (int32_t i
= 0; i
< cnt
; i
++) {
668 double objDouble
= objs
[i
].getDouble(status
);
669 if (U_SUCCESS(status
)) {
671 appendTo
+= format(objDouble
, buffer
, pos
);
678 // -------------------------------------
679 // Formats an array of objects. Checks if the data type of the objects
680 // to get the right value for formatting.
683 ChoiceFormat::format(const Formattable
& obj
,
684 UnicodeString
& appendTo
,
686 UErrorCode
& status
) const
688 return NumberFormat::format(obj
, appendTo
, pos
, status
);
690 // -------------------------------------
693 ChoiceFormat::parse(const UnicodeString
& text
,
695 ParsePosition
& status
) const
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())
715 status
.setIndex(furthest
);
716 if (status
.getIndex() == start
) {
717 status
.setErrorIndex(furthest
);
719 result
.setDouble(bestNumber
);
722 // -------------------------------------
723 // Parses the text and return the Formattable object.
726 ChoiceFormat::parse(const UnicodeString
& text
,
728 UErrorCode
& status
) const
730 NumberFormat::parse(text
, result
, status
);
733 // -------------------------------------
736 ChoiceFormat::clone() const
738 ChoiceFormat
*aCopy
= new ChoiceFormat(*this);
744 #endif /* #if !UCONFIG_NO_FORMATTING */