diff options
Diffstat (limited to 'Build/source/libs/icu/icu-4.6/i18n/plurfmt.cpp')
-rw-r--r-- | Build/source/libs/icu/icu-4.6/i18n/plurfmt.cpp | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-4.6/i18n/plurfmt.cpp b/Build/source/libs/icu/icu-4.6/i18n/plurfmt.cpp new file mode 100644 index 00000000000..0464cf57c66 --- /dev/null +++ b/Build/source/libs/icu/icu-4.6/i18n/plurfmt.cpp @@ -0,0 +1,537 @@ +/* +******************************************************************************* +* Copyright (C) 2009, International Business Machines Corporation and +* others. All Rights Reserved. +******************************************************************************* +* +* File PLURFMT.CPP +* +* Modification History: +* +* Date Name Description +******************************************************************************* +*/ + + +#include "unicode/utypes.h" +#include "unicode/plurfmt.h" +#include "unicode/plurrule.h" +#include "plurrule_impl.h" + +#if !UCONFIG_NO_FORMATTING + +U_NAMESPACE_BEGIN + +U_CDECL_BEGIN +static void U_CALLCONV +deleteHashStrings(void *obj) { + delete (UnicodeString *)obj; +} +U_CDECL_END + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralFormat) + +#define MAX_KEYWORD_SIZE 30 + +PluralFormat::PluralFormat(UErrorCode& status) { + init(NULL, Locale::getDefault(), status); +} + +PluralFormat::PluralFormat(const Locale& loc, UErrorCode& status) { + init(NULL, loc, status); +} + +PluralFormat::PluralFormat(const PluralRules& rules, UErrorCode& status) { + init(&rules, Locale::getDefault(), status); +} + +PluralFormat::PluralFormat(const Locale& loc, const PluralRules& rules, UErrorCode& status) { + init(&rules, loc, status); +} + +PluralFormat::PluralFormat(const UnicodeString& pat, UErrorCode& status) { + init(NULL, Locale::getDefault(), status); + applyPattern(pat, status); +} + +PluralFormat::PluralFormat(const Locale& loc, const UnicodeString& pat, UErrorCode& status) { + init(NULL, loc, status); + applyPattern(pat, status); +} + +PluralFormat::PluralFormat(const PluralRules& rules, const UnicodeString& pat, UErrorCode& status) { + init(&rules, Locale::getDefault(), status); + applyPattern(pat, status); +} + +PluralFormat::PluralFormat(const Locale& loc, const PluralRules& rules, const UnicodeString& pat, UErrorCode& status) { + init(&rules, loc, status); + applyPattern(pat, status); +} + +PluralFormat::PluralFormat(const PluralFormat& other) : Format(other) { + UErrorCode status = U_ZERO_ERROR; + locale = other.locale; + pluralRules = other.pluralRules->clone(); + pattern = other.pattern; + copyHashtable(other.fParsedValuesHash, status); + if (U_FAILURE(status)) { + delete pluralRules; + pluralRules = NULL; + return; + } + numberFormat=NumberFormat::createInstance(locale, status); + if (U_FAILURE(status)) { + delete pluralRules; + pluralRules = NULL; + delete fParsedValuesHash; + fParsedValuesHash = NULL; + return; + } + replacedNumberFormat=other.replacedNumberFormat; +} + +PluralFormat::~PluralFormat() { + delete pluralRules; + delete fParsedValuesHash; + delete numberFormat; +} + +void +PluralFormat::init(const PluralRules* rules, const Locale& curLocale, UErrorCode& status) { + if (U_FAILURE(status)) { + return; + } + locale = curLocale; + if ( rules==NULL) { + pluralRules = PluralRules::forLocale(locale, status); + if (U_FAILURE(status)) { + return; + } + } + else { + pluralRules = rules->clone(); + } + fParsedValuesHash=NULL; + pattern.remove(); + numberFormat= NumberFormat::createInstance(curLocale, status); + if (U_FAILURE(status)) { + delete pluralRules; + pluralRules = NULL; + return; + } + replacedNumberFormat=NULL; +} + +void +PluralFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) { + if (U_FAILURE(status)) { + return; + } + this->pattern = newPattern; + UnicodeString token; + int32_t braceCount=0; + fmtToken type; + UBool spaceIncluded=FALSE; + + if (fParsedValuesHash==NULL) { + fParsedValuesHash = new Hashtable(TRUE, status); + if (U_FAILURE(status)) { + return; + } + fParsedValuesHash->setValueDeleter(deleteHashStrings); + } + + UBool getKeyword=TRUE; + UnicodeString hashKeyword; + UnicodeString *hashPattern; + + for (int32_t i=0; i<pattern.length(); ++i) { + UChar ch=pattern.charAt(i); + + if ( !inRange(ch, type) ) { + if (getKeyword) { + status = U_ILLEGAL_CHARACTER; + return; + } + else { + token += ch; + continue; + } + } + switch (type) { + case tSpace: + if (token.length()==0) { + continue; + } + if (getKeyword) { + // space after keyword + spaceIncluded = TRUE; + } + else { + token += ch; + } + break; + case tLeftBrace: + if ( getKeyword ) { + if (fParsedValuesHash->get(token)!= NULL) { + status = U_DUPLICATE_KEYWORD; + return; + } + if (token.length()==0) { + status = U_PATTERN_SYNTAX_ERROR; + return; + } + if (!pluralRules->isKeyword(token)) { + status = U_UNDEFINED_KEYWORD; + return; + } + hashKeyword = token; + getKeyword = FALSE; + token.remove(); + } + else { + if (braceCount==0) { + status = U_UNEXPECTED_TOKEN; + return; + } + else { + token += ch; + } + } + braceCount++; + spaceIncluded = FALSE; + break; + case tRightBrace: + if ( getKeyword ) { + status = U_UNEXPECTED_TOKEN; + return; + } + else { + hashPattern = new UnicodeString(token); + fParsedValuesHash->put(hashKeyword, hashPattern, status); + if (U_FAILURE(status)) { + return; + } + braceCount--; + if ( braceCount==0 ) { + getKeyword=TRUE; + hashKeyword.remove(); + hashPattern=NULL; + token.remove(); + } + else { + token += ch; + } + } + spaceIncluded = FALSE; + break; + case tLetter: + case tNumberSign: + if (spaceIncluded) { + status = U_PATTERN_SYNTAX_ERROR; + return; + } + default: + token+=ch; + break; + } + } + if ( checkSufficientDefinition() ) { + return; + } + else { + status = U_DEFAULT_KEYWORD_MISSING; + return; + } +} + +UnicodeString& +PluralFormat::format(const Formattable& obj, + UnicodeString& appendTo, + FieldPosition& pos, + UErrorCode& status) const +{ + if (U_FAILURE(status)) return appendTo; + int32_t number; + + switch (obj.getType()) + { + case Formattable::kDouble: + return format((int32_t)obj.getDouble(), appendTo, pos, status); + break; + case Formattable::kLong: + number = (int32_t)obj.getLong(); + return format(number, appendTo, pos, status); + break; + case Formattable::kInt64: + return format((int32_t)obj.getInt64(), appendTo, pos, status); + default: + status = U_ILLEGAL_ARGUMENT_ERROR; + return appendTo; + } +} + +UnicodeString +PluralFormat::format(int32_t number, UErrorCode& status) const { + if (U_FAILURE(status)) { + return UnicodeString(); + } + FieldPosition fpos(0); + UnicodeString result; + + return format(number, result, fpos, status); +} + +UnicodeString +PluralFormat::format(double number, UErrorCode& status) const { + if (U_FAILURE(status)) { + return UnicodeString(); + } + FieldPosition fpos(0); + UnicodeString result; + + return format(number, result, fpos, status); +} + + +UnicodeString& +PluralFormat::format(int32_t number, + UnicodeString& appendTo, + FieldPosition& pos, + UErrorCode& status) const { + return format((double)number, appendTo, pos, status); +} + +UnicodeString& +PluralFormat::format(double number, + UnicodeString& appendTo, + FieldPosition& pos, + UErrorCode& /*status*/) const { + + if (fParsedValuesHash==NULL) { + if ( replacedNumberFormat== NULL ) { + return numberFormat->format(number, appendTo, pos); + } + else { + replacedNumberFormat->format(number, appendTo, pos); + } + } + UnicodeString selectedRule = pluralRules->select(number); + UnicodeString *selectedPattern = (UnicodeString *)fParsedValuesHash->get(selectedRule); + if (selectedPattern==NULL) { + selectedPattern = (UnicodeString *)fParsedValuesHash->get(pluralRules->getKeywordOther()); + } + appendTo = insertFormattedNumber(number, *selectedPattern, appendTo, pos); + + return appendTo; +} + +UnicodeString& +PluralFormat::toPattern(UnicodeString& appendTo) { + appendTo+= pattern; + return appendTo; +} + +UBool +PluralFormat::inRange(UChar ch, fmtToken& type) { + if ((ch>=CAP_A) && (ch<=CAP_Z)) { + // we assume all characters are in lower case already. + return FALSE; + } + if ((ch>=LOW_A) && (ch<=LOW_Z)) { + type = tLetter; + return TRUE; + } + switch (ch) { + case LEFTBRACE: + type = tLeftBrace; + return TRUE; + case SPACE: + type = tSpace; + return TRUE; + case RIGHTBRACE: + type = tRightBrace; + return TRUE; + case NUMBER_SIGN: + type = tNumberSign; + return TRUE; + default : + type = none; + return FALSE; + } +} + +UBool +PluralFormat::checkSufficientDefinition() { + // Check that at least the default rule is defined. + if (fParsedValuesHash==NULL) return FALSE; + if (fParsedValuesHash->get(pluralRules->getKeywordOther()) == NULL) { + return FALSE; + } + else { + return TRUE; + } +} + +void +PluralFormat::setLocale(const Locale& loc, UErrorCode& status) { + if (U_FAILURE(status)) { + return; + } + if (pluralRules!=NULL) { + delete pluralRules; + pluralRules=NULL; + } + if (fParsedValuesHash!= NULL) { + delete fParsedValuesHash; + fParsedValuesHash = NULL; + } + if (numberFormat!=NULL) { + delete numberFormat; + numberFormat = NULL; + replacedNumberFormat=NULL; + } + init(NULL, loc, status); +} + +void +PluralFormat::setNumberFormat(const NumberFormat* format, UErrorCode& /*status*/) { + // TODO: The copy constructor and assignment op of NumberFormat class are protected. + // create a pointer as the workaround. + replacedNumberFormat = (NumberFormat *)format; +} + +Format* +PluralFormat::clone() const +{ + return new PluralFormat(*this); +} + +PluralFormat& +PluralFormat::operator=(const PluralFormat& other) { + if (this != &other) { + UErrorCode status = U_ZERO_ERROR; + delete pluralRules; + delete fParsedValuesHash; + delete numberFormat; + locale = other.locale; + pluralRules = other.pluralRules->clone(); + pattern = other.pattern; + copyHashtable(other.fParsedValuesHash, status); + if (U_FAILURE(status)) { + delete pluralRules; + pluralRules = NULL; + fParsedValuesHash = NULL; + numberFormat = NULL; + return *this; + } + numberFormat=NumberFormat::createInstance(locale, status); + if (U_FAILURE(status)) { + delete pluralRules; + delete fParsedValuesHash; + pluralRules = NULL; + fParsedValuesHash = NULL; + numberFormat = NULL; + return *this; + } + replacedNumberFormat=other.replacedNumberFormat; + } + + return *this; +} + +UBool +PluralFormat::operator==(const Format& other) const { + // This protected comparison operator should only be called by subclasses + // which have confirmed that the other object being compared against is + // an instance of a sublcass of PluralFormat. THIS IS IMPORTANT. + // Format::operator== guarantees that this cast is safe + PluralFormat* fmt = (PluralFormat*)&other; + return ((*pluralRules == *(fmt->pluralRules)) && + (*numberFormat == *(fmt->numberFormat))); +} + +UBool +PluralFormat::operator!=(const Format& other) const { + return !operator==(other); +} + +void +PluralFormat::parseObject(const UnicodeString& /*source*/, + Formattable& /*result*/, + ParsePosition& /*pos*/) const +{ + // TODO: not yet supported in icu4j and icu4c +} + +UnicodeString +PluralFormat::insertFormattedNumber(double number, + UnicodeString& message, + UnicodeString& appendTo, + FieldPosition& pos) const { + UnicodeString result; + int32_t braceStack=0; + int32_t startIndex=0; + + if (message.length()==0) { + return result; + } + appendTo = numberFormat->format(number, appendTo, pos); + for(int32_t i=0; i<message.length(); ++i) { + switch(message.charAt(i)) { + case LEFTBRACE: + ++braceStack; + break; + case RIGHTBRACE: + --braceStack; + break; + case NUMBER_SIGN: + if (braceStack==0) { + result += UnicodeString(message, startIndex, i); + result += appendTo; + startIndex = i + 1; + } + break; + } + } + if ( startIndex < message.length() ) { + result += UnicodeString(message, startIndex, message.length()-startIndex); + } + appendTo = result; + return result; +} + +void +PluralFormat::copyHashtable(Hashtable *other, UErrorCode& status) { + if (other == NULL || U_FAILURE(status)) { + fParsedValuesHash = NULL; + return; + } + fParsedValuesHash = new Hashtable(TRUE, status); + if(U_FAILURE(status)){ + return; + } + fParsedValuesHash->setValueDeleter(deleteHashStrings); + int32_t pos = -1; + const UHashElement* elem = NULL; + // walk through the hash table and create a deep clone + while((elem = other->nextElement(pos))!= NULL){ + const UHashTok otherKeyTok = elem->key; + UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer; + const UHashTok otherKeyToVal = elem->value; + UnicodeString* otherValue = (UnicodeString*)otherKeyToVal.pointer; + fParsedValuesHash->put(*otherKey, new UnicodeString(*otherValue), status); + if(U_FAILURE(status)){ + return; + } + } +} + + +U_NAMESPACE_END + + +#endif /* #if !UCONFIG_NO_FORMATTING */ + +//eof |