1 /******************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 1997-2012, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 * Copyright (C) 2010 , Yahoo! Inc. 6 ******************************************************************** 7 * 8 * File SELFMT.CPP 9 * 10 * Modification History: 11 * 12 * Date Name Description 13 * 11/11/09 kirtig Finished first cut of implementation. 14 * 11/16/09 kirtig Improved version 15 ********************************************************************/ 16 17 #include "utypeinfo.h" // for 'typeid' to work 18 19 #include "unicode/messagepattern.h" 20 #include "unicode/rbnf.h" 21 #include "unicode/selfmt.h" 22 #include "unicode/uchar.h" 23 #include "unicode/ucnv_err.h" 24 #include "unicode/umsg.h" 25 #include "unicode/ustring.h" 26 #include "unicode/utypes.h" 27 #include "cmemory.h" 28 #include "messageimpl.h" 29 #include "patternprops.h" 30 #include "selfmtimpl.h" 31 #include "uassert.h" 32 #include "ustrfmt.h" 33 #include "util.h" 34 #include "uvector.h" 35 36 #if !UCONFIG_NO_FORMATTING 37 38 U_NAMESPACE_BEGIN 39 40 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SelectFormat) 41 42 static const UChar SELECT_KEYWORD_OTHER[] = {LOW_O, LOW_T, LOW_H, LOW_E, LOW_R, 0}; 43 44 SelectFormat::SelectFormat(const UnicodeString& pat, 45 UErrorCode& status) : msgPattern(status) { 46 applyPattern(pat, status); 47 } 48 49 SelectFormat::SelectFormat(const SelectFormat& other) : Format(other), 50 msgPattern(other.msgPattern) { 51 } 52 53 SelectFormat::~SelectFormat() { 54 } 55 56 void 57 SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) { 58 if (U_FAILURE(status)) { 59 return; 60 } 61 62 msgPattern.parseSelectStyle(newPattern, NULL, status); 63 if (U_FAILURE(status)) { 64 msgPattern.clear(); 65 } 66 } 67 68 UnicodeString& 69 SelectFormat::format(const Formattable& obj, 70 UnicodeString& appendTo, 71 FieldPosition& pos, 72 UErrorCode& status) const 73 { 74 if (U_FAILURE(status)) { 75 return appendTo; 76 } 77 if (obj.getType() == Formattable::kString) { 78 return format(obj.getString(status), appendTo, pos, status); 79 } else { 80 status = U_ILLEGAL_ARGUMENT_ERROR; 81 return appendTo; 82 } 83 } 84 85 UnicodeString& 86 SelectFormat::format(const UnicodeString& keyword, 87 UnicodeString& appendTo, 88 FieldPosition& /*pos */, 89 UErrorCode& status) const { 90 if (U_FAILURE(status)) { 91 return appendTo; 92 } 93 // Check for the validity of the keyword 94 if (!PatternProps::isIdentifier(keyword.getBuffer(), keyword.length())) { 95 status = U_ILLEGAL_ARGUMENT_ERROR; // Invalid formatting argument. 96 } 97 if (msgPattern.countParts() == 0) { 98 status = U_INVALID_STATE_ERROR; 99 return appendTo; 100 } 101 int32_t msgStart = findSubMessage(msgPattern, 0, keyword, status); 102 if (!MessageImpl::jdkAposMode(msgPattern)) { 103 int32_t patternStart = msgPattern.getPart(msgStart).getLimit(); 104 int32_t msgLimit = msgPattern.getLimitPartIndex(msgStart); 105 appendTo.append(msgPattern.getPatternString(), 106 patternStart, 107 msgPattern.getPatternIndex(msgLimit) - patternStart); 108 return appendTo; 109 } 110 // JDK compatibility mode: Remove SKIP_SYNTAX. 111 return MessageImpl::appendSubMessageWithoutSkipSyntax(msgPattern, msgStart, appendTo); 112 } 113 114 UnicodeString& 115 SelectFormat::toPattern(UnicodeString& appendTo) { 116 if (0 == msgPattern.countParts()) { 117 appendTo.setToBogus(); 118 } else { 119 appendTo.append(msgPattern.getPatternString()); 120 } 121 return appendTo; 122 } 123 124 125 int32_t SelectFormat::findSubMessage(const MessagePattern& pattern, int32_t partIndex, 126 const UnicodeString& keyword, UErrorCode& ec) { 127 if (U_FAILURE(ec)) { 128 return 0; 129 } 130 UnicodeString other(FALSE, SELECT_KEYWORD_OTHER, 5); 131 int32_t count = pattern.countParts(); 132 int32_t msgStart=0; 133 // Iterate over (ARG_SELECTOR, message) pairs until ARG_LIMIT or end of select-only pattern. 134 do { 135 const MessagePattern::Part& part=pattern.getPart(partIndex++); 136 const UMessagePatternPartType type=part.getType(); 137 if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) { 138 break; 139 } 140 // part is an ARG_SELECTOR followed by a message 141 if(pattern.partSubstringMatches(part, keyword)) { 142 // keyword matches 143 return partIndex; 144 } else if(msgStart==0 && pattern.partSubstringMatches(part, other)) { 145 msgStart=partIndex; 146 } 147 partIndex=pattern.getLimitPartIndex(partIndex); 148 } while(++partIndex<count); 149 return msgStart; 150 } 151 152 Format* SelectFormat::clone() const 153 { 154 return new SelectFormat(*this); 155 } 156 157 SelectFormat& 158 SelectFormat::operator=(const SelectFormat& other) { 159 if (this != &other) { 160 msgPattern = other.msgPattern; 161 } 162 return *this; 163 } 164 165 UBool 166 SelectFormat::operator==(const Format& other) const { 167 if (this == &other) { 168 return TRUE; 169 } 170 if (!Format::operator==(other)) { 171 return FALSE; 172 } 173 const SelectFormat& o = (const SelectFormat&)other; 174 return msgPattern == o.msgPattern; 175 } 176 177 UBool 178 SelectFormat::operator!=(const Format& other) const { 179 return !operator==(other); 180 } 181 182 void 183 SelectFormat::parseObject(const UnicodeString& /*source*/, 184 Formattable& /*result*/, 185 ParsePosition& pos) const 186 { 187 // Parsing not supported. 188 pos.setErrorIndex(pos.getIndex()); 189 } 190 191 U_NAMESPACE_END 192 193 #endif /* #if !UCONFIG_NO_FORMATTING */ 194 195 //eof 196