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