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 */