10596faeddefbf198de137d5e893708495ab1584cFredrik Roubert// © 2016 and later: Unicode, Inc. and others.
264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html
350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho/********************************************************************
427f654740f2a26ad62a5c155af9199af9e69b889claireho * COPYRIGHT:
554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius * Copyright (c) 1997-2012, International Business Machines Corporation and
650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * others. All Rights Reserved.
727f654740f2a26ad62a5c155af9199af9e69b889claireho * Copyright (C) 2010 , Yahoo! Inc.
850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho ********************************************************************
950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho *
1050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * File SELFMT.CPP
1150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho *
1250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * Modification History:
1350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho *
1450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho *   Date        Name        Description
1550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho *   11/11/09    kirtig      Finished first cut of implementation.
1627f654740f2a26ad62a5c155af9199af9e69b889claireho *   11/16/09    kirtig      Improved version
1750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho ********************************************************************/
1850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
1954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#include "utypeinfo.h"  // for 'typeid' to work
2027f654740f2a26ad62a5c155af9199af9e69b889claireho
21b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/messagepattern.h"
22b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/rbnf.h"
23b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/selfmt.h"
2450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#include "unicode/uchar.h"
25b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/ucnv_err.h"
2650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#include "unicode/umsg.h"
27b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/ustring.h"
28b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/utypes.h"
2950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#include "cmemory.h"
30b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "messageimpl.h"
31b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "patternprops.h"
32b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "selfmtimpl.h"
3350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#include "uassert.h"
3450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#include "ustrfmt.h"
35b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "util.h"
3650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#include "uvector.h"
3750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
3850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#if !UCONFIG_NO_FORMATTING
3950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
4050294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoU_NAMESPACE_BEGIN
4150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
4250294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUOBJECT_DEFINE_RTTI_IMPLEMENTATION(SelectFormat)
4350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
4450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const UChar SELECT_KEYWORD_OTHER[] = {LOW_O, LOW_T, LOW_H, LOW_E, LOW_R, 0};
4550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
46b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoSelectFormat::SelectFormat(const UnicodeString& pat,
47b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                           UErrorCode& status) : msgPattern(status) {
4850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho   applyPattern(pat, status);
4950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
5050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
51b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoSelectFormat::SelectFormat(const SelectFormat& other) : Format(other),
52b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                                        msgPattern(other.msgPattern) {
5350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
5450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
5550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoSelectFormat::~SelectFormat() {
5627f654740f2a26ad62a5c155af9199af9e69b889claireho}
5750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
5850294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehovoid
5950294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoSelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) {
6050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (U_FAILURE(status)) {
6150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      return;
6227f654740f2a26ad62a5c155af9199af9e69b889claireho    }
6350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
64b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    msgPattern.parseSelectStyle(newPattern, NULL, status);
65b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
66b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        msgPattern.clear();
6750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
6850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
6950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
7050294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUnicodeString&
7150294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoSelectFormat::format(const Formattable& obj,
7250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                   UnicodeString& appendTo,
7350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                   FieldPosition& pos,
7450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                   UErrorCode& status) const
7550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho{
76b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
77b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return appendTo;
78b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
79b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (obj.getType() == Formattable::kString) {
80b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return format(obj.getString(status), appendTo, pos, status);
81b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    } else {
82b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        status = U_ILLEGAL_ARGUMENT_ERROR;
8350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return appendTo;
8450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
8550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
8650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
8750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUnicodeString&
8850294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoSelectFormat::format(const UnicodeString& keyword,
8927f654740f2a26ad62a5c155af9199af9e69b889claireho                     UnicodeString& appendTo,
9027f654740f2a26ad62a5c155af9199af9e69b889claireho                     FieldPosition& /*pos */,
9150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                     UErrorCode& status) const {
92b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
9350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return appendTo;
9450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
95b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Check for the validity of the keyword
96b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (!PatternProps::isIdentifier(keyword.getBuffer(), keyword.length())) {
97b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        status = U_ILLEGAL_ARGUMENT_ERROR;  // Invalid formatting argument.
98b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
99b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (msgPattern.countParts() == 0) {
100b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        status = U_INVALID_STATE_ERROR;
10150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return appendTo;
10250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
103b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t msgStart = findSubMessage(msgPattern, 0, keyword, status);
104b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (!MessageImpl::jdkAposMode(msgPattern)) {
105b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        int32_t patternStart = msgPattern.getPart(msgStart).getLimit();
106b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        int32_t msgLimit = msgPattern.getLimitPartIndex(msgStart);
107b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        appendTo.append(msgPattern.getPatternString(),
108b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        patternStart,
109b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        msgPattern.getPatternIndex(msgLimit) - patternStart);
110b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return appendTo;
11150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
112b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // JDK compatibility mode: Remove SKIP_SYNTAX.
113b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return MessageImpl::appendSubMessageWithoutSkipSyntax(msgPattern, msgStart, appendTo);
11450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
11550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
11650294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUnicodeString&
11750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoSelectFormat::toPattern(UnicodeString& appendTo) {
118b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (0 == msgPattern.countParts()) {
119b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        appendTo.setToBogus();
120b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    } else {
121b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        appendTo.append(msgPattern.getPatternString());
12250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
123b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return appendTo;
12450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
12550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
12650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
127b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoint32_t SelectFormat::findSubMessage(const MessagePattern& pattern, int32_t partIndex,
128b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                     const UnicodeString& keyword, UErrorCode& ec) {
129b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(ec)) {
130b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return 0;
13150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
132b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString other(FALSE, SELECT_KEYWORD_OTHER, 5);
133b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t count = pattern.countParts();
134b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t msgStart=0;
135b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Iterate over (ARG_SELECTOR, message) pairs until ARG_LIMIT or end of select-only pattern.
136b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    do {
137b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        const MessagePattern::Part& part=pattern.getPart(partIndex++);
138b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        const UMessagePatternPartType type=part.getType();
139b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
140b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            break;
14150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
142b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // part is an ARG_SELECTOR followed by a message
143b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if(pattern.partSubstringMatches(part, keyword)) {
144b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // keyword matches
145b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            return partIndex;
146b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        } else if(msgStart==0 && pattern.partSubstringMatches(part, other)) {
147b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            msgStart=partIndex;
148b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
149b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        partIndex=pattern.getLimitPartIndex(partIndex);
150b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    } while(++partIndex<count);
151b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return msgStart;
15250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
15350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
15450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoFormat* SelectFormat::clone() const
15550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho{
15650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return new SelectFormat(*this);
15750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
15850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
15950294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoSelectFormat&
16050294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoSelectFormat::operator=(const SelectFormat& other) {
16150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (this != &other) {
162b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        msgPattern = other.msgPattern;
16350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
16450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return *this;
16550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
16650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
16750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUBool
16850294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoSelectFormat::operator==(const Format& other) const {
169b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (this == &other) {
17050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return TRUE;
17150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
172b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (!Format::operator==(other)) {
17350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return FALSE;
174b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
175b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const SelectFormat& o = (const SelectFormat&)other;
176b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return msgPattern == o.msgPattern;
17750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
17850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
17950294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUBool
18050294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoSelectFormat::operator!=(const Format& other) const {
18150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return  !operator==(other);
18250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
18350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
18450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehovoid
18550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoSelectFormat::parseObject(const UnicodeString& /*source*/,
18650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        Formattable& /*result*/,
18750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        ParsePosition& pos) const
18850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho{
189b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Parsing not supported.
19050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    pos.setErrorIndex(pos.getIndex());
19150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
19250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
19350294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoU_NAMESPACE_END
19450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
19550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#endif /* #if !UCONFIG_NO_FORMATTING */
19650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
19750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho//eof
198