1999-08-16 21:50:52 +00:00
|
|
|
/*
|
1999-11-22 20:25:35 +00:00
|
|
|
*******************************************************************************
|
2001-03-21 20:31:13 +00:00
|
|
|
* Copyright (C) 1997-2001, International Business Machines Corporation and *
|
1999-11-22 20:25:35 +00:00
|
|
|
* others. All Rights Reserved. *
|
|
|
|
*******************************************************************************
|
1999-08-16 21:50:52 +00:00
|
|
|
*
|
|
|
|
* 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)'
|
2001-03-06 19:44:45 +00:00
|
|
|
* 07/22/98 stephen JDK 1.2 Sync - removed UBool array (doubleFlags)
|
1999-08-16 21:50:52 +00:00
|
|
|
* 02/22/99 stephen Removed character literals for EBCDIC safety
|
|
|
|
********************************************************************************
|
|
|
|
*/
|
|
|
|
|
1999-10-12 00:19:25 +00:00
|
|
|
#include "cpputils.h"
|
1999-12-28 23:57:50 +00:00
|
|
|
#include "unicode/choicfmt.h"
|
|
|
|
#include "unicode/numfmt.h"
|
|
|
|
#include "unicode/locid.h"
|
2001-03-06 19:44:45 +00:00
|
|
|
#include "mutex.h"
|
1999-08-16 21:50:52 +00:00
|
|
|
|
|
|
|
// *****************************************************************************
|
|
|
|
// class ChoiceFormat
|
|
|
|
// *****************************************************************************
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
char ChoiceFormat::fgClassID = 0; // Value is irrelevant
|
|
|
|
|
2001-06-11 17:21:28 +00:00
|
|
|
UMTX ChoiceFormat::fgMutex = NULL; // lock for fgNumberFormat
|
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
NumberFormat* ChoiceFormat::fgNumberFormat = 0;
|
|
|
|
|
2001-06-11 17:21:28 +00:00
|
|
|
inline double _getDouble(const Formattable& f) {
|
|
|
|
return (f.getType() == Formattable::kLong) ?
|
|
|
|
((double) f.getLong()) : f.getDouble();
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) /*#*/
|
2001-06-21 20:46:12 +00:00
|
|
|
#define LESS_EQUAL2 ((UChar)0x2264)
|
2001-06-11 17:21:28 +00:00
|
|
|
#define VERTICAL_BAR ((UChar)0x007C) /*|*/
|
|
|
|
#define MINUS ((UChar)0x002D) /*-*/
|
2001-06-21 20:46:12 +00:00
|
|
|
#define INFINITY ((UChar)0x221E)
|
2001-06-11 17:21:28 +00:00
|
|
|
|
2001-06-21 20:46:12 +00:00
|
|
|
const UChar ChoiceFormat::fgPositiveInfinity[] = {INFINITY, 0};
|
|
|
|
const UChar ChoiceFormat::fgNegativeInfinity[] = {MINUS, INFINITY, 0};
|
2001-06-21 20:58:03 +00:00
|
|
|
#define POSITIVE_INF_STRLEN 1
|
|
|
|
#define NEGATIVE_INF_STRLEN 2
|
2001-06-11 17:21:28 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// Creates a ChoiceFormat instance based on the pattern.
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
|
|
|
|
UErrorCode& status)
|
|
|
|
: fChoiceLimits(0),
|
2001-06-11 17:21:28 +00:00
|
|
|
fClosures(0),
|
1999-08-16 21:50:52 +00:00
|
|
|
fChoiceFormats(0),
|
|
|
|
fCount(0)
|
|
|
|
{
|
|
|
|
applyPattern(newPattern, status);
|
|
|
|
}
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// 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),
|
2001-06-11 17:21:28 +00:00
|
|
|
fClosures(0),
|
1999-08-16 21:50:52 +00:00
|
|
|
fChoiceFormats(0),
|
|
|
|
fCount(0)
|
|
|
|
{
|
|
|
|
setChoices(limits, formats, cnt );
|
|
|
|
}
|
|
|
|
|
2001-06-11 17:21:28 +00:00
|
|
|
// -------------------------------------
|
|
|
|
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// copy constructor
|
|
|
|
|
|
|
|
ChoiceFormat::ChoiceFormat(const ChoiceFormat& that)
|
|
|
|
: fChoiceLimits(0),
|
2001-06-11 17:21:28 +00:00
|
|
|
fClosures(0),
|
1999-08-16 21:50:52 +00:00
|
|
|
fChoiceFormats(0)
|
|
|
|
{
|
|
|
|
*this = that;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
|
|
|
2000-05-18 22:08:39 +00:00
|
|
|
UBool
|
1999-08-16 21:50:52 +00:00
|
|
|
ChoiceFormat::operator==(const Format& that) const
|
|
|
|
{
|
|
|
|
if (this == &that) return TRUE;
|
|
|
|
if (this->getDynamicClassID() != that.getDynamicClassID()) return FALSE; // not the same class
|
|
|
|
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]) ||
|
2001-06-11 17:21:28 +00:00
|
|
|
(fClosures[i] != thatAlias.fClosures[i]) ||
|
1999-08-16 21:50:52 +00:00
|
|
|
(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;
|
|
|
|
delete [] fChoiceLimits; fChoiceLimits = 0;
|
2001-06-11 17:21:28 +00:00
|
|
|
delete [] fClosures; fClosures = 0;
|
1999-08-16 21:50:52 +00:00
|
|
|
delete [] fChoiceFormats; fChoiceFormats = 0;
|
|
|
|
fChoiceLimits = new double[fCount];
|
2001-06-11 17:21:28 +00:00
|
|
|
fClosures = new UBool[fCount];
|
1999-08-16 21:50:52 +00:00
|
|
|
fChoiceFormats = new UnicodeString[fCount];
|
|
|
|
|
1999-12-28 23:57:50 +00:00
|
|
|
uprv_arrayCopy(that.fChoiceLimits, fChoiceLimits, fCount);
|
2001-06-11 17:21:28 +00:00
|
|
|
uprv_arrayCopy(that.fClosures, fClosures, fCount);
|
1999-12-28 23:57:50 +00:00
|
|
|
uprv_arrayCopy(that.fChoiceFormats, fChoiceFormats, fCount);
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
|
|
|
|
|
|
ChoiceFormat::~ChoiceFormat()
|
|
|
|
{
|
|
|
|
delete [] fChoiceLimits;
|
|
|
|
fChoiceLimits = 0;
|
2001-06-11 17:21:28 +00:00
|
|
|
delete [] fClosures;
|
|
|
|
fClosures = 0;
|
1999-08-16 21:50:52 +00:00
|
|
|
delete [] fChoiceFormats;
|
|
|
|
fChoiceFormats = 0;
|
|
|
|
fCount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
|
|
// NumberFormat cache management
|
|
|
|
|
|
|
|
NumberFormat*
|
|
|
|
ChoiceFormat::getNumberFormat(UErrorCode &status)
|
|
|
|
{
|
|
|
|
NumberFormat *theFormat = 0;
|
|
|
|
|
|
|
|
if (fgNumberFormat != 0) // if there's something in the cache
|
|
|
|
{
|
2001-06-11 17:21:28 +00:00
|
|
|
Mutex lock(&fgMutex);
|
1999-08-16 21:50:52 +00:00
|
|
|
|
|
|
|
if (fgNumberFormat != 0) // Someone might have grabbed it.
|
|
|
|
{
|
|
|
|
theFormat = fgNumberFormat;
|
|
|
|
fgNumberFormat = 0; // We have exclusive right to this formatter.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(theFormat == 0) // If we weren't able to pull it out of the cache, then we have to create it.
|
|
|
|
{
|
|
|
|
theFormat = NumberFormat::createInstance(Locale::US, status);
|
1999-10-18 22:48:32 +00:00
|
|
|
if(U_FAILURE(status))
|
1999-08-16 21:50:52 +00:00
|
|
|
return 0;
|
|
|
|
theFormat->setMinimumFractionDigits(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return theFormat;
|
|
|
|
}
|
|
|
|
|
2001-03-06 19:44:45 +00:00
|
|
|
void
|
1999-08-16 21:50:52 +00:00
|
|
|
ChoiceFormat::releaseNumberFormat(NumberFormat *adopt)
|
|
|
|
{
|
|
|
|
if(fgNumberFormat == 0) // If the cache is empty we must add it back.
|
|
|
|
{
|
2001-06-11 17:21:28 +00:00
|
|
|
Mutex lock(&fgMutex);
|
1999-08-16 21:50:52 +00:00
|
|
|
|
|
|
|
if(fgNumberFormat == 0)
|
|
|
|
{
|
|
|
|
fgNumberFormat = adopt;
|
|
|
|
adopt = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete adopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert a string to a double value using a default NumberFormat object
|
|
|
|
* which is static (shared by all ChoiceFormat instances).
|
|
|
|
*/
|
|
|
|
double
|
|
|
|
ChoiceFormat::stod(const UnicodeString& string,
|
|
|
|
UErrorCode& status)
|
|
|
|
{
|
|
|
|
// Use a shared global number format to convert a double value to
|
|
|
|
// or string or vice versa.
|
|
|
|
NumberFormat *myFormat = getNumberFormat(status);
|
|
|
|
|
1999-10-18 22:48:32 +00:00
|
|
|
if(U_FAILURE(status))
|
1999-08-16 21:50:52 +00:00
|
|
|
return -1; // OK?
|
|
|
|
|
|
|
|
Formattable result;
|
|
|
|
myFormat->parse(string, result, status);
|
|
|
|
releaseNumberFormat(myFormat);
|
|
|
|
double value = 0.0;
|
2001-06-11 17:21:28 +00:00
|
|
|
if (U_SUCCESS(status)) {
|
|
|
|
value = _getDouble(result);
|
|
|
|
if (uprv_isNaN(value)) {
|
|
|
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert a double value to a string using a default NumberFormat object
|
|
|
|
* which is static (shared by all ChoiceFormat instances).
|
|
|
|
*/
|
|
|
|
UnicodeString&
|
|
|
|
ChoiceFormat::dtos(double value,
|
|
|
|
UnicodeString& string,
|
|
|
|
UErrorCode& status)
|
|
|
|
{
|
|
|
|
NumberFormat *myFormat = getNumberFormat(status);
|
|
|
|
|
1999-10-18 22:48:32 +00:00
|
|
|
if (U_SUCCESS(status)) {
|
1999-08-16 21:50:52 +00:00
|
|
|
FieldPosition fieldPos(0);
|
|
|
|
myFormat->format(value, string, fieldPos);
|
|
|
|
}
|
|
|
|
releaseNumberFormat(myFormat);
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
|
|
// Applies the pattern to this ChoiceFormat instance.
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
void
|
2001-06-11 17:21:28 +00:00
|
|
|
ChoiceFormat::applyPattern(const UnicodeString& pattern,
|
1999-08-16 21:50:52 +00:00
|
|
|
UErrorCode& status)
|
|
|
|
{
|
2001-06-11 17:21:28 +00:00
|
|
|
if (U_FAILURE(status)) {
|
1999-08-16 21:50:52 +00:00
|
|
|
return;
|
2001-06-11 17:21:28 +00:00
|
|
|
}
|
1999-08-16 21:50:52 +00:00
|
|
|
|
2001-06-11 17:21:28 +00:00
|
|
|
// 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;
|
|
|
|
}
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
2001-06-11 17:21:28 +00:00
|
|
|
} else if (c == VERTICAL_BAR) {
|
|
|
|
++count;
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
2001-06-11 17:21:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate the required storage.
|
|
|
|
double *newLimits = new double[count];
|
|
|
|
UBool *newClosures = new UBool[count];
|
|
|
|
UnicodeString *newFormats = new UnicodeString[count];
|
1999-08-16 21:50:52 +00:00
|
|
|
|
2001-06-11 17:21:28 +00:00
|
|
|
// 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;
|
2001-03-06 19:44:45 +00:00
|
|
|
}
|
2001-06-11 17:21:28 +00:00
|
|
|
} else if (inQuote) {
|
|
|
|
buf += c;
|
|
|
|
} else if (c == LESS_THAN || c == LESS_EQUAL || c == LESS_EQUAL2) {
|
|
|
|
if (!inNumber || buf.length() == 0) {
|
|
|
|
goto error;
|
2001-03-06 19:44:45 +00:00
|
|
|
}
|
2001-06-11 17:21:28 +00:00
|
|
|
inNumber = FALSE;
|
|
|
|
|
|
|
|
double limit;
|
|
|
|
buf.trim();
|
2001-06-21 20:58:03 +00:00
|
|
|
if (!buf.compare(fgPositiveInfinity, POSITIVE_INF_STRLEN)) {
|
2001-06-11 17:21:28 +00:00
|
|
|
limit = uprv_getInfinity();
|
2001-06-21 20:58:03 +00:00
|
|
|
} else if (!buf.compare(fgNegativeInfinity, NEGATIVE_INF_STRLEN)) {
|
2001-06-11 17:21:28 +00:00
|
|
|
limit = -uprv_getInfinity();
|
|
|
|
} else {
|
|
|
|
limit = stod(buf, status);
|
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
goto error;
|
|
|
|
}
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
|
|
|
|
2001-06-11 17:21:28 +00:00
|
|
|
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.
|
2001-06-21 20:46:12 +00:00
|
|
|
goto error;
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
2001-06-11 17:21:28 +00:00
|
|
|
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;
|
|
|
|
}
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
2001-06-11 17:21:28 +00:00
|
|
|
|
|
|
|
buf.truncate(0);
|
|
|
|
} else if (c == VERTICAL_BAR) {
|
|
|
|
if (inNumber) {
|
2001-06-21 20:46:12 +00:00
|
|
|
goto error;
|
2001-06-11 17:21:28 +00:00
|
|
|
}
|
|
|
|
inNumber = TRUE;
|
|
|
|
|
|
|
|
newFormats[k] = buf;
|
|
|
|
++k;
|
|
|
|
buf.truncate(0);
|
1999-08-16 21:50:52 +00:00
|
|
|
} else {
|
2001-06-11 17:21:28 +00:00
|
|
|
buf += c;
|
|
|
|
}
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
|
|
|
|
2001-06-11 17:21:28 +00:00
|
|
|
if (k != (count-1) || inNumber || inQuote) {
|
2001-06-21 20:46:12 +00:00
|
|
|
goto error;
|
2001-06-11 17:21:28 +00:00
|
|
|
}
|
|
|
|
newFormats[k] = buf;
|
1999-08-16 21:50:52 +00:00
|
|
|
|
2001-06-11 17:21:28 +00:00
|
|
|
// Don't modify this object until the parse succeeds
|
|
|
|
delete[] fChoiceLimits;
|
|
|
|
delete[] fClosures;
|
|
|
|
delete[] fChoiceFormats;
|
1999-08-16 21:50:52 +00:00
|
|
|
fCount = count;
|
2001-06-11 17:21:28 +00:00
|
|
|
fChoiceLimits = newLimits;
|
|
|
|
fClosures = newClosures;
|
|
|
|
fChoiceFormats = newFormats;
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
|
|
|
delete[] newLimits;
|
|
|
|
delete[] newClosures;
|
|
|
|
delete[] newFormats;
|
|
|
|
return;
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// Reconstruct the original input pattern.
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
UnicodeString&
|
|
|
|
ChoiceFormat::toPattern(UnicodeString& result) const
|
|
|
|
{
|
|
|
|
result.remove();
|
|
|
|
for (int32_t i = 0; i < fCount; ++i) {
|
|
|
|
if (i != 0) {
|
2001-06-11 17:21:28 +00:00
|
|
|
result += VERTICAL_BAR;
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
1999-10-07 00:07:53 +00:00
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
1999-08-16 21:50:52 +00:00
|
|
|
UnicodeString buf;
|
2001-06-11 17:21:28 +00:00
|
|
|
if (uprv_isPositiveInfinity(fChoiceLimits[i])) {
|
|
|
|
result += INFINITY;
|
|
|
|
} else if (uprv_isNegativeInfinity(fChoiceLimits[i])) {
|
|
|
|
result += MINUS;
|
|
|
|
result += INFINITY;
|
|
|
|
} else {
|
1999-08-16 21:50:52 +00:00
|
|
|
result += dtos(fChoiceLimits[i], buf, status);
|
2001-03-06 19:44:45 +00:00
|
|
|
}
|
2001-06-14 23:23:04 +00:00
|
|
|
if (fClosures[i]) {
|
|
|
|
result += LESS_THAN;
|
|
|
|
} else {
|
|
|
|
result += LESS_EQUAL;
|
|
|
|
}
|
2001-06-11 17:21:28 +00:00
|
|
|
// 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;
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
2001-06-11 17:21:28 +00:00
|
|
|
if (text.indexOf(SINGLE_QUOTE) < 0) {
|
1999-08-16 21:50:52 +00:00
|
|
|
result += text;
|
2001-06-11 17:21:28 +00:00
|
|
|
}
|
1999-08-16 21:50:52 +00:00
|
|
|
else {
|
2001-06-11 17:21:28 +00:00
|
|
|
for (int32_t j = 0; j < text.length(); ++j) {
|
1999-08-16 21:50:52 +00:00
|
|
|
UChar c = text[j];
|
|
|
|
result += c;
|
2001-06-11 17:21:28 +00:00
|
|
|
if (c == SINGLE_QUOTE) {
|
1999-08-16 21:50:52 +00:00
|
|
|
result += c;
|
2001-06-11 17:21:28 +00:00
|
|
|
}
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
|
|
|
}
|
2001-06-11 17:21:28 +00:00
|
|
|
if (needQuote) {
|
|
|
|
result += SINGLE_QUOTE;
|
|
|
|
}
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
return result;
|
|
|
|
}
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// Adopts the limit and format arrays.
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
void
|
|
|
|
ChoiceFormat::adoptChoices(double *limits,
|
|
|
|
UnicodeString *formats,
|
|
|
|
int32_t cnt )
|
2001-06-11 17:21:28 +00:00
|
|
|
{
|
|
|
|
adoptChoices(limits, 0, formats, cnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
|
|
// Adopts the limit and format arrays.
|
|
|
|
|
|
|
|
void
|
|
|
|
ChoiceFormat::adoptChoices(double *limits,
|
|
|
|
UBool *closures,
|
|
|
|
UnicodeString *formats,
|
|
|
|
int32_t cnt )
|
1999-08-16 21:50:52 +00:00
|
|
|
{
|
|
|
|
if(limits == 0 || formats == 0)
|
|
|
|
return;
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
delete [] fChoiceLimits;
|
2001-06-11 17:21:28 +00:00
|
|
|
delete [] fClosures;
|
1999-08-16 21:50:52 +00:00
|
|
|
delete [] fChoiceFormats;
|
|
|
|
fChoiceLimits = limits;
|
2001-06-11 17:21:28 +00:00
|
|
|
fClosures = closures;
|
1999-08-16 21:50:52 +00:00
|
|
|
fChoiceFormats = formats;
|
|
|
|
fCount = cnt;
|
2001-06-11 17:21:28 +00:00
|
|
|
|
|
|
|
if (fClosures == 0) {
|
|
|
|
fClosures = new UBool[fCount];
|
|
|
|
int32_t i;
|
|
|
|
for (i=0; i<fCount; ++i) {
|
|
|
|
fClosures[i] = FALSE;
|
|
|
|
}
|
|
|
|
}
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// Sets the limit and format arrays.
|
|
|
|
void
|
|
|
|
ChoiceFormat::setChoices( const double* limits,
|
|
|
|
const UnicodeString* formats,
|
|
|
|
int32_t cnt )
|
2001-06-11 17:21:28 +00:00
|
|
|
{
|
|
|
|
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 )
|
1999-08-16 21:50:52 +00:00
|
|
|
{
|
|
|
|
if(limits == 0 || formats == 0)
|
|
|
|
return;
|
|
|
|
|
2001-06-11 17:21:28 +00:00
|
|
|
delete [] fChoiceLimits;
|
|
|
|
delete [] fClosures;
|
|
|
|
delete [] fChoiceFormats;
|
1999-08-16 21:50:52 +00:00
|
|
|
|
|
|
|
// Note that the old arrays are deleted and this owns
|
|
|
|
// the created array.
|
|
|
|
fCount = cnt;
|
|
|
|
fChoiceLimits = new double[fCount];
|
2001-06-11 17:21:28 +00:00
|
|
|
fClosures = new UBool[fCount];
|
1999-08-16 21:50:52 +00:00
|
|
|
fChoiceFormats = new UnicodeString[fCount];
|
|
|
|
|
1999-12-28 23:57:50 +00:00
|
|
|
uprv_arrayCopy(limits, fChoiceLimits, fCount);
|
|
|
|
uprv_arrayCopy(formats, fChoiceFormats, fCount);
|
2001-06-11 17:21:28 +00:00
|
|
|
|
|
|
|
if (closures != 0) {
|
|
|
|
uprv_arrayCopy(closures, fClosures, fCount);
|
|
|
|
} else {
|
|
|
|
int32_t i;
|
|
|
|
for (i=0; i<fCount; ++i) {
|
|
|
|
fClosures[i] = FALSE;
|
|
|
|
}
|
|
|
|
}
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// Gets the limit array.
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
const double*
|
|
|
|
ChoiceFormat::getLimits(int32_t& cnt) const
|
|
|
|
{
|
|
|
|
cnt = fCount;
|
|
|
|
return fChoiceLimits;
|
|
|
|
}
|
2001-03-06 19:44:45 +00:00
|
|
|
|
2001-06-11 17:21:28 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// Gets the closures array.
|
|
|
|
|
|
|
|
const UBool*
|
|
|
|
ChoiceFormat::getClosures(int32_t& cnt) const
|
|
|
|
{
|
|
|
|
cnt = fCount;
|
|
|
|
return fClosures;
|
|
|
|
}
|
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// Gets the format array.
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
const UnicodeString*
|
|
|
|
ChoiceFormat::getFormats(int32_t& cnt) const
|
|
|
|
{
|
|
|
|
cnt = fCount;
|
|
|
|
return fChoiceFormats;
|
|
|
|
}
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// Formats a long number, it's actually formatted as
|
|
|
|
// a double. The returned format string may differ
|
|
|
|
// from the input number because of this.
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
UnicodeString&
|
|
|
|
ChoiceFormat::format(int32_t number,
|
|
|
|
UnicodeString& toAppendTo,
|
|
|
|
FieldPosition& status) const
|
|
|
|
{
|
|
|
|
return format((double) number, toAppendTo, status);
|
|
|
|
}
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// Formats a double number.
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
UnicodeString&
|
|
|
|
ChoiceFormat::format(double number,
|
|
|
|
UnicodeString& toAppendTo,
|
2000-08-15 18:25:20 +00:00
|
|
|
FieldPosition& /*pos*/) const
|
1999-08-16 21:50:52 +00:00
|
|
|
{
|
|
|
|
// find the number
|
|
|
|
int32_t i;
|
|
|
|
for (i = 0; i < fCount; ++i) {
|
2001-06-11 17:21:28 +00:00
|
|
|
if (fClosures[i]) {
|
|
|
|
if (!(number > fChoiceLimits[i])) {
|
|
|
|
// same as number <= fChoiceLimits, except catches NaN
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (!(number >= fChoiceLimits[i])) {
|
1999-08-16 21:50:52 +00:00
|
|
|
// same as number < fChoiceLimits, except catches NaN
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
--i;
|
2001-06-11 17:21:28 +00:00
|
|
|
if (i < 0) {
|
1999-08-16 21:50:52 +00:00
|
|
|
i = 0;
|
2001-06-11 17:21:28 +00:00
|
|
|
}
|
1999-08-16 21:50:52 +00:00
|
|
|
// return either a formatted number, or a string
|
2001-06-11 17:21:28 +00:00
|
|
|
toAppendTo += fChoiceFormats[i];
|
|
|
|
return toAppendTo;
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
// -------------------------------------
|
|
|
|
// 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& toAppendTo,
|
|
|
|
FieldPosition& pos,
|
|
|
|
UErrorCode& status) const
|
|
|
|
{
|
|
|
|
if(cnt < 0) {
|
1999-10-07 00:07:53 +00:00
|
|
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
1999-08-16 21:50:52 +00:00
|
|
|
return toAppendTo;
|
|
|
|
}
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
UnicodeString buffer;
|
|
|
|
for (int32_t i = 0; i < cnt; i++) {
|
|
|
|
buffer.remove();
|
2001-06-11 17:21:28 +00:00
|
|
|
toAppendTo += format(_getDouble(objs[i]), buffer, pos);
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return toAppendTo;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
|
|
// 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& toAppendTo,
|
|
|
|
FieldPosition& pos,
|
|
|
|
UErrorCode& status) const
|
|
|
|
{
|
2001-03-06 19:44:45 +00:00
|
|
|
return NumberFormat::format(obj, toAppendTo, pos, status);
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
|
|
|
// -------------------------------------
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
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;
|
1999-12-28 23:57:50 +00:00
|
|
|
double bestNumber = uprv_getNaN();
|
1999-08-16 21:50:52 +00:00
|
|
|
double tempNumber = 0.0;
|
|
|
|
for (int i = 0; i < fCount; ++i) {
|
|
|
|
UnicodeString tempString = fChoiceFormats[i];
|
1999-12-08 02:11:04 +00:00
|
|
|
if(text.compareBetween(start, tempString.length(), tempString, 0, tempString.length()) == 0) {
|
|
|
|
status.setIndex(start + tempString.length());
|
1999-08-16 21:50:52 +00:00
|
|
|
tempNumber = fChoiceLimits[i];
|
|
|
|
if (status.getIndex() > furthest) {
|
|
|
|
furthest = status.getIndex();
|
|
|
|
bestNumber = tempNumber;
|
1999-12-08 02:11:04 +00:00
|
|
|
if (furthest == text.length())
|
1999-08-16 21:50:52 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
status.setIndex(furthest);
|
|
|
|
if (status.getIndex() == start) {
|
|
|
|
status.setErrorIndex(furthest);
|
|
|
|
}
|
|
|
|
result.setDouble(bestNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
|
|
// Parses the text and return the Formattable object.
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
void
|
|
|
|
ChoiceFormat::parse(const UnicodeString& text,
|
|
|
|
Formattable& result,
|
|
|
|
UErrorCode& status) const
|
|
|
|
{
|
|
|
|
NumberFormat::parse(text, result, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
2001-03-06 19:44:45 +00:00
|
|
|
|
1999-08-16 21:50:52 +00:00
|
|
|
Format*
|
|
|
|
ChoiceFormat::clone() const
|
|
|
|
{
|
|
|
|
ChoiceFormat *aCopy = new ChoiceFormat(*this);
|
|
|
|
return aCopy;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
|
|
|
|
|
|
double
|
2000-05-18 22:08:39 +00:00
|
|
|
ChoiceFormat::nextDouble( double d, UBool positive )
|
1999-08-16 21:50:52 +00:00
|
|
|
{
|
1999-12-28 23:57:50 +00:00
|
|
|
return uprv_nextDouble( d, positive );
|
1999-08-16 21:50:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//eof
|