| Index: icu46/source/i18n/choicfmt.cpp
|
| ===================================================================
|
| --- icu46/source/i18n/choicfmt.cpp (revision 0)
|
| +++ icu46/source/i18n/choicfmt.cpp (revision 0)
|
| @@ -0,0 +1,764 @@
|
| +/*
|
| +*******************************************************************************
|
| +* Copyright (C) 1997-2009, International Business Machines Corporation and *
|
| +* others. All Rights Reserved. *
|
| +*******************************************************************************
|
| +*
|
| +* File CHOICFMT.CPP
|
| +*
|
| +* Modification History:
|
| +*
|
| +* Date Name Description
|
| +* 02/19/97 aliu Converted from java.
|
| +* 03/20/97 helena Finished first cut of implementation and got rid
|
| +* of nextDouble/previousDouble and replaced with
|
| +* boolean array.
|
| +* 4/10/97 aliu Clean up. Modified to work on AIX.
|
| +* 06/04/97 helena Fixed applyPattern(), toPattern() and not to include
|
| +* wchar.h.
|
| +* 07/09/97 helena Made ParsePosition into a class.
|
| +* 08/06/97 nos removed overloaded constructor, fixed 'format(array)'
|
| +* 07/22/98 stephen JDK 1.2 Sync - removed UBool array (doubleFlags)
|
| +* 02/22/99 stephen Removed character literals for EBCDIC safety
|
| +********************************************************************************
|
| +*/
|
| +
|
| +#include "unicode/utypes.h"
|
| +
|
| +#if !UCONFIG_NO_FORMATTING
|
| +
|
| +#include "unicode/choicfmt.h"
|
| +#include "unicode/numfmt.h"
|
| +#include "unicode/locid.h"
|
| +#include "cpputils.h"
|
| +#include "cstring.h"
|
| +#include "putilimp.h"
|
| +#include <stdio.h>
|
| +#include <float.h>
|
| +
|
| +// *****************************************************************************
|
| +// class ChoiceFormat
|
| +// *****************************************************************************
|
| +
|
| +U_NAMESPACE_BEGIN
|
| +
|
| +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChoiceFormat)
|
| +
|
| +// Special characters used by ChoiceFormat. There are two characters
|
| +// used interchangeably to indicate <=. Either is parsed, but only
|
| +// LESS_EQUAL is generated by toPattern().
|
| +#define SINGLE_QUOTE ((UChar)0x0027) /*'*/
|
| +#define LESS_THAN ((UChar)0x003C) /*<*/
|
| +#define LESS_EQUAL ((UChar)0x0023) /*#*/
|
| +#define LESS_EQUAL2 ((UChar)0x2264)
|
| +#define VERTICAL_BAR ((UChar)0x007C) /*|*/
|
| +#define MINUS ((UChar)0x002D) /*-*/
|
| +
|
| +#ifdef INFINITY
|
| +#undef INFINITY
|
| +#endif
|
| +#define INFINITY ((UChar)0x221E)
|
| +
|
| +static const UChar gPositiveInfinity[] = {INFINITY, 0};
|
| +static const UChar gNegativeInfinity[] = {MINUS, INFINITY, 0};
|
| +#define POSITIVE_INF_STRLEN 1
|
| +#define NEGATIVE_INF_STRLEN 2
|
| +
|
| +// -------------------------------------
|
| +// Creates a ChoiceFormat instance based on the pattern.
|
| +
|
| +ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
|
| + UErrorCode& status)
|
| +: fChoiceLimits(0),
|
| + fClosures(0),
|
| + fChoiceFormats(0),
|
| + fCount(0)
|
| +{
|
| + applyPattern(newPattern, status);
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Creates a ChoiceFormat instance with the limit array and
|
| +// format strings for each limit.
|
| +
|
| +ChoiceFormat::ChoiceFormat(const double* limits,
|
| + const UnicodeString* formats,
|
| + int32_t cnt )
|
| +: fChoiceLimits(0),
|
| + fClosures(0),
|
| + fChoiceFormats(0),
|
| + fCount(0)
|
| +{
|
| + setChoices(limits, formats, cnt );
|
| +}
|
| +
|
| +// -------------------------------------
|
| +
|
| +ChoiceFormat::ChoiceFormat(const double* limits,
|
| + const UBool* closures,
|
| + const UnicodeString* formats,
|
| + int32_t cnt )
|
| +: fChoiceLimits(0),
|
| + fClosures(0),
|
| + fChoiceFormats(0),
|
| + fCount(0)
|
| +{
|
| + setChoices(limits, closures, formats, cnt );
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// copy constructor
|
| +
|
| +ChoiceFormat::ChoiceFormat(const ChoiceFormat& that)
|
| +: NumberFormat(that),
|
| + fChoiceLimits(0),
|
| + fClosures(0),
|
| + fChoiceFormats(0)
|
| +{
|
| + *this = that;
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Private constructor that creates a
|
| +// ChoiceFormat instance based on the
|
| +// pattern and populates UParseError
|
| +
|
| +ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
|
| + UParseError& parseError,
|
| + UErrorCode& status)
|
| +: fChoiceLimits(0),
|
| + fClosures(0),
|
| + fChoiceFormats(0),
|
| + fCount(0)
|
| +{
|
| + applyPattern(newPattern,parseError, status);
|
| +}
|
| +// -------------------------------------
|
| +
|
| +UBool
|
| +ChoiceFormat::operator==(const Format& that) const
|
| +{
|
| + if (this == &that) return TRUE;
|
| + if (!NumberFormat::operator==(that)) return FALSE;
|
| + ChoiceFormat& thatAlias = (ChoiceFormat&)that;
|
| + if (fCount != thatAlias.fCount) return FALSE;
|
| + // Checks the limits, the corresponding format string and LE or LT flags.
|
| + // LE means less than and equal to, LT means less than.
|
| + for (int32_t i = 0; i < fCount; i++) {
|
| + if ((fChoiceLimits[i] != thatAlias.fChoiceLimits[i]) ||
|
| + (fClosures[i] != thatAlias.fClosures[i]) ||
|
| + (fChoiceFormats[i] != thatAlias.fChoiceFormats[i]))
|
| + return FALSE;
|
| + }
|
| + return TRUE;
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// copy constructor
|
| +
|
| +const ChoiceFormat&
|
| +ChoiceFormat::operator=(const ChoiceFormat& that)
|
| +{
|
| + if (this != &that) {
|
| + NumberFormat::operator=(that);
|
| + fCount = that.fCount;
|
| + uprv_free(fChoiceLimits);
|
| + fChoiceLimits = NULL;
|
| + uprv_free(fClosures);
|
| + fClosures = NULL;
|
| + delete [] fChoiceFormats;
|
| + fChoiceFormats = NULL;
|
| +
|
| + fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount);
|
| + fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount);
|
| + fChoiceFormats = new UnicodeString[fCount];
|
| +
|
| + // check for memory allocation error
|
| + if (!fChoiceLimits || !fClosures || !fChoiceFormats) {
|
| + if (fChoiceLimits) {
|
| + uprv_free(fChoiceLimits);
|
| + fChoiceLimits = NULL;
|
| + }
|
| + if (fClosures) {
|
| + uprv_free(fClosures);
|
| + fClosures = NULL;
|
| + }
|
| + if (fChoiceFormats) {
|
| + delete[] fChoiceFormats;
|
| + fChoiceFormats = NULL;
|
| + }
|
| + } else {
|
| + uprv_arrayCopy(that.fChoiceLimits, fChoiceLimits, fCount);
|
| + uprv_arrayCopy(that.fClosures, fClosures, fCount);
|
| + uprv_arrayCopy(that.fChoiceFormats, fChoiceFormats, fCount);
|
| + }
|
| + }
|
| + return *this;
|
| +}
|
| +
|
| +// -------------------------------------
|
| +
|
| +ChoiceFormat::~ChoiceFormat()
|
| +{
|
| + uprv_free(fChoiceLimits);
|
| + fChoiceLimits = NULL;
|
| + uprv_free(fClosures);
|
| + fClosures = NULL;
|
| + delete [] fChoiceFormats;
|
| + fChoiceFormats = NULL;
|
| + fCount = 0;
|
| +}
|
| +
|
| +/**
|
| + * Convert a string to a double value
|
| + */
|
| +double
|
| +ChoiceFormat::stod(const UnicodeString& string)
|
| +{
|
| + char source[256];
|
| + char* end;
|
| +
|
| + string.extract(0, string.length(), source, (int32_t)sizeof(source), US_INV); /* invariant codepage */
|
| + return uprv_strtod(source,&end);
|
| +}
|
| +
|
| +// -------------------------------------
|
| +
|
| +/**
|
| + * Convert a double value to a string without the overhead of ICU.
|
| + */
|
| +UnicodeString&
|
| +ChoiceFormat::dtos(double value,
|
| + UnicodeString& string)
|
| +{
|
| + /* Buffer to contain the digits and any extra formatting stuff. */
|
| + char temp[DBL_DIG + 16];
|
| + char *itrPtr = temp;
|
| + char *expPtr;
|
| +
|
| + sprintf(temp, "%.*g", DBL_DIG, value);
|
| +
|
| + /* Find and convert the decimal point.
|
| + Using setlocale on some machines will cause sprintf to use a comma for certain locales.
|
| + */
|
| + while (*itrPtr && (*itrPtr == '-' || isdigit(*itrPtr))) {
|
| + itrPtr++;
|
| + }
|
| + if (*itrPtr != 0 && *itrPtr != 'e') {
|
| + /* We reached something that looks like a decimal point.
|
| + In case someone used setlocale(), which changes the decimal point. */
|
| + *itrPtr = '.';
|
| + itrPtr++;
|
| + }
|
| + /* Search for the exponent */
|
| + while (*itrPtr && *itrPtr != 'e') {
|
| + itrPtr++;
|
| + }
|
| + if (*itrPtr == 'e') {
|
| + itrPtr++;
|
| + /* Verify the exponent sign */
|
| + if (*itrPtr == '+' || *itrPtr == '-') {
|
| + itrPtr++;
|
| + }
|
| + /* Remove leading zeros. You will see this on Windows machines. */
|
| + expPtr = itrPtr;
|
| + while (*itrPtr == '0') {
|
| + itrPtr++;
|
| + }
|
| + if (*itrPtr && expPtr != itrPtr) {
|
| + /* Shift the exponent without zeros. */
|
| + while (*itrPtr) {
|
| + *(expPtr++) = *(itrPtr++);
|
| + }
|
| + // NULL terminate
|
| + *expPtr = 0;
|
| + }
|
| + }
|
| +
|
| + string = UnicodeString(temp, -1, US_INV); /* invariant codepage */
|
| + return string;
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// calls the overloaded applyPattern method.
|
| +
|
| +void
|
| +ChoiceFormat::applyPattern(const UnicodeString& pattern,
|
| + UErrorCode& status)
|
| +{
|
| + UParseError parseError;
|
| + applyPattern(pattern, parseError, status);
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Applies the pattern to this ChoiceFormat instance.
|
| +
|
| +void
|
| +ChoiceFormat::applyPattern(const UnicodeString& pattern,
|
| + UParseError& parseError,
|
| + UErrorCode& status)
|
| +{
|
| + if (U_FAILURE(status))
|
| + {
|
| + return;
|
| + }
|
| +
|
| + // Clear error struct
|
| + parseError.offset = -1;
|
| + parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
|
| +
|
| + // Perform 2 passes. The first computes the number of limits in
|
| + // this pattern (fCount), which is 1 more than the number of
|
| + // literal VERTICAL_BAR characters.
|
| + int32_t count = 1;
|
| + int32_t i;
|
| + for (i=0; i<pattern.length(); ++i) {
|
| + UChar c = pattern[i];
|
| + if (c == SINGLE_QUOTE) {
|
| + // Skip over the entire quote, including embedded
|
| + // contiguous pairs of SINGLE_QUOTE.
|
| + for (;;) {
|
| + do {
|
| + ++i;
|
| + } while (i<pattern.length() &&
|
| + pattern[i] != SINGLE_QUOTE);
|
| + if ((i+1)<pattern.length() &&
|
| + pattern[i+1] == SINGLE_QUOTE) {
|
| + // SINGLE_QUOTE pair; skip over it
|
| + ++i;
|
| + } else {
|
| + break;
|
| + }
|
| + }
|
| + } else if (c == VERTICAL_BAR) {
|
| + ++count;
|
| + }
|
| + }
|
| +
|
| + // Allocate the required storage.
|
| + double *newLimits = (double*) uprv_malloc( sizeof(double) * count);
|
| + /* test for NULL */
|
| + if (newLimits == 0) {
|
| + status = U_MEMORY_ALLOCATION_ERROR;
|
| + return;
|
| + }
|
| + UBool *newClosures = (UBool*) uprv_malloc( sizeof(UBool) * count);
|
| + /* test for NULL */
|
| + if (newClosures == 0) {
|
| + status = U_MEMORY_ALLOCATION_ERROR;
|
| + uprv_free(newLimits);
|
| + return;
|
| + }
|
| + UnicodeString *newFormats = new UnicodeString[count];
|
| + /* test for NULL */
|
| + if (newFormats == 0) {
|
| + status = U_MEMORY_ALLOCATION_ERROR;
|
| + uprv_free(newLimits);
|
| + uprv_free(newClosures);
|
| + return;
|
| + }
|
| +
|
| + // Perform the second pass
|
| + int32_t k = 0; // index into newXxx[] arrays
|
| + UnicodeString buf; // scratch buffer
|
| + UBool inQuote = FALSE;
|
| + UBool inNumber = TRUE; // TRUE before < or #, FALSE after
|
| +
|
| + for (i=0; i<pattern.length(); ++i) {
|
| + UChar c = pattern[i];
|
| + if (c == SINGLE_QUOTE) {
|
| + // Check for SINGLE_QUOTE pair indicating a literal quote
|
| + if ((i+1) < pattern.length() &&
|
| + pattern[i+1] == SINGLE_QUOTE) {
|
| + buf += SINGLE_QUOTE;
|
| + ++i;
|
| + } else {
|
| + inQuote = !inQuote;
|
| + }
|
| + } else if (inQuote) {
|
| + buf += c;
|
| + } else if (c == LESS_THAN || c == LESS_EQUAL || c == LESS_EQUAL2) {
|
| + if (!inNumber || buf.length() == 0) {
|
| + goto error;
|
| + }
|
| + inNumber = FALSE;
|
| +
|
| + double limit;
|
| + buf.trim();
|
| + if (!buf.compare(gPositiveInfinity, POSITIVE_INF_STRLEN)) {
|
| + limit = uprv_getInfinity();
|
| + } else if (!buf.compare(gNegativeInfinity, NEGATIVE_INF_STRLEN)) {
|
| + limit = -uprv_getInfinity();
|
| + } else {
|
| + limit = stod(buf);
|
| + }
|
| +
|
| + if (k == count) {
|
| + // This shouldn't happen. If it does, it means that
|
| + // the count determined in the first pass did not
|
| + // match the number of elements found in the second
|
| + // pass.
|
| + goto error;
|
| + }
|
| + newLimits[k] = limit;
|
| + newClosures[k] = (c == LESS_THAN);
|
| +
|
| + if (k > 0 && limit <= newLimits[k-1]) {
|
| + // Each limit must be strictly > than the previous
|
| + // limit. One exception: Two subsequent limits may be
|
| + // == if the first closure is FALSE and the second
|
| + // closure is TRUE. This places the limit value in
|
| + // the second interval.
|
| + if (!(limit == newLimits[k-1] &&
|
| + !newClosures[k-1] &&
|
| + newClosures[k])) {
|
| + goto error;
|
| + }
|
| + }
|
| +
|
| + buf.truncate(0);
|
| + } else if (c == VERTICAL_BAR) {
|
| + if (inNumber) {
|
| + goto error;
|
| + }
|
| + inNumber = TRUE;
|
| +
|
| + newFormats[k] = buf;
|
| + ++k;
|
| + buf.truncate(0);
|
| + } else {
|
| + buf += c;
|
| + }
|
| + }
|
| +
|
| + if (k != (count-1) || inNumber || inQuote) {
|
| + goto error;
|
| + }
|
| + newFormats[k] = buf;
|
| +
|
| + // Don't modify this object until the parse succeeds
|
| + uprv_free(fChoiceLimits);
|
| + uprv_free(fClosures);
|
| + delete[] fChoiceFormats;
|
| + fCount = count;
|
| + fChoiceLimits = newLimits;
|
| + fClosures = newClosures;
|
| + fChoiceFormats = newFormats;
|
| + return;
|
| +
|
| +error:
|
| + status = U_ILLEGAL_ARGUMENT_ERROR;
|
| + syntaxError(pattern,i,parseError);
|
| + uprv_free(newLimits);
|
| + uprv_free(newClosures);
|
| + delete[] newFormats;
|
| + return;
|
| +
|
| +}
|
| +// -------------------------------------
|
| +// Reconstruct the original input pattern.
|
| +
|
| +UnicodeString&
|
| +ChoiceFormat::toPattern(UnicodeString& result) const
|
| +{
|
| + result.remove();
|
| + for (int32_t i = 0; i < fCount; ++i) {
|
| + if (i != 0) {
|
| + result += VERTICAL_BAR;
|
| + }
|
| + UnicodeString buf;
|
| + if (uprv_isPositiveInfinity(fChoiceLimits[i])) {
|
| + result += INFINITY;
|
| + } else if (uprv_isNegativeInfinity(fChoiceLimits[i])) {
|
| + result += MINUS;
|
| + result += INFINITY;
|
| + } else {
|
| + result += dtos(fChoiceLimits[i], buf);
|
| + }
|
| + if (fClosures[i]) {
|
| + result += LESS_THAN;
|
| + } else {
|
| + result += LESS_EQUAL;
|
| + }
|
| + // Append fChoiceFormats[i], using quotes if there are special
|
| + // characters. Single quotes themselves must be escaped in
|
| + // either case.
|
| + const UnicodeString& text = fChoiceFormats[i];
|
| + UBool needQuote = text.indexOf(LESS_THAN) >= 0
|
| + || text.indexOf(LESS_EQUAL) >= 0
|
| + || text.indexOf(LESS_EQUAL2) >= 0
|
| + || text.indexOf(VERTICAL_BAR) >= 0;
|
| + if (needQuote) {
|
| + result += SINGLE_QUOTE;
|
| + }
|
| + if (text.indexOf(SINGLE_QUOTE) < 0) {
|
| + result += text;
|
| + }
|
| + else {
|
| + for (int32_t j = 0; j < text.length(); ++j) {
|
| + UChar c = text[j];
|
| + result += c;
|
| + if (c == SINGLE_QUOTE) {
|
| + result += c;
|
| + }
|
| + }
|
| + }
|
| + if (needQuote) {
|
| + result += SINGLE_QUOTE;
|
| + }
|
| + }
|
| +
|
| + return result;
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Sets the limit and format arrays.
|
| +void
|
| +ChoiceFormat::setChoices( const double* limits,
|
| + const UnicodeString* formats,
|
| + int32_t cnt )
|
| +{
|
| + setChoices(limits, 0, formats, cnt);
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Sets the limit and format arrays.
|
| +void
|
| +ChoiceFormat::setChoices( const double* limits,
|
| + const UBool* closures,
|
| + const UnicodeString* formats,
|
| + int32_t cnt )
|
| +{
|
| + if(limits == 0 || formats == 0)
|
| + return;
|
| +
|
| + if (fChoiceLimits) {
|
| + uprv_free(fChoiceLimits);
|
| + }
|
| + if (fClosures) {
|
| + uprv_free(fClosures);
|
| + }
|
| + if (fChoiceFormats) {
|
| + delete [] fChoiceFormats;
|
| + }
|
| +
|
| + // Note that the old arrays are deleted and this owns
|
| + // the created array.
|
| + fCount = cnt;
|
| + fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount);
|
| + fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount);
|
| + fChoiceFormats = new UnicodeString[fCount];
|
| +
|
| + //check for memory allocation error
|
| + if (!fChoiceLimits || !fClosures || !fChoiceFormats) {
|
| + if (fChoiceLimits) {
|
| + uprv_free(fChoiceLimits);
|
| + fChoiceLimits = NULL;
|
| + }
|
| + if (fClosures) {
|
| + uprv_free(fClosures);
|
| + fClosures = NULL;
|
| + }
|
| + if (fChoiceFormats) {
|
| + delete[] fChoiceFormats;
|
| + fChoiceFormats = NULL;
|
| + }
|
| + return;
|
| + }
|
| +
|
| + uprv_arrayCopy(limits, fChoiceLimits, fCount);
|
| + uprv_arrayCopy(formats, fChoiceFormats, fCount);
|
| +
|
| + if (closures != 0) {
|
| + uprv_arrayCopy(closures, fClosures, fCount);
|
| + } else {
|
| + int32_t i;
|
| + for (i=0; i<fCount; ++i) {
|
| + fClosures[i] = FALSE;
|
| + }
|
| + }
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Gets the limit array.
|
| +
|
| +const double*
|
| +ChoiceFormat::getLimits(int32_t& cnt) const
|
| +{
|
| + cnt = fCount;
|
| + return fChoiceLimits;
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Gets the closures array.
|
| +
|
| +const UBool*
|
| +ChoiceFormat::getClosures(int32_t& cnt) const
|
| +{
|
| + cnt = fCount;
|
| + return fClosures;
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Gets the format array.
|
| +
|
| +const UnicodeString*
|
| +ChoiceFormat::getFormats(int32_t& cnt) const
|
| +{
|
| + cnt = fCount;
|
| + return fChoiceFormats;
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Formats an int64 number, it's actually formatted as
|
| +// a double. The returned format string may differ
|
| +// from the input number because of this.
|
| +
|
| +UnicodeString&
|
| +ChoiceFormat::format(int64_t number,
|
| + UnicodeString& appendTo,
|
| + FieldPosition& status) const
|
| +{
|
| + return format((double) number, appendTo, status);
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Formats a long number, it's actually formatted as
|
| +// a double. The returned format string may differ
|
| +// from the input number because of this.
|
| +
|
| +UnicodeString&
|
| +ChoiceFormat::format(int32_t number,
|
| + UnicodeString& appendTo,
|
| + FieldPosition& status) const
|
| +{
|
| + return format((double) number, appendTo, status);
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Formats a double number.
|
| +
|
| +UnicodeString&
|
| +ChoiceFormat::format(double number,
|
| + UnicodeString& appendTo,
|
| + FieldPosition& /*pos*/) const
|
| +{
|
| + // find the number
|
| + int32_t i;
|
| + for (i = 0; i < fCount; ++i) {
|
| + if (fClosures[i]) {
|
| + if (!(number > fChoiceLimits[i])) {
|
| + // same as number <= fChoiceLimits, except catches NaN
|
| + break;
|
| + }
|
| + } else if (!(number >= fChoiceLimits[i])) {
|
| + // same as number < fChoiceLimits, except catches NaN
|
| + break;
|
| + }
|
| + }
|
| + --i;
|
| + if (i < 0) {
|
| + i = 0;
|
| + }
|
| + // return either a formatted number, or a string
|
| + appendTo += fChoiceFormats[i];
|
| + return appendTo;
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Formats an array of objects. Checks if the data type of the objects
|
| +// to get the right value for formatting.
|
| +
|
| +UnicodeString&
|
| +ChoiceFormat::format(const Formattable* objs,
|
| + int32_t cnt,
|
| + UnicodeString& appendTo,
|
| + FieldPosition& pos,
|
| + UErrorCode& status) const
|
| +{
|
| + if(cnt < 0) {
|
| + status = U_ILLEGAL_ARGUMENT_ERROR;
|
| + return appendTo;
|
| + }
|
| +
|
| + UnicodeString buffer;
|
| + for (int32_t i = 0; i < cnt; i++) {
|
| + double objDouble = objs[i].getDouble(status);
|
| + if (U_SUCCESS(status)) {
|
| + buffer.remove();
|
| + appendTo += format(objDouble, buffer, pos);
|
| + }
|
| + }
|
| +
|
| + return appendTo;
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Formats an array of objects. Checks if the data type of the objects
|
| +// to get the right value for formatting.
|
| +
|
| +UnicodeString&
|
| +ChoiceFormat::format(const Formattable& obj,
|
| + UnicodeString& appendTo,
|
| + FieldPosition& pos,
|
| + UErrorCode& status) const
|
| +{
|
| + return NumberFormat::format(obj, appendTo, pos, status);
|
| +}
|
| +// -------------------------------------
|
| +
|
| +void
|
| +ChoiceFormat::parse(const UnicodeString& text,
|
| + Formattable& result,
|
| + ParsePosition& status) const
|
| +{
|
| + // find the best number (defined as the one with the longest parse)
|
| + int32_t start = status.getIndex();
|
| + int32_t furthest = start;
|
| + double bestNumber = uprv_getNaN();
|
| + double tempNumber = 0.0;
|
| + for (int i = 0; i < fCount; ++i) {
|
| + int32_t len = fChoiceFormats[i].length();
|
| + if (text.compare(start, len, fChoiceFormats[i]) == 0) {
|
| + status.setIndex(start + len);
|
| + tempNumber = fChoiceLimits[i];
|
| + if (status.getIndex() > furthest) {
|
| + furthest = status.getIndex();
|
| + bestNumber = tempNumber;
|
| + if (furthest == text.length())
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + status.setIndex(furthest);
|
| + if (status.getIndex() == start) {
|
| + status.setErrorIndex(furthest);
|
| + }
|
| + result.setDouble(bestNumber);
|
| +}
|
| +
|
| +// -------------------------------------
|
| +// Parses the text and return the Formattable object.
|
| +
|
| +void
|
| +ChoiceFormat::parse(const UnicodeString& text,
|
| + Formattable& result,
|
| + UErrorCode& status) const
|
| +{
|
| + NumberFormat::parse(text, result, status);
|
| +}
|
| +
|
| +// -------------------------------------
|
| +
|
| +Format*
|
| +ChoiceFormat::clone() const
|
| +{
|
| + ChoiceFormat *aCopy = new ChoiceFormat(*this);
|
| + return aCopy;
|
| +}
|
| +
|
| +U_NAMESPACE_END
|
| +
|
| +#endif /* #if !UCONFIG_NO_FORMATTING */
|
| +
|
| +//eof
|
|
|
| Property changes on: icu46/source/i18n/choicfmt.cpp
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|