michael@0: /******************************************************************** michael@0: * COPYRIGHT: michael@0: * Copyright (c) 1997-2012, International Business Machines Corporation and michael@0: * others. All Rights Reserved. michael@0: * Copyright (C) 2010 , Yahoo! Inc. michael@0: ******************************************************************** michael@0: * michael@0: * File SELFMT.CPP michael@0: * michael@0: * Modification History: michael@0: * michael@0: * Date Name Description michael@0: * 11/11/09 kirtig Finished first cut of implementation. michael@0: * 11/16/09 kirtig Improved version michael@0: ********************************************************************/ michael@0: michael@0: #include "utypeinfo.h" // for 'typeid' to work michael@0: michael@0: #include "unicode/messagepattern.h" michael@0: #include "unicode/rbnf.h" michael@0: #include "unicode/selfmt.h" michael@0: #include "unicode/uchar.h" michael@0: #include "unicode/ucnv_err.h" michael@0: #include "unicode/umsg.h" michael@0: #include "unicode/ustring.h" michael@0: #include "unicode/utypes.h" michael@0: #include "cmemory.h" michael@0: #include "messageimpl.h" michael@0: #include "patternprops.h" michael@0: #include "selfmtimpl.h" michael@0: #include "uassert.h" michael@0: #include "ustrfmt.h" michael@0: #include "util.h" michael@0: #include "uvector.h" michael@0: michael@0: #if !UCONFIG_NO_FORMATTING michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SelectFormat) michael@0: michael@0: static const UChar SELECT_KEYWORD_OTHER[] = {LOW_O, LOW_T, LOW_H, LOW_E, LOW_R, 0}; michael@0: michael@0: SelectFormat::SelectFormat(const UnicodeString& pat, michael@0: UErrorCode& status) : msgPattern(status) { michael@0: applyPattern(pat, status); michael@0: } michael@0: michael@0: SelectFormat::SelectFormat(const SelectFormat& other) : Format(other), michael@0: msgPattern(other.msgPattern) { michael@0: } michael@0: michael@0: SelectFormat::~SelectFormat() { michael@0: } michael@0: michael@0: void michael@0: SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) { michael@0: if (U_FAILURE(status)) { michael@0: return; michael@0: } michael@0: michael@0: msgPattern.parseSelectStyle(newPattern, NULL, status); michael@0: if (U_FAILURE(status)) { michael@0: msgPattern.clear(); michael@0: } michael@0: } michael@0: michael@0: UnicodeString& michael@0: SelectFormat::format(const Formattable& obj, michael@0: UnicodeString& appendTo, michael@0: FieldPosition& pos, michael@0: UErrorCode& status) const michael@0: { michael@0: if (U_FAILURE(status)) { michael@0: return appendTo; michael@0: } michael@0: if (obj.getType() == Formattable::kString) { michael@0: return format(obj.getString(status), appendTo, pos, status); michael@0: } else { michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return appendTo; michael@0: } michael@0: } michael@0: michael@0: UnicodeString& michael@0: SelectFormat::format(const UnicodeString& keyword, michael@0: UnicodeString& appendTo, michael@0: FieldPosition& /*pos */, michael@0: UErrorCode& status) const { michael@0: if (U_FAILURE(status)) { michael@0: return appendTo; michael@0: } michael@0: // Check for the validity of the keyword michael@0: if (!PatternProps::isIdentifier(keyword.getBuffer(), keyword.length())) { michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; // Invalid formatting argument. michael@0: } michael@0: if (msgPattern.countParts() == 0) { michael@0: status = U_INVALID_STATE_ERROR; michael@0: return appendTo; michael@0: } michael@0: int32_t msgStart = findSubMessage(msgPattern, 0, keyword, status); michael@0: if (!MessageImpl::jdkAposMode(msgPattern)) { michael@0: int32_t patternStart = msgPattern.getPart(msgStart).getLimit(); michael@0: int32_t msgLimit = msgPattern.getLimitPartIndex(msgStart); michael@0: appendTo.append(msgPattern.getPatternString(), michael@0: patternStart, michael@0: msgPattern.getPatternIndex(msgLimit) - patternStart); michael@0: return appendTo; michael@0: } michael@0: // JDK compatibility mode: Remove SKIP_SYNTAX. michael@0: return MessageImpl::appendSubMessageWithoutSkipSyntax(msgPattern, msgStart, appendTo); michael@0: } michael@0: michael@0: UnicodeString& michael@0: SelectFormat::toPattern(UnicodeString& appendTo) { michael@0: if (0 == msgPattern.countParts()) { michael@0: appendTo.setToBogus(); michael@0: } else { michael@0: appendTo.append(msgPattern.getPatternString()); michael@0: } michael@0: return appendTo; michael@0: } michael@0: michael@0: michael@0: int32_t SelectFormat::findSubMessage(const MessagePattern& pattern, int32_t partIndex, michael@0: const UnicodeString& keyword, UErrorCode& ec) { michael@0: if (U_FAILURE(ec)) { michael@0: return 0; michael@0: } michael@0: UnicodeString other(FALSE, SELECT_KEYWORD_OTHER, 5); michael@0: int32_t count = pattern.countParts(); michael@0: int32_t msgStart=0; michael@0: // Iterate over (ARG_SELECTOR, message) pairs until ARG_LIMIT or end of select-only pattern. michael@0: do { michael@0: const MessagePattern::Part& part=pattern.getPart(partIndex++); michael@0: const UMessagePatternPartType type=part.getType(); michael@0: if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) { michael@0: break; michael@0: } michael@0: // part is an ARG_SELECTOR followed by a message michael@0: if(pattern.partSubstringMatches(part, keyword)) { michael@0: // keyword matches michael@0: return partIndex; michael@0: } else if(msgStart==0 && pattern.partSubstringMatches(part, other)) { michael@0: msgStart=partIndex; michael@0: } michael@0: partIndex=pattern.getLimitPartIndex(partIndex); michael@0: } while(++partIndex