/******************************************************************** * COPYRIGHT: * Copyright (c) 1997-2012, 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 "utypeinfo.h" // for 'typeid' to work #include "unicode/messagepattern.h" #include "unicode/rbnf.h" #include "unicode/selfmt.h" #include "unicode/uchar.h" #include "unicode/ucnv_err.h" #include "unicode/umsg.h" #include "unicode/ustring.h" #include "unicode/utypes.h" #include "cmemory.h" #include "messageimpl.h" #include "patternprops.h" #include "selfmtimpl.h" #include "uassert.h" #include "ustrfmt.h" #include "util.h" #include "uvector.h" #if !UCONFIG_NO_FORMATTING U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SelectFormat) static const UChar SELECT_KEYWORD_OTHER[] = {LOW_O, LOW_T, LOW_H, LOW_E, LOW_R, 0}; SelectFormat::SelectFormat(const UnicodeString& pat, UErrorCode& status) : msgPattern(status) { applyPattern(pat, status); } SelectFormat::SelectFormat(const SelectFormat& other) : Format(other), msgPattern(other.msgPattern) { } SelectFormat::~SelectFormat() { } void SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) { if (U_FAILURE(status)) { return; } msgPattern.parseSelectStyle(newPattern, NULL, status); if (U_FAILURE(status)) { msgPattern.clear(); } } UnicodeString& SelectFormat::format(const Formattable& obj, UnicodeString& appendTo, FieldPosition& pos, UErrorCode& status) const { if (U_FAILURE(status)) { return appendTo; } if (obj.getType() == Formattable::kString) { return format(obj.getString(status), appendTo, pos, status); } else { 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; } // Check for the validity of the keyword if (!PatternProps::isIdentifier(keyword.getBuffer(), keyword.length())) { status = U_ILLEGAL_ARGUMENT_ERROR; // Invalid formatting argument. } if (msgPattern.countParts() == 0) { status = U_INVALID_STATE_ERROR; return appendTo; } int32_t msgStart = findSubMessage(msgPattern, 0, keyword, status); if (!MessageImpl::jdkAposMode(msgPattern)) { int32_t patternStart = msgPattern.getPart(msgStart).getLimit(); int32_t msgLimit = msgPattern.getLimitPartIndex(msgStart); appendTo.append(msgPattern.getPatternString(), patternStart, msgPattern.getPatternIndex(msgLimit) - patternStart); return appendTo; } // JDK compatibility mode: Remove SKIP_SYNTAX. return MessageImpl::appendSubMessageWithoutSkipSyntax(msgPattern, msgStart, appendTo); } UnicodeString& SelectFormat::toPattern(UnicodeString& appendTo) { if (0 == msgPattern.countParts()) { appendTo.setToBogus(); } else { appendTo.append(msgPattern.getPatternString()); } return appendTo; } int32_t SelectFormat::findSubMessage(const MessagePattern& pattern, int32_t partIndex, const UnicodeString& keyword, UErrorCode& ec) { if (U_FAILURE(ec)) { return 0; } UnicodeString other(FALSE, SELECT_KEYWORD_OTHER, 5); int32_t count = pattern.countParts(); int32_t msgStart=0; // Iterate over (ARG_SELECTOR, message) pairs until ARG_LIMIT or end of select-only pattern. do { const MessagePattern::Part& part=pattern.getPart(partIndex++); const UMessagePatternPartType type=part.getType(); if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) { break; } // part is an ARG_SELECTOR followed by a message if(pattern.partSubstringMatches(part, keyword)) { // keyword matches return partIndex; } else if(msgStart==0 && pattern.partSubstringMatches(part, other)) { msgStart=partIndex; } partIndex=pattern.getLimitPartIndex(partIndex); } while(++partIndex