| 1 | // © 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 | SelectFormat* 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 |  | 
|---|