ICU-7952 ICU4C SelectFormat review feedback. Merge from branches/jinglun.

X-SVN-Rev: 28878
This commit is contained in:
Jinglun Li 2010-10-20 02:36:31 +00:00
parent ac89f9ed5b
commit a1f9c9d8f7
3 changed files with 231 additions and 233 deletions

View file

@ -1,5 +1,5 @@
/********************************************************************
* COPYRIGHT:
* COPYRIGHT:
* Copyright (c) 1997-2010, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************
@ -16,7 +16,7 @@
* 06/17/97 helena Fixed the getPattern to return the correct pattern.
* 07/09/97 helena Made ParsePosition into a class.
* 02/22/99 stephen Removed character literals for EBCDIC safety
* 11/01/09 kirtig Added SelectFormat
* 11/01/09 kirtig Added SelectFormat
********************************************************************/
#include "unicode/utypes.h"
@ -42,10 +42,6 @@
#include "ustrfmt.h"
#include "uvector.h"
//Todo:remove stdio
#include "stdio.h"
// *****************************************************************************
// class MessageFormat
// *****************************************************************************
@ -94,7 +90,7 @@ static const UChar ID_SELECT[] = {
static const UChar * const TYPE_IDS[] = {
ID_EMPTY,
ID_NUMBER,
ID_DATE,
ID_DATE,
ID_TIME,
ID_CHOICE,
ID_SPELLOUT,
@ -104,7 +100,7 @@ static const UChar * const TYPE_IDS[] = {
ID_SELECT,
NULL,
};
static const UChar ID_CURRENCY[] = {
0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0 /* "currency" */
};
@ -146,7 +142,7 @@ static const UChar * const DATE_STYLE_IDS[] = {
ID_FULL,
NULL,
};
static const U_NAMESPACE_QUALIFIER DateFormat::EStyle DATE_STYLES[] = {
U_NAMESPACE_QUALIFIER DateFormat::kDefault,
U_NAMESPACE_QUALIFIER DateFormat::kShort,
@ -209,23 +205,23 @@ static UnicodeString& itos(int32_t i, UnicodeString& appendTo) {
class MessageFormat::Subformat : public UMemory {
public:
/**
* @internal
* @internal
*/
Format* format; // formatter
/**
* @internal
* @internal
*/
int32_t offset; // offset into fPattern
/**
* @internal
* @internal
*/
// TODO (claireho) or save the number to argName and use itos to convert to number.=> we need this number
int32_t argNum; // 0-based argument number
/**
* @internal
* @internal
*/
UnicodeString* argName; // argument name or number
/**
* Clone that.format and assign it to this.format
* Do NOT delete this.format
@ -242,7 +238,7 @@ public:
}
/**
* @internal
* @internal
*/
UBool operator==(const Subformat& that) const {
// Do cheap comparisons first
@ -290,7 +286,7 @@ MessageFormat::MessageFormat(const UnicodeString& pattern,
applyPattern(pattern, success);
setLocaleIDs(fLocale.getName(), fLocale.getName());
}
MessageFormat::MessageFormat(const UnicodeString& pattern,
const Locale& newLocale,
UErrorCode& success)
@ -479,13 +475,13 @@ MessageFormat::operator=(const MessageFormat& that)
delete subformats[j].format;
}
subformatCount = 0;
for (j=0; j<that.subformatCount; ++j) {
// Subformat::operator= does NOT delete this.format
subformats[j] = that.subformats[j];
}
subformatCount = that.subformatCount;
for (j=0; j<that.argTypeCount; ++j) {
argTypes[j] = that.argTypes[j];
}
@ -495,10 +491,10 @@ MessageFormat::operator=(const MessageFormat& that)
}
UBool
MessageFormat::operator==(const Format& rhs) const
MessageFormat::operator==(const Format& rhs) const
{
if (this == &rhs) return TRUE;
MessageFormat& that = (MessageFormat&)rhs;
// Check class ID before checking MessageFormat members
@ -515,22 +511,22 @@ MessageFormat::operator==(const Format& rhs) const
return FALSE;
}
}
return TRUE;
}
// -------------------------------------
// Creates a copy of this MessageFormat, the caller owns the copy.
Format*
MessageFormat::clone() const
{
return new MessageFormat(*this);
}
// -------------------------------------
// Sets the locale of this MessageFormat object to theLocale.
void
MessageFormat::setLocale(const Locale& theLocale)
{
@ -543,10 +539,10 @@ MessageFormat::setLocale(const Locale& theLocale)
fLocale = theLocale;
setLocaleIDs(fLocale.getName(), fLocale.getName());
}
// -------------------------------------
// Gets the locale of this MessageFormat object.
const Locale&
MessageFormat::getLocale() const
{
@ -557,7 +553,7 @@ MessageFormat::getLocale() const
void
MessageFormat::applyPattern(const UnicodeString& newPattern,
MessageFormat::applyPattern(const UnicodeString& newPattern,
UErrorCode& status)
{
UParseError parseError;
@ -569,10 +565,10 @@ MessageFormat::applyPattern(const UnicodeString& newPattern,
// Applies the new pattern and returns an error if the pattern
// is not correct.
void
MessageFormat::applyPattern(const UnicodeString& pattern,
MessageFormat::applyPattern(const UnicodeString& pattern,
UParseError& parseError,
UErrorCode& ec)
{
{
if(U_FAILURE(ec)) {
return;
}
@ -611,7 +607,7 @@ MessageFormat::applyPattern(const UnicodeString& pattern,
parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
int32_t patLen = pattern.length();
int32_t i;
for (i=0; i<subformatCount; ++i) {
delete subformats[i].format;
}
@ -707,7 +703,7 @@ MessageFormat::applyPattern(const UnicodeString& pattern,
argTypeCount = subformatCount = 0;
}
// -------------------------------------
// Converts this MessageFormat instance to a pattern.
// Converts this MessageFormat instance to a pattern.
UnicodeString&
MessageFormat::toPattern(UnicodeString& appendTo) const {
@ -732,7 +728,7 @@ MessageFormat::toPattern(UnicodeString& appendTo) const {
SelectFormat* selfmt;
if (fmt == NULL) {
// do nothing, string format
}
}
else if ((decfmt = dynamic_cast<DecimalFormat*>(fmt)) != NULL) {
UErrorCode ec = U_ZERO_ERROR;
NumberFormat& formatAlias = *decfmt;
@ -740,31 +736,31 @@ MessageFormat::toPattern(UnicodeString& appendTo) const {
NumberFormat *currencyTemplate = NumberFormat::createCurrencyInstance(fLocale, ec);
NumberFormat *percentTemplate = NumberFormat::createPercentInstance(fLocale, ec);
NumberFormat *integerTemplate = createIntegerFormat(fLocale, ec);
appendTo += COMMA;
appendTo += ID_NUMBER;
if (formatAlias != *defaultTemplate) {
appendTo += COMMA;
if (formatAlias == *currencyTemplate) {
appendTo += ID_CURRENCY;
}
}
else if (formatAlias == *percentTemplate) {
appendTo += ID_PERCENT;
}
}
else if (formatAlias == *integerTemplate) {
appendTo += ID_INTEGER;
}
}
else {
UnicodeString buffer;
appendTo += decfmt->toPattern(buffer);
}
}
delete defaultTemplate;
delete currencyTemplate;
delete percentTemplate;
delete integerTemplate;
}
}
else if ((sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt)) != NULL) {
DateFormat& formatAlias = *sdtfmt;
DateFormat *defaultDateTemplate = DateFormat::createDateInstance(DateFormat::kDefault, fLocale);
@ -775,62 +771,62 @@ MessageFormat::toPattern(UnicodeString& appendTo) const {
DateFormat *shortTimeTemplate = DateFormat::createTimeInstance(DateFormat::kShort, fLocale);
DateFormat *longTimeTemplate = DateFormat::createTimeInstance(DateFormat::kLong, fLocale);
DateFormat *fullTimeTemplate = DateFormat::createTimeInstance(DateFormat::kFull, fLocale);
appendTo += COMMA;
if (formatAlias == *defaultDateTemplate) {
appendTo += ID_DATE;
}
}
else if (formatAlias == *shortDateTemplate) {
appendTo += ID_DATE;
appendTo += COMMA;
appendTo += ID_SHORT;
}
}
else if (formatAlias == *defaultDateTemplate) {
appendTo += ID_DATE;
appendTo += COMMA;
appendTo += ID_MEDIUM;
}
}
else if (formatAlias == *longDateTemplate) {
appendTo += ID_DATE;
appendTo += COMMA;
appendTo += ID_LONG;
}
}
else if (formatAlias == *fullDateTemplate) {
appendTo += ID_DATE;
appendTo += COMMA;
appendTo += ID_FULL;
}
}
else if (formatAlias == *defaultTimeTemplate) {
appendTo += ID_TIME;
}
}
else if (formatAlias == *shortTimeTemplate) {
appendTo += ID_TIME;
appendTo += COMMA;
appendTo += ID_SHORT;
}
}
else if (formatAlias == *defaultTimeTemplate) {
appendTo += ID_TIME;
appendTo += COMMA;
appendTo += ID_MEDIUM;
}
}
else if (formatAlias == *longTimeTemplate) {
appendTo += ID_TIME;
appendTo += COMMA;
appendTo += ID_LONG;
}
}
else if (formatAlias == *fullTimeTemplate) {
appendTo += ID_TIME;
appendTo += COMMA;
appendTo += ID_FULL;
}
}
else {
UnicodeString buffer;
appendTo += ID_DATE;
appendTo += COMMA;
appendTo += sdtfmt->toPattern(buffer);
}
delete defaultDateTemplate;
delete shortDateTemplate;
delete longDateTemplate;
@ -840,7 +836,7 @@ MessageFormat::toPattern(UnicodeString& appendTo) const {
delete longTimeTemplate;
delete fullTimeTemplate;
// {sfb} there should be a more efficient way to do this!
}
}
else if ((chcfmt = dynamic_cast<ChoiceFormat*>(fmt)) != NULL) {
UnicodeString buffer;
appendTo += COMMA;
@ -851,11 +847,11 @@ MessageFormat::toPattern(UnicodeString& appendTo) const {
else if ((plfmt = dynamic_cast<PluralFormat*>(fmt)) != NULL) {
UnicodeString buffer;
appendTo += plfmt->toPattern(buffer);
}
}
else if ((selfmt = dynamic_cast<SelectFormat*>(fmt)) != NULL) {
UnicodeString buffer;
appendTo += ((SelectFormat*)fmt)->toPattern(buffer);
}
}
else {
//appendTo += ", unknown";
}
@ -864,18 +860,18 @@ MessageFormat::toPattern(UnicodeString& appendTo) const {
copyAndFixQuotes(fPattern, lastOffset, fPattern.length(), appendTo);
return appendTo;
}
// -------------------------------------
// Adopts the new formats array and updates the array count.
// This MessageFormat instance owns the new formats.
void
MessageFormat::adoptFormats(Format** newFormats,
int32_t count) {
if (newFormats == NULL || count < 0) {
return;
}
int32_t i;
if (allocateSubformats(count)) {
for (i=0; i<subformatCount; ++i) {
@ -894,12 +890,12 @@ MessageFormat::adoptFormats(Format** newFormats,
}
// TODO: What about the .offset and .argNum fields?
}
}
// -------------------------------------
// Sets the new formats array and updates the array count.
// This MessageFormat instance maks a copy of the new formats.
void
MessageFormat::setFormats(const Format** newFormats,
int32_t count) {
@ -908,7 +904,7 @@ MessageFormat::setFormats(const Format** newFormats,
}
if (allocateSubformats(count)) {
int32_t i;
int32_t i;
for (i=0; i<subformatCount; ++i) {
delete subformats[i].format;
}
@ -921,12 +917,12 @@ MessageFormat::setFormats(const Format** newFormats,
}
// TODO: What about the .offset and .arg fields?
}
}
// -------------------------------------
// Adopt a single format by format number.
// Do nothing if the format number is not less than the array count.
void
MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
if (n < 0 || n >= subformatCount) {
@ -941,14 +937,14 @@ MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
// Adopt a single format by format name.
// Do nothing if there is no match of formatName.
void
MessageFormat::adoptFormat(const UnicodeString& formatName,
MessageFormat::adoptFormat(const UnicodeString& formatName,
Format* formatToAdopt,
UErrorCode& status) {
if (isArgNumeric ) {
int32_t argumentNumber = stou(formatName);
if (argumentNumber<0) {
status = U_ARGUMENT_TYPE_MISMATCH;
return;
return;
}
adoptFormat(argumentNumber, formatToAdopt);
return;
@ -969,7 +965,7 @@ MessageFormat::adoptFormat(const UnicodeString& formatName,
// -------------------------------------
// Set a single format.
// Do nothing if the variable is not less than the array count.
void
MessageFormat::setFormat(int32_t n, const Format& newFormat) {
if (n >= 0 && n < subformatCount) {
@ -990,12 +986,12 @@ Format *
MessageFormat::getFormat(const UnicodeString& formatName, UErrorCode& status) {
if (U_FAILURE(status)) return NULL;
if (isArgNumeric ) {
int32_t argumentNumber = stou(formatName);
if (argumentNumber<0) {
status = U_ARGUMENT_TYPE_MISMATCH;
return NULL;
return NULL;
}
if (argumentNumber < 0 || argumentNumber >= subformatCount) {
return subformats[argumentNumber].format;
@ -1004,7 +1000,7 @@ MessageFormat::getFormat(const UnicodeString& formatName, UErrorCode& status) {
return NULL;
}
}
for (int32_t i=0; i<subformatCount; ++i) {
if (formatName==*subformats[i].argName)
{
@ -1042,7 +1038,7 @@ MessageFormat::setFormat(const UnicodeString& formatName,
// -------------------------------------
// Gets the format array.
const Format**
MessageFormat::getFormats(int32_t& cnt) const
{
@ -1060,7 +1056,7 @@ MessageFormat::getFormats(int32_t& cnt) const
if (a == NULL) {
return NULL;
}
t->formatAliases = a;
t->formatAliases = a;
} else if (subformatCount > formatAliasesCapacity) {
Format** a = (Format**)
uprv_realloc(formatAliases, sizeof(Format*) * subformatCount);
@ -1076,16 +1072,16 @@ MessageFormat::getFormats(int32_t& cnt) const
cnt = subformatCount;
return (const Format**)formatAliases;
}
StringEnumeration*
MessageFormat::getFormatNames(UErrorCode& status) {
if (U_FAILURE(status)) return NULL;
if (isArgNumeric) {
status = U_ARGUMENT_TYPE_MISMATCH;
return NULL;
}
}
UVector *fFormatNames = new UVector(status);
if (U_FAILURE(status)) {
status = U_MEMORY_ALLOCATION_ERROR;
@ -1102,30 +1098,30 @@ MessageFormat::getFormatNames(UErrorCode& status) {
// -------------------------------------
// Formats the source Formattable array and copy into the result buffer.
// Ignore the FieldPosition result for error checking.
UnicodeString&
MessageFormat::format(const Formattable* source,
int32_t cnt,
UnicodeString& appendTo,
FieldPosition& ignore,
int32_t cnt,
UnicodeString& appendTo,
FieldPosition& ignore,
UErrorCode& success) const
{
if (U_FAILURE(success))
if (U_FAILURE(success))
return appendTo;
return format(source, cnt, appendTo, ignore, 0, success);
}
// -------------------------------------
// Internally creates a MessageFormat instance based on the
// pattern and formats the arguments Formattable array and
// pattern and formats the arguments Formattable array and
// copy into the appendTo buffer.
UnicodeString&
MessageFormat::format( const UnicodeString& pattern,
const Formattable* arguments,
int32_t cnt,
UnicodeString& appendTo,
UnicodeString& appendTo,
UErrorCode& success)
{
MessageFormat temp(pattern, success);
@ -1133,28 +1129,28 @@ MessageFormat::format( const UnicodeString& pattern,
temp.format(arguments, cnt, appendTo, ignore, success);
return appendTo;
}
// -------------------------------------
// Formats the source Formattable object and copy into the
// Formats the source Formattable object and copy into the
// appendTo buffer. The Formattable object must be an array
// of Formattable instances, returns error otherwise.
UnicodeString&
MessageFormat::format(const Formattable& source,
UnicodeString& appendTo,
FieldPosition& ignore,
MessageFormat::format(const Formattable& source,
UnicodeString& appendTo,
FieldPosition& ignore,
UErrorCode& success) const
{
int32_t cnt;
if (U_FAILURE(success))
if (U_FAILURE(success))
return appendTo;
if (source.getType() != Formattable::kArray) {
success = U_ILLEGAL_ARGUMENT_ERROR;
return appendTo;
}
const Formattable* tmpPtr = source.getArray(cnt);
return format(tmpPtr, cnt, appendTo, ignore, 0, success);
}
@ -1170,12 +1166,12 @@ MessageFormat::format(const UnicodeString* argumentNames,
}
UnicodeString&
MessageFormat::format(const Formattable* arguments,
int32_t cnt,
UnicodeString& appendTo,
FieldPosition& status,
MessageFormat::format(const Formattable* arguments,
int32_t cnt,
UnicodeString& appendTo,
FieldPosition& status,
int32_t recursionProtection,
UErrorCode& success) const
UErrorCode& success) const
{
return format(arguments, NULL, cnt, appendTo, status, recursionProtection, success);
}
@ -1187,24 +1183,24 @@ MessageFormat::format(const Formattable* arguments,
UnicodeString&
MessageFormat::format(const Formattable* arguments,
const UnicodeString *argumentNames,
int32_t cnt,
UnicodeString& appendTo,
FieldPosition& status,
int32_t cnt,
UnicodeString& appendTo,
FieldPosition& status,
int32_t recursionProtection,
UErrorCode& success) const
{
UErrorCode& success) const
{
int32_t lastOffset = 0;
int32_t argumentNumber=0;
if (cnt < 0 || (cnt && arguments == NULL)) {
success = U_ILLEGAL_ARGUMENT_ERROR;
return appendTo;
}
if ( !isArgNumeric && argumentNames== NULL ) {
success = U_ILLEGAL_ARGUMENT_ERROR;
return appendTo;
}
const Formattable *obj=NULL;
for (int32_t i=0; i<subformatCount; ++i) {
// Append the prefix of current format element.
@ -1235,7 +1231,7 @@ MessageFormat::format(const Formattable* arguments,
appendTo += *subformats[i].argName;
appendTo += RIGHT_CURLY_BRACE;
continue;
}
}
Formattable::Type type = obj->getType();
@ -1263,8 +1259,8 @@ MessageFormat::format(const Formattable* arguments,
else {
temp.format(arguments, argumentNames, cnt, appendTo, status, recursionProtection, success);
}
if (U_FAILURE(success)) {
return appendTo;
if (U_FAILURE(success)) {
return appendTo;
}
}
else {
@ -1272,13 +1268,13 @@ MessageFormat::format(const Formattable* arguments,
}
}
// If the obj data type is a number, use a NumberFormat instance.
else if ((type == Formattable::kDouble) ||
else if ((type == Formattable::kDouble) ||
(type == Formattable::kLong) ||
(type == Formattable::kInt64)) {
const NumberFormat* nf = getDefaultNumberFormat(success);
if (nf == NULL) {
return appendTo;
if (nf == NULL) {
return appendTo;
}
if (type == Formattable::kDouble) {
nf->format(obj->getDouble(), appendTo);
@ -1291,8 +1287,8 @@ MessageFormat::format(const Formattable* arguments,
// If the obj data type is a Date instance, use a DateFormat instance.
else if (type == Formattable::kDate) {
const DateFormat* df = getDefaultDateFormat(success);
if (df == NULL) {
return appendTo;
if (df == NULL) {
return appendTo;
}
df->format(obj->getDate(), appendTo);
}
@ -1312,11 +1308,11 @@ MessageFormat::format(const Formattable* arguments,
// -------------------------------------
// Parses the source pattern and returns the Formattable objects array,
// the array count and the ending parse position. The caller of this method
// the array count and the ending parse position. The caller of this method
// owns the array.
Formattable*
MessageFormat::parse(const UnicodeString& source,
MessageFormat::parse(const UnicodeString& source,
ParsePosition& pos,
int32_t& count) const
{
@ -1336,15 +1332,15 @@ MessageFormat::parse(const UnicodeString& source,
for (int32_t i = 0; i < subformatCount; ++i) {
// match up to format
len = subformats[i].offset - patternOffset;
if (len == 0 ||
if (len == 0 ||
fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
sourceOffset += len;
patternOffset += len;
}
}
else {
goto PARSE_ERROR;
}
// now use format
Format* fmt = subformats[i].format;
int32_t argNum = subformats[i].argNum;
@ -1354,7 +1350,7 @@ MessageFormat::parse(const UnicodeString& source,
// does NOT recursively try all possibilities
int32_t tempLength = (i+1<subformatCount) ?
subformats[i+1].offset : fPattern.length();
int32_t next;
if (patternOffset >= tempLength) {
next = source.length();
@ -1364,10 +1360,10 @@ MessageFormat::parse(const UnicodeString& source,
fPattern.extract(patternOffset,tempLength - patternOffset, buffer);
next = source.indexOf(buffer, sourceOffset);
}
if (next < 0) {
goto PARSE_ERROR;
}
}
else {
UnicodeString buffer;
source.extract(sourceOffset,next - sourceOffset, buffer);
@ -1391,14 +1387,14 @@ MessageFormat::parse(const UnicodeString& source,
}
sourceOffset = next;
}
}
}
else {
tempPos.setIndex(sourceOffset);
fmt->parseObject(source, resultArray[argNum], tempPos);
if (tempPos.getIndex() == sourceOffset) {
goto PARSE_ERROR;
}
if ((argNum + 1) > count) {
count = argNum + 1;
}
@ -1406,7 +1402,7 @@ MessageFormat::parse(const UnicodeString& source,
}
}
len = fPattern.length() - patternOffset;
if (len == 0 ||
if (len == 0 ||
fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
pos.setIndex(sourceOffset + len);
return resultArray;
@ -1419,20 +1415,20 @@ MessageFormat::parse(const UnicodeString& source,
count = 0;
return NULL; // leave index as is to signal error
}
// -------------------------------------
// Parses the source string and returns the array of
// Formattable objects and the array count. The caller
// Parses the source string and returns the array of
// Formattable objects and the array count. The caller
// owns the returned array.
Formattable*
MessageFormat::parse(const UnicodeString& source,
MessageFormat::parse(const UnicodeString& source,
int32_t& cnt,
UErrorCode& success) const
{
if (!isArgNumeric ) {
success = U_ARGUMENT_TYPE_MISMATCH;
return NULL;
return NULL;
}
ParsePosition status(0);
// Calls the actual implementation method and starts
@ -1445,10 +1441,10 @@ MessageFormat::parse(const UnicodeString& source,
}
return result;
}
// -------------------------------------
// Parses the source text and copy into the result buffer.
void
MessageFormat::parseObject( const UnicodeString& source,
Formattable& result,
@ -1456,11 +1452,11 @@ MessageFormat::parseObject( const UnicodeString& source,
{
int32_t cnt = 0;
Formattable* tmpResult = parse(source, status, cnt);
if (tmpResult != NULL)
if (tmpResult != NULL)
result.adoptArray(tmpResult, cnt);
}
UnicodeString
UnicodeString
MessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) {
UnicodeString result;
if (U_SUCCESS(status)) {
@ -1493,7 +1489,7 @@ static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const Unicode
}
return fmt;
}
/**
* Reads the segments[] array (see applyPattern()) and parses the
* segments[1..3] into a Format* object. Stores the format object in
@ -1506,7 +1502,7 @@ static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const Unicode
* @param ec error code
*/
void
MessageFormat::makeFormat(int32_t formatNumber,
MessageFormat::makeFormat(int32_t formatNumber,
UnicodeString* segments,
UParseError& parseError,
UErrorCode& ec) {
@ -1632,7 +1628,7 @@ MessageFormat::makeFormat(int32_t formatNumber,
else {
inQuote = !inQuote;
}
}
}
else {
unquotedPattern += ch;
}
@ -1651,7 +1647,7 @@ MessageFormat::makeFormat(int32_t formatNumber,
if (fmt==NULL && argType!=Formattable::kString && U_SUCCESS(ec)) {
ec = U_MEMORY_ALLOCATION_ERROR;
}
if (!allocateSubformats(formatNumber+1) ||
!allocateArgTypes(argumentNumber+1)) {
ec = U_MEMORY_ALLOCATION_ERROR;
@ -1682,10 +1678,10 @@ MessageFormat::makeFormat(int32_t formatNumber,
argTypeCount = argumentNumber+1;
}
}
// -------------------------------------
// Finds the string, s, in the string array, list.
int32_t MessageFormat::findKeyword(const UnicodeString& s,
// Finds the string, s, in the string array, list.
int32_t MessageFormat::findKeyword(const UnicodeString& s,
const UChar * const *list)
{
if (s.length() == 0)
@ -1702,19 +1698,19 @@ int32_t MessageFormat::findKeyword(const UnicodeString& s,
}
return -1;
}
// -------------------------------------
// Checks the range of the source text to quote the special
// characters, { and ' and copy to target buffer.
void
MessageFormat::copyAndFixQuotes(const UnicodeString& source,
int32_t start,
int32_t end,
MessageFormat::copyAndFixQuotes(const UnicodeString& source,
int32_t start,
int32_t end,
UnicodeString& appendTo)
{
UBool gotLB = FALSE;
for (int32_t i = start; i < end; ++i) {
UChar ch = source[i];
if (ch == LEFT_CURLY_BRACE) {
@ -1722,7 +1718,7 @@ MessageFormat::copyAndFixQuotes(const UnicodeString& source,
appendTo += LEFT_CURLY_BRACE;
appendTo += SINGLE_QUOTE;
gotLB = TRUE;
}
}
else if (ch == RIGHT_CURLY_BRACE) {
if(gotLB) {
appendTo += RIGHT_CURLY_BRACE;
@ -1734,11 +1730,11 @@ MessageFormat::copyAndFixQuotes(const UnicodeString& source,
appendTo += RIGHT_CURLY_BRACE;
appendTo += SINGLE_QUOTE;
}
}
}
else if (ch == SINGLE_QUOTE) {
appendTo += SINGLE_QUOTE;
appendTo += SINGLE_QUOTE;
}
}
else {
appendTo += ch;
}
@ -1748,7 +1744,7 @@ MessageFormat::copyAndFixQuotes(const UnicodeString& source,
/**
* Convenience method that ought to be in NumberFormat
*/
NumberFormat*
NumberFormat*
MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
NumberFormat *temp = NumberFormat::createInstance(locale, status);
DecimalFormat *temp2;
@ -1772,7 +1768,7 @@ const NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const
if (defaultNumberFormat == NULL) {
MessageFormat* t = (MessageFormat*) this;
t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec);
if (U_FAILURE(ec)) {
if (U_FAILURE(ec)) {
delete t->defaultNumberFormat;
t->defaultNumberFormat = NULL;
} else if (t->defaultNumberFormat == NULL) {
@ -1818,10 +1814,10 @@ MessageFormat::isLegalArgName(const UnicodeString& argName) const {
return TRUE;
}
int32_t
int32_t
MessageFormat::getArgTypeCount() const {
return argTypeCount;
}
return argTypeCount;
}
FormatNameEnumeration::FormatNameEnumeration(UVector *fNameList, UErrorCode& /*status*/) {
pos=0;

View file

@ -1,8 +1,8 @@
/********************************************************************
* COPYRIGHT:
* COPYRIGHT:
* Copyright (c) 1997-2010, International Business Machines Corporation and
* others. All Rights Reserved.
* Copyright (C) 2010 , Yahoo! Inc.
* Copyright (C) 2010 , Yahoo! Inc.
********************************************************************
*
* File SELFMT.CPP
@ -11,7 +11,7 @@
*
* Date Name Description
* 11/11/09 kirtig Finished first cut of implementation.
* 11/16/09 kirtig Improved version
* 11/16/09 kirtig Improved version
********************************************************************/
#include <typeinfo> // for 'typeid' to work
@ -40,41 +40,61 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SelectFormat)
#define MAX_KEYWORD_SIZE 30
static const UChar SELECT_KEYWORD_OTHER[] = {LOW_O, LOW_T, LOW_H, LOW_E, LOW_R, 0};
SelectFormat::SelectFormat(const UnicodeString& pat, UErrorCode& status) {
SelectFormat::SelectFormat(const UnicodeString& pat, UErrorCode& status) : parsedValuesHash(NULL) {
if (U_FAILURE(status)) {
return;
}
init(status);
}
initHashTable(status);
applyPattern(pat, status);
}
SelectFormat::SelectFormat(const SelectFormat& other) : Format(other) {
SelectFormat::SelectFormat(const SelectFormat& other) : Format(other), parsedValuesHash(NULL) {
UErrorCode status = U_ZERO_ERROR;
pattern = other.pattern;
copyHashtable(other.parsedValuesHash, status);
}
SelectFormat::~SelectFormat() {
delete parsedValuesHash;
cleanHashTable();
}
void
SelectFormat::init(UErrorCode& status) {
if (U_FAILURE(status)) {
void SelectFormat::initHashTable(UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
// has inited
if (parsedValuesHash != NULL) {
return;
}
parsedValuesHash = new Hashtable(TRUE, status);
if (U_FAILURE(status)) {
cleanHashTable();
return;
} else {
if (parsedValuesHash == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
parsedValuesHash = NULL;
pattern.remove();
}
}
// to use hashtable->equals(), must set Value Compartor.
parsedValuesHash->setValueComparator(uhash_compareCaselessUnicodeString);
}
void SelectFormat::cleanHashTable() {
if (parsedValuesHash != NULL) {
delete parsedValuesHash;
parsedValuesHash = NULL;
}
}
void
SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
}
this->pattern = newPattern;
pattern = newPattern;
enum State{ startState, keywordState, pastKeywordState, phraseState};
//Initialization
@ -83,12 +103,13 @@ SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status)
UnicodeString* ptrPhrase ;
int32_t braceCount = 0;
delete parsedValuesHash;
this->parsedValuesHash = NULL;
parsedValuesHash = new Hashtable(TRUE, status);
if (U_FAILURE(status)) {
if (parsedValuesHash == NULL) {
initHashTable(status);
if (U_FAILURE(status)) {
return;
}
}
parsedValuesHash->removeAll();
parsedValuesHash->setValueDeleter(uhash_deleteUnicodeString);
//Process the state machine
@ -96,7 +117,7 @@ SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status)
for (int32_t i = 0; i < pattern.length(); ++i) {
//Get the character and check its type
UChar ch = pattern.charAt(i);
CharacterClass type = classifyCharacter(ch);
CharacterClass type = classifyCharacter(ch);
//Allow any character in phrase but nowhere else
if ( type == tOther ) {
@ -105,6 +126,7 @@ SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status)
continue;
}else {
status = U_PATTERN_SYNTAX_ERROR;
cleanHashTable();
return;
}
}
@ -123,6 +145,7 @@ SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status)
//If anything else is encountered, it's a syntax error
default:
status = U_PATTERN_SYNTAX_ERROR;
cleanHashTable();
return;
}//end of switch(type)
break;
@ -143,6 +166,7 @@ SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status)
//If anything else is encountered, it's a syntax error
default:
status = U_PATTERN_SYNTAX_ERROR;
cleanHashTable();
return;
}//end of switch(type)
break;
@ -158,6 +182,7 @@ SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status)
//If anything else is encountered, it's a syntax error
default:
status = U_PATTERN_SYNTAX_ERROR;
cleanHashTable();
return;
}//end of switch(type)
break;
@ -175,10 +200,12 @@ SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status)
//Check validity of keyword
if (parsedValuesHash->get(keyword) != NULL) {
status = U_DUPLICATE_KEYWORD;
return;
cleanHashTable();
return;
}
if (keyword.length() == 0) {
status = U_PATTERN_SYNTAX_ERROR;
cleanHashTable();
return;
}
@ -206,6 +233,7 @@ SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status)
//Handle the default case of switch(state)
default:
status = U_PATTERN_SYNTAX_ERROR;
cleanHashTable();
return;
}//end of switch(state)
@ -214,12 +242,14 @@ SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status)
//Check if the state machine is back to startState
if ( state != startState){
status = U_PATTERN_SYNTAX_ERROR;
cleanHashTable();
return;
}
//Check if "other" keyword is present
//Check if "other" keyword is present
if ( !checkSufficientDefinition() ) {
status = U_DEFAULT_KEYWORD_MISSING;
cleanHashTable();
}
return;
}
@ -244,28 +274,28 @@ SelectFormat::format(const Formattable& obj,
UnicodeString&
SelectFormat::format(const UnicodeString& keyword,
UnicodeString& appendTo,
UnicodeString& appendTo,
FieldPosition& /*pos */,
UErrorCode& status) const {
if (U_FAILURE(status)) return appendTo;
if (parsedValuesHash == NULL) {
status = U_INVALID_FORMAT_ERROR;
return appendTo;
}
//Check for the validity of the keyword
if ( !checkValidKeyword(keyword) ){
status = U_ILLEGAL_ARGUMENT_ERROR;
return appendTo;
}
if (parsedValuesHash == NULL) {
status = U_INVALID_FORMAT_ERROR;
return appendTo;
}
UnicodeString *selectedPattern = (UnicodeString *)parsedValuesHash->get(keyword);
if (selectedPattern == NULL) {
selectedPattern = (UnicodeString *)parsedValuesHash->get(SELECT_KEYWORD_OTHER);
}
return appendTo += *selectedPattern;
}
@ -289,7 +319,7 @@ SelectFormat::classifyCharacter(UChar ch) const{
return tSpace;
}
switch (ch) {
case LEFTBRACE:
case LEFTBRACE:
return tLeftBrace;
case RIGHTBRACE:
return tRightBrace;
@ -314,13 +344,13 @@ SelectFormat::checkValidKeyword(const UnicodeString& argKeyword ) const{
if (len < 1){
return FALSE;
}
CharacterClass type = classifyCharacter(argKeyword.charAt(0));
CharacterClass type = classifyCharacter(argKeyword.charAt(0));
if( type != tStartKeyword ){
return FALSE;
}
for (int32_t i = 0; i < argKeyword.length(); ++i) {
type = classifyCharacter(argKeyword.charAt(i));
type = classifyCharacter(argKeyword.charAt(i));
if( type != tStartKeyword && type != tContinueKeyword ){
return FALSE;
}
@ -337,7 +367,6 @@ SelectFormat&
SelectFormat::operator=(const SelectFormat& other) {
if (this != &other) {
UErrorCode status = U_ZERO_ERROR;
delete parsedValuesHash;
pattern = other.pattern;
copyHashtable(other.parsedValuesHash, status);
}
@ -358,44 +387,7 @@ SelectFormat::operator==(const Format& other) const {
return TRUE;
if ( parsedValuesHash == NULL || hashOther == NULL)
return FALSE;
if ( hashOther->count() != parsedValuesHash->count() ){
return FALSE;
}
const UHashElement* elem = NULL;
int32_t pos = -1;
while ((elem = hashOther->nextElement(pos)) != NULL) {
const UHashTok otherKeyTok = elem->key;
UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer;
const UHashTok otherKeyToVal = elem->value;
UnicodeString* otherValue = (UnicodeString*)otherKeyToVal.pointer;
UnicodeString* thisElemValue = (UnicodeString*)parsedValuesHash->get(*otherKey);
if ( thisElemValue == NULL ){
return FALSE;
}
if ( *thisElemValue != *otherValue){
return FALSE;
}
}
pos = -1;
while ((elem = parsedValuesHash->nextElement(pos)) != NULL) {
const UHashTok thisKeyTok = elem->key;
UnicodeString* thisKey = (UnicodeString*)thisKeyTok.pointer;
const UHashTok thisKeyToVal = elem->value;
UnicodeString* thisValue = (UnicodeString*)thisKeyToVal.pointer;
UnicodeString* otherElemValue = (UnicodeString*)hashOther->get(*thisKey);
if ( otherElemValue == NULL ){
return FALSE;
}
if ( *otherElemValue != *thisValue){
return FALSE;
}
}
return TRUE;
return parsedValuesHash->equals(*hashOther);
}
UBool
@ -414,14 +406,21 @@ SelectFormat::parseObject(const UnicodeString& /*source*/,
void
SelectFormat::copyHashtable(Hashtable *other, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
if (other == NULL) {
parsedValuesHash = NULL;
return;
cleanHashTable();
return;
}
parsedValuesHash = new Hashtable(TRUE, status);
if (U_FAILURE(status)){
if (parsedValuesHash == NULL) {
initHashTable(status);
if (U_FAILURE(status)) {
return;
}
}
parsedValuesHash->removeAll();
parsedValuesHash->setValueDeleter(uhash_deleteUnicodeString);
int32_t pos = -1;
@ -435,6 +434,7 @@ SelectFormat::copyHashtable(Hashtable *other, UErrorCode& status) {
UnicodeString* otherValue = (UnicodeString*)otherKeyToVal.pointer;
parsedValuesHash->put(*otherKey, new UnicodeString(*otherValue), status);
if (U_FAILURE(status)){
cleanHashTable();
return;
}
}

View file

@ -356,7 +356,9 @@ private:
Hashtable *parsedValuesHash;
SelectFormat(); // default constructor not implemented.
void init(UErrorCode& status);
void initHashTable(UErrorCode &status);
void cleanHashTable();
//For the applyPattern , classifies char.s in one of the characterClass.
CharacterClass classifyCharacter(UChar ch) const;
//Checks if the "other" keyword is present in pattern.