Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Unified Diff: icu46/source/i18n/selfmt.cpp

Issue 5516007: Check in the pristine copy of ICU 4.6... (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/third_party/
Patch Set: Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « icu46/source/i18n/search.cpp ('k') | icu46/source/i18n/selfmtimpl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: icu46/source/i18n/selfmt.cpp
===================================================================
--- icu46/source/i18n/selfmt.cpp (revision 0)
+++ icu46/source/i18n/selfmt.cpp (revision 0)
@@ -0,0 +1,447 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2010, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ * Copyright (C) 2010 , Yahoo! Inc.
+ ********************************************************************
+ *
+ * File SELFMT.CPP
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 11/11/09 kirtig Finished first cut of implementation.
+ * 11/16/09 kirtig Improved version
+ ********************************************************************/
+
+#include <typeinfo> // for 'typeid' to work
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "unicode/ucnv_err.h"
+#include "unicode/uchar.h"
+#include "unicode/umsg.h"
+#include "unicode/rbnf.h"
+#include "cmemory.h"
+#include "util.h"
+#include "uassert.h"
+#include "ustrfmt.h"
+#include "uvector.h"
+
+#include "unicode/selfmt.h"
+#include "selfmtimpl.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+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) : parsedValuesHash(NULL) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ initHashTable(status);
+ applyPattern(pat, status);
+}
+
+SelectFormat::SelectFormat(const SelectFormat& other) : Format(other), parsedValuesHash(NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ pattern = other.pattern;
+ copyHashtable(other.parsedValuesHash, status);
+}
+
+SelectFormat::~SelectFormat() {
+ cleanHashTable();
+}
+
+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;
+ }
+ }
+ // 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;
+ }
+
+ pattern = newPattern;
+ enum State{ startState, keywordState, pastKeywordState, phraseState};
+
+ //Initialization
+ UnicodeString keyword ;
+ UnicodeString phrase ;
+ UnicodeString* ptrPhrase ;
+ int32_t braceCount = 0;
+
+ if (parsedValuesHash == NULL) {
+ initHashTable(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ parsedValuesHash->removeAll();
+ parsedValuesHash->setValueDeleter(uhash_deleteUnicodeString);
+
+ //Process the state machine
+ State state = startState;
+ 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);
+
+ //Allow any character in phrase but nowhere else
+ if ( type == tOther ) {
+ if ( state == phraseState ){
+ phrase += ch;
+ continue;
+ }else {
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+ }
+ }
+
+ //Process the state machine
+ switch (state) {
+ //At the start of pattern
+ case startState:
+ switch (type) {
+ case tSpace:
+ break;
+ case tStartKeyword:
+ state = keywordState;
+ keyword += ch;
+ break;
+ //If anything else is encountered, it's a syntax error
+ default:
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+ }//end of switch(type)
+ break;
+
+ //Handle the keyword state
+ case keywordState:
+ switch (type) {
+ case tSpace:
+ state = pastKeywordState;
+ break;
+ case tStartKeyword:
+ case tContinueKeyword:
+ keyword += ch;
+ break;
+ case tLeftBrace:
+ state = phraseState;
+ break;
+ //If anything else is encountered, it's a syntax error
+ default:
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+ }//end of switch(type)
+ break;
+
+ //Handle the pastkeyword state
+ case pastKeywordState:
+ switch (type) {
+ case tSpace:
+ break;
+ case tLeftBrace:
+ state = phraseState;
+ break;
+ //If anything else is encountered, it's a syntax error
+ default:
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+ }//end of switch(type)
+ break;
+
+ //Handle the phrase state
+ case phraseState:
+ switch (type) {
+ case tLeftBrace:
+ braceCount++;
+ phrase += ch;
+ break;
+ case tRightBrace:
+ //Matching keyword, phrase pair found
+ if (braceCount == 0){
+ //Check validity of keyword
+ if (parsedValuesHash->get(keyword) != NULL) {
+ status = U_DUPLICATE_KEYWORD;
+ cleanHashTable();
+ return;
+ }
+ if (keyword.length() == 0) {
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+ }
+
+ //Store the keyword, phrase pair in hashTable
+ ptrPhrase = new UnicodeString(phrase);
+ parsedValuesHash->put( keyword, ptrPhrase, status);
+
+ //Reinitialize
+ keyword.remove();
+ phrase.remove();
+ ptrPhrase = NULL;
+ state = startState;
+ }
+
+ if (braceCount > 0){
+ braceCount-- ;
+ phrase += ch;
+ }
+ break;
+ default:
+ phrase += ch;
+ }//end of switch(type)
+ break;
+
+ //Handle the default case of switch(state)
+ default:
+ status = U_PATTERN_SYNTAX_ERROR;
+ cleanHashTable();
+ return;
+
+ }//end of switch(state)
+ }
+
+ //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
+ if ( !checkSufficientDefinition() ) {
+ status = U_DEFAULT_KEYWORD_MISSING;
+ cleanHashTable();
+ }
+ return;
+}
+
+UnicodeString&
+SelectFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ switch (obj.getType())
+ {
+ case Formattable::kString:
+ return format(obj.getString(), appendTo, pos, status);
+ default:
+ if( U_SUCCESS(status) ){
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return appendTo;
+ }
+}
+
+UnicodeString&
+SelectFormat::format(const UnicodeString& keyword,
+ 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;
+ }
+
+ UnicodeString *selectedPattern = (UnicodeString *)parsedValuesHash->get(keyword);
+ if (selectedPattern == NULL) {
+ selectedPattern = (UnicodeString *)parsedValuesHash->get(SELECT_KEYWORD_OTHER);
+ }
+
+ return appendTo += *selectedPattern;
+}
+
+UnicodeString&
+SelectFormat::toPattern(UnicodeString& appendTo) {
+ return appendTo += pattern;
+}
+
+SelectFormat::CharacterClass
+SelectFormat::classifyCharacter(UChar ch) const{
+ if ((ch >= CAP_A) && (ch <= CAP_Z)) {
+ return tStartKeyword;
+ }
+ if ((ch >= LOW_A) && (ch <= LOW_Z)) {
+ return tStartKeyword;
+ }
+ if ((ch >= U_ZERO) && (ch <= U_NINE)) {
+ return tContinueKeyword;
+ }
+ if ( uprv_isRuleWhiteSpace(ch) ){
+ return tSpace;
+ }
+ switch (ch) {
+ case LEFTBRACE:
+ return tLeftBrace;
+ case RIGHTBRACE:
+ return tRightBrace;
+ case HYPHEN:
+ case LOWLINE:
+ return tContinueKeyword;
+ default :
+ return tOther;
+ }
+}
+
+UBool
+SelectFormat::checkSufficientDefinition() {
+ // Check that at least the default rule is defined.
+ return (parsedValuesHash != NULL &&
+ parsedValuesHash->get(SELECT_KEYWORD_OTHER) != NULL) ;
+}
+
+UBool
+SelectFormat::checkValidKeyword(const UnicodeString& argKeyword ) const{
+ int32_t len = argKeyword.length();
+ if (len < 1){
+ return FALSE;
+ }
+ 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));
+ if( type != tStartKeyword && type != tContinueKeyword ){
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+Format* SelectFormat::clone() const
+{
+ return new SelectFormat(*this);
+}
+
+SelectFormat&
+SelectFormat::operator=(const SelectFormat& other) {
+ if (this != &other) {
+ UErrorCode status = U_ZERO_ERROR;
+ pattern = other.pattern;
+ copyHashtable(other.parsedValuesHash, status);
+ }
+ return *this;
+}
+
+UBool
+SelectFormat::operator==(const Format& other) const {
+ if( this == &other){
+ return TRUE;
+ }
+ if (typeid(*this) != typeid(other)) {
+ return FALSE;
+ }
+ SelectFormat* fmt = (SelectFormat*)&other;
+ Hashtable* hashOther = fmt->parsedValuesHash;
+ if ( parsedValuesHash == NULL && hashOther == NULL)
+ return TRUE;
+ if ( parsedValuesHash == NULL || hashOther == NULL)
+ return FALSE;
+ return parsedValuesHash->equals(*hashOther);
+}
+
+UBool
+SelectFormat::operator!=(const Format& other) const {
+ return !operator==(other);
+}
+
+void
+SelectFormat::parseObject(const UnicodeString& /*source*/,
+ Formattable& /*result*/,
+ ParsePosition& pos) const
+{
+ // TODO: not yet supported in icu4j and icu4c
+ pos.setErrorIndex(pos.getIndex());
+}
+
+void
+SelectFormat::copyHashtable(Hashtable *other, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (other == NULL) {
+ cleanHashTable();
+ return;
+ }
+ if (parsedValuesHash == NULL) {
+ initHashTable(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+
+ parsedValuesHash->removeAll();
+ parsedValuesHash->setValueDeleter(uhash_deleteUnicodeString);
+
+ 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;
+ parsedValuesHash->put(*otherKey, new UnicodeString(*otherValue), status);
+ if (U_FAILURE(status)){
+ cleanHashTable();
+ return;
+ }
+ }
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
Property changes on: icu46/source/i18n/selfmt.cpp
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:eol-style
+ LF
« no previous file with comments | « icu46/source/i18n/search.cpp ('k') | icu46/source/i18n/selfmtimpl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698