2 *******************************************************************************
3 * Copyright (C) 1997-2003, 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"
36 // *****************************************************************************
38 // *****************************************************************************
42 const char ChoiceFormat::fgClassID
= 0; // Value is irrelevant
44 // Special characters used by ChoiceFormat. There are two characters
45 // used interchangeably to indicate <=. Either is parsed, but only
46 // LESS_EQUAL is generated by toPattern().
47 #define SINGLE_QUOTE ((UChar)0x0027) /*'*/
48 #define LESS_THAN ((UChar)0x003C) /*<*/
49 #define LESS_EQUAL ((UChar)0x0023) /*#*/
50 #define LESS_EQUAL2 ((UChar)0x2264)
51 #define VERTICAL_BAR ((UChar)0x007C) /*|*/
52 #define MINUS ((UChar)0x002D) /*-*/
53 #define INFINITY ((UChar)0x221E)
55 const UChar
ChoiceFormat::fgPositiveInfinity
[] = {INFINITY
, 0};
56 const UChar
ChoiceFormat::fgNegativeInfinity
[] = {MINUS
, INFINITY
, 0};
57 #define POSITIVE_INF_STRLEN 1
58 #define NEGATIVE_INF_STRLEN 2
60 // -------------------------------------
61 // Creates a ChoiceFormat instance based on the pattern.
63 ChoiceFormat::ChoiceFormat(const UnicodeString
& newPattern
,
70 applyPattern(newPattern
, status
);
73 // -------------------------------------
74 // Creates a ChoiceFormat instance with the limit array and
75 // format strings for each limit.
77 ChoiceFormat::ChoiceFormat(const double* limits
,
78 const UnicodeString
* formats
,
85 setChoices(limits
, formats
, cnt
);
88 // -------------------------------------
90 ChoiceFormat::ChoiceFormat(const double* limits
,
91 const UBool
* closures
,
92 const UnicodeString
* formats
,
99 setChoices(limits
, closures
, formats
, cnt
);
102 // -------------------------------------
105 ChoiceFormat::ChoiceFormat(const ChoiceFormat
& that
)
106 : NumberFormat(that
),
114 // -------------------------------------
115 // Private constructor that creates a
116 // ChoiceFormat instance based on the
117 // pattern and populates UParseError
119 ChoiceFormat::ChoiceFormat(const UnicodeString
& newPattern
,
120 UParseError
& parseError
,
127 applyPattern(newPattern
,parseError
, status
);
129 // -------------------------------------
132 ChoiceFormat::operator==(const Format
& that
) const
134 if (this == &that
) return TRUE
;
135 if (this->getDynamicClassID() != that
.getDynamicClassID()) return FALSE
; // not the same class
136 if (!NumberFormat::operator==(that
)) return FALSE
;
137 ChoiceFormat
& thatAlias
= (ChoiceFormat
&)that
;
138 if (fCount
!= thatAlias
.fCount
) return FALSE
;
139 // Checks the limits, the corresponding format string and LE or LT flags.
140 // LE means less than and equal to, LT means less than.
141 for (int32_t i
= 0; i
< fCount
; i
++) {
142 if ((fChoiceLimits
[i
] != thatAlias
.fChoiceLimits
[i
]) ||
143 (fClosures
[i
] != thatAlias
.fClosures
[i
]) ||
144 (fChoiceFormats
[i
] != thatAlias
.fChoiceFormats
[i
]))
150 // -------------------------------------
154 ChoiceFormat::operator=(const ChoiceFormat
& that
)
157 NumberFormat::operator=(that
);
158 fCount
= that
.fCount
;
159 uprv_free(fChoiceLimits
);
160 fChoiceLimits
= NULL
;
161 uprv_free(fClosures
);
163 delete [] fChoiceFormats
;
164 fChoiceFormats
= NULL
;
166 fChoiceLimits
= (double*) uprv_malloc( sizeof(double) * fCount
);
167 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
168 fChoiceFormats
= new UnicodeString
[fCount
];
170 uprv_arrayCopy(that
.fChoiceLimits
, fChoiceLimits
, fCount
);
171 uprv_arrayCopy(that
.fClosures
, fClosures
, fCount
);
172 uprv_arrayCopy(that
.fChoiceFormats
, fChoiceFormats
, fCount
);
177 // -------------------------------------
179 ChoiceFormat::~ChoiceFormat()
181 uprv_free(fChoiceLimits
);
182 fChoiceLimits
= NULL
;
183 uprv_free(fClosures
);
185 delete [] fChoiceFormats
;
186 fChoiceFormats
= NULL
;
191 * Convert a string to a double value
194 ChoiceFormat::stod(const UnicodeString
& string
)
199 string
.extract(0, string
.length(), source
, sizeof(source
), ""); /* invariant codepage */
200 return uprv_strtod(source
,&end
);
203 // -------------------------------------
206 * Convert a double value to a string
209 ChoiceFormat::dtos(double value
,
210 UnicodeString
& string
)
214 uprv_dtostr(value
, temp
, 3, TRUE
);
215 string
= UnicodeString(temp
, ""); /* invariant codepage */
219 // -------------------------------------
220 // calls the overloaded applyPattern method.
223 ChoiceFormat::applyPattern(const UnicodeString
& pattern
,
226 UParseError parseError
;
227 applyPattern(pattern
, parseError
, status
);
230 // -------------------------------------
231 // Applies the pattern to this ChoiceFormat instance.
234 ChoiceFormat::applyPattern(const UnicodeString
& pattern
,
235 UParseError
& parseError
,
238 if (U_FAILURE(status
))
243 // Clear error struct
244 parseError
.offset
= -1;
245 parseError
.preContext
[0] = parseError
.postContext
[0] = (UChar
)0;
247 // Perform 2 passes. The first computes the number of limits in
248 // this pattern (fCount), which is 1 more than the number of
249 // literal VERTICAL_BAR characters.
252 for (i
=0; i
<pattern
.length(); ++i
) {
253 UChar c
= pattern
[i
];
254 if (c
== SINGLE_QUOTE
) {
255 // Skip over the entire quote, including embedded
256 // contiguous pairs of SINGLE_QUOTE.
260 } while (i
<pattern
.length() &&
261 pattern
[i
] != SINGLE_QUOTE
);
262 if ((i
+1)<pattern
.length() &&
263 pattern
[i
+1] == SINGLE_QUOTE
) {
264 // SINGLE_QUOTE pair; skip over it
270 } else if (c
== VERTICAL_BAR
) {
275 // Allocate the required storage.
276 double *newLimits
= (double*) uprv_malloc( sizeof(double) * count
);
278 if (newLimits
== 0) {
279 status
= U_MEMORY_ALLOCATION_ERROR
;
282 UBool
*newClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * count
);
284 if (newClosures
== 0) {
285 status
= U_MEMORY_ALLOCATION_ERROR
;
286 uprv_free(newLimits
);
289 UnicodeString
*newFormats
= new UnicodeString
[count
];
291 if (newFormats
== 0) {
292 status
= U_MEMORY_ALLOCATION_ERROR
;
293 uprv_free(newLimits
);
294 uprv_free(newClosures
);
298 // Perform the second pass
299 int32_t k
= 0; // index into newXxx[] arrays
300 UnicodeString buf
; // scratch buffer
301 UBool inQuote
= FALSE
;
302 UBool inNumber
= TRUE
; // TRUE before < or #, FALSE after
304 for (i
=0; i
<pattern
.length(); ++i
) {
305 UChar c
= pattern
[i
];
306 if (c
== SINGLE_QUOTE
) {
307 // Check for SINGLE_QUOTE pair indicating a literal quote
308 if ((i
+1) < pattern
.length() &&
309 pattern
[i
+1] == SINGLE_QUOTE
) {
315 } else if (inQuote
) {
317 } else if (c
== LESS_THAN
|| c
== LESS_EQUAL
|| c
== LESS_EQUAL2
) {
318 if (!inNumber
|| buf
.length() == 0) {
325 if (!buf
.compare(fgPositiveInfinity
, POSITIVE_INF_STRLEN
)) {
326 limit
= uprv_getInfinity();
327 } else if (!buf
.compare(fgNegativeInfinity
, NEGATIVE_INF_STRLEN
)) {
328 limit
= -uprv_getInfinity();
334 // This shouldn't happen. If it does, it means that
335 // the count determined in the first pass did not
336 // match the number of elements found in the second
340 newLimits
[k
] = limit
;
341 newClosures
[k
] = (c
== LESS_THAN
);
343 if (k
> 0 && limit
<= newLimits
[k
-1]) {
344 // Each limit must be strictly > than the previous
345 // limit. One exception: Two subsequent limits may be
346 // == if the first closure is FALSE and the second
347 // closure is TRUE. This places the limit value in
348 // the second interval.
349 if (!(limit
== newLimits
[k
-1] &&
357 } else if (c
== VERTICAL_BAR
) {
371 if (k
!= (count
-1) || inNumber
|| inQuote
) {
376 // Don't modify this object until the parse succeeds
377 uprv_free(fChoiceLimits
);
378 uprv_free(fClosures
);
379 delete[] fChoiceFormats
;
381 fChoiceLimits
= newLimits
;
382 fClosures
= newClosures
;
383 fChoiceFormats
= newFormats
;
387 status
= U_ILLEGAL_ARGUMENT_ERROR
;
388 syntaxError(pattern
,i
,parseError
);
389 uprv_free(newLimits
);
390 uprv_free(newClosures
);
395 // -------------------------------------
396 // Reconstruct the original input pattern.
399 ChoiceFormat::toPattern(UnicodeString
& result
) const
402 for (int32_t i
= 0; i
< fCount
; ++i
) {
404 result
+= VERTICAL_BAR
;
407 if (uprv_isPositiveInfinity(fChoiceLimits
[i
])) {
409 } else if (uprv_isNegativeInfinity(fChoiceLimits
[i
])) {
413 result
+= dtos(fChoiceLimits
[i
], buf
);
418 result
+= LESS_EQUAL
;
420 // Append fChoiceFormats[i], using quotes if there are special
421 // characters. Single quotes themselves must be escaped in
423 const UnicodeString
& text
= fChoiceFormats
[i
];
424 UBool needQuote
= text
.indexOf(LESS_THAN
) >= 0
425 || text
.indexOf(LESS_EQUAL
) >= 0
426 || text
.indexOf(LESS_EQUAL2
) >= 0
427 || text
.indexOf(VERTICAL_BAR
) >= 0;
429 result
+= SINGLE_QUOTE
;
431 if (text
.indexOf(SINGLE_QUOTE
) < 0) {
435 for (int32_t j
= 0; j
< text
.length(); ++j
) {
438 if (c
== SINGLE_QUOTE
) {
444 result
+= SINGLE_QUOTE
;
451 #ifdef U_USE_CHOICE_FORMAT_DEPRECATES
452 // -------------------------------------
453 // Adopts the limit and format arrays.
456 ChoiceFormat::adoptChoices(double *limits
,
457 UnicodeString
*formats
,
460 adoptChoices(limits
, (UBool
*)0, formats
, cnt
);
463 // -------------------------------------
464 // Adopts the limit and format arrays.
467 ChoiceFormat::adoptChoices(double *limits
,
469 UnicodeString
*formats
,
472 if(limits
== 0 || formats
== 0)
475 uprv_free(fChoiceLimits
);
476 uprv_free(fClosures
);
477 delete [] fChoiceFormats
;
478 fChoiceLimits
= limits
;
479 fClosures
= closures
;
480 fChoiceFormats
= formats
;
483 if (fClosures
== 0) {
484 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
486 for (i
=0; i
<fCount
; ++i
) {
487 fClosures
[i
] = FALSE
;
493 // -------------------------------------
494 // Sets the limit and format arrays.
496 ChoiceFormat::setChoices( const double* limits
,
497 const UnicodeString
* formats
,
500 setChoices(limits
, 0, formats
, cnt
);
503 // -------------------------------------
504 // Sets the limit and format arrays.
506 ChoiceFormat::setChoices( const double* limits
,
507 const UBool
* closures
,
508 const UnicodeString
* formats
,
511 if(limits
== 0 || formats
== 0)
514 uprv_free(fChoiceLimits
);
515 uprv_free(fClosures
);
516 delete [] fChoiceFormats
;
518 // Note that the old arrays are deleted and this owns
519 // the created array.
521 fChoiceLimits
= (double*) uprv_malloc( sizeof(double) * fCount
);
522 fClosures
= (UBool
*) uprv_malloc( sizeof(UBool
) * fCount
);
523 fChoiceFormats
= new UnicodeString
[fCount
];
525 uprv_arrayCopy(limits
, fChoiceLimits
, fCount
);
526 uprv_arrayCopy(formats
, fChoiceFormats
, fCount
);
529 uprv_arrayCopy(closures
, fClosures
, fCount
);
532 for (i
=0; i
<fCount
; ++i
) {
533 fClosures
[i
] = FALSE
;
538 // -------------------------------------
539 // Gets the limit array.
542 ChoiceFormat::getLimits(int32_t& cnt
) const
545 return fChoiceLimits
;
548 // -------------------------------------
549 // Gets the closures array.
552 ChoiceFormat::getClosures(int32_t& cnt
) const
558 // -------------------------------------
559 // Gets the format array.
562 ChoiceFormat::getFormats(int32_t& cnt
) const
565 return fChoiceFormats
;
568 // -------------------------------------
569 // Formats a long number, it's actually formatted as
570 // a double. The returned format string may differ
571 // from the input number because of this.
574 ChoiceFormat::format(int32_t number
,
575 UnicodeString
& appendTo
,
576 FieldPosition
& status
) const
578 return format((double) number
, appendTo
, status
);
581 // -------------------------------------
582 // Formats a double number.
585 ChoiceFormat::format(double number
,
586 UnicodeString
& appendTo
,
587 FieldPosition
& /*pos*/) const
591 for (i
= 0; i
< fCount
; ++i
) {
593 if (!(number
> fChoiceLimits
[i
])) {
594 // same as number <= fChoiceLimits, except catches NaN
597 } else if (!(number
>= fChoiceLimits
[i
])) {
598 // same as number < fChoiceLimits, except catches NaN
606 // return either a formatted number, or a string
607 appendTo
+= fChoiceFormats
[i
];
611 // -------------------------------------
612 // Formats an array of objects. Checks if the data type of the objects
613 // to get the right value for formatting.
616 ChoiceFormat::format(const Formattable
* objs
,
618 UnicodeString
& appendTo
,
620 UErrorCode
& status
) const
623 status
= U_ILLEGAL_ARGUMENT_ERROR
;
627 UnicodeString buffer
;
628 for (int32_t i
= 0; i
< cnt
; i
++) {
629 double objDouble
= (objs
[i
].getType() == Formattable::kLong
) ?
630 ((double) objs
[i
].getLong()) : objs
[i
].getDouble();
632 appendTo
+= format(objDouble
, buffer
, pos
);
638 // -------------------------------------
639 // Formats an array of objects. Checks if the data type of the objects
640 // to get the right value for formatting.
643 ChoiceFormat::format(const Formattable
& obj
,
644 UnicodeString
& appendTo
,
646 UErrorCode
& status
) const
648 return NumberFormat::format(obj
, appendTo
, pos
, status
);
650 // -------------------------------------
653 ChoiceFormat::parse(const UnicodeString
& text
,
655 ParsePosition
& status
) const
657 // find the best number (defined as the one with the longest parse)
658 int32_t start
= status
.getIndex();
659 int32_t furthest
= start
;
660 double bestNumber
= uprv_getNaN();
661 double tempNumber
= 0.0;
662 for (int i
= 0; i
< fCount
; ++i
) {
663 int32_t len
= fChoiceFormats
[i
].length();
664 if (text
.compare(start
, len
, fChoiceFormats
[i
]) == 0) {
665 status
.setIndex(start
+ len
);
666 tempNumber
= fChoiceLimits
[i
];
667 if (status
.getIndex() > furthest
) {
668 furthest
= status
.getIndex();
669 bestNumber
= tempNumber
;
670 if (furthest
== text
.length())
675 status
.setIndex(furthest
);
676 if (status
.getIndex() == start
) {
677 status
.setErrorIndex(furthest
);
679 result
.setDouble(bestNumber
);
682 // -------------------------------------
683 // Parses the text and return the Formattable object.
686 ChoiceFormat::parse(const UnicodeString
& text
,
688 UErrorCode
& status
) const
690 NumberFormat::parse(text
, result
, status
);
693 // -------------------------------------
696 ChoiceFormat::clone() const
698 ChoiceFormat
*aCopy
= new ChoiceFormat(*this);
704 #endif /* #if !UCONFIG_NO_FORMATTING */