16f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/********************************************************************
26f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * COPYRIGHT:
36f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Copyright (c) 1997-2012, International Business Machines Corporation and
46f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * others. All Rights Reserved.
56f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Copyright (C) 2010 , Yahoo! Inc.
66f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org ********************************************************************
76f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
86f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * File SELFMT.CPP
96f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Modification History:
116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   Date        Name        Description
136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   11/11/09    kirtig      Finished first cut of implementation.
146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   11/16/09    kirtig      Improved version
156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org ********************************************************************/
166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "utypeinfo.h"  // for 'typeid' to work
186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/messagepattern.h"
206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/rbnf.h"
216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/selfmt.h"
226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/uchar.h"
236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/ucnv_err.h"
246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/umsg.h"
256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/ustring.h"
266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/utypes.h"
276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "cmemory.h"
286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "messageimpl.h"
296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "patternprops.h"
306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "selfmtimpl.h"
316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uassert.h"
326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "ustrfmt.h"
336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "util.h"
346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uvector.h"
356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !UCONFIG_NO_FORMATTING
376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_NAMESPACE_BEGIN
396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUOBJECT_DEFINE_RTTI_IMPLEMENTATION(SelectFormat)
416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar SELECT_KEYWORD_OTHER[] = {LOW_O, LOW_T, LOW_H, LOW_E, LOW_R, 0};
436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat::SelectFormat(const UnicodeString& pat,
456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           UErrorCode& status) : msgPattern(status) {
466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org   applyPattern(pat, status);
476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat::SelectFormat(const SelectFormat& other) : Format(other),
506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                        msgPattern(other.msgPattern) {
516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat::~SelectFormat() {
546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) {
586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return;
606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    msgPattern.parseSelectStyle(newPattern, NULL, status);
636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        msgPattern.clear();
656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat::format(const Formattable& obj,
706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                   UnicodeString& appendTo,
716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                   FieldPosition& pos,
726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                   UErrorCode& status) const
736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (obj.getType() == Formattable::kString) {
786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return format(obj.getString(status), appendTo, pos, status);
796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_ILLEGAL_ARGUMENT_ERROR;
816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat::format(const UnicodeString& keyword,
876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     UnicodeString& appendTo,
886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     FieldPosition& /*pos */,
896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     UErrorCode& status) const {
906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Check for the validity of the keyword
946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!PatternProps::isIdentifier(keyword.getBuffer(), keyword.length())) {
956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_ILLEGAL_ARGUMENT_ERROR;  // Invalid formatting argument.
966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (msgPattern.countParts() == 0) {
986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_INVALID_STATE_ERROR;
996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
1006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t msgStart = findSubMessage(msgPattern, 0, keyword, status);
1026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!MessageImpl::jdkAposMode(msgPattern)) {
1036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t patternStart = msgPattern.getPart(msgStart).getLimit();
1046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t msgLimit = msgPattern.getLimitPartIndex(msgStart);
1056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        appendTo.append(msgPattern.getPatternString(),
1066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        patternStart,
1076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        msgPattern.getPatternIndex(msgLimit) - patternStart);
1086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
1096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // JDK compatibility mode: Remove SKIP_SYNTAX.
1116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return MessageImpl::appendSubMessageWithoutSkipSyntax(msgPattern, msgStart, appendTo);
1126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
1156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat::toPattern(UnicodeString& appendTo) {
1166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (0 == msgPattern.countParts()) {
1176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        appendTo.setToBogus();
1186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
1196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        appendTo.append(msgPattern.getPatternString());
1206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return appendTo;
1226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t SelectFormat::findSubMessage(const MessagePattern& pattern, int32_t partIndex,
1266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                     const UnicodeString& keyword, UErrorCode& ec) {
1276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(ec)) {
1286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return 0;
1296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString other(FALSE, SELECT_KEYWORD_OTHER, 5);
1316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t count = pattern.countParts();
1326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t msgStart=0;
1336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Iterate over (ARG_SELECTOR, message) pairs until ARG_LIMIT or end of select-only pattern.
1346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    do {
1356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern::Part& part=pattern.getPart(partIndex++);
1366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const UMessagePatternPartType type=part.getType();
1376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
1386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
1396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
1406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // part is an ARG_SELECTOR followed by a message
1416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(pattern.partSubstringMatches(part, keyword)) {
1426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // keyword matches
1436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return partIndex;
1446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if(msgStart==0 && pattern.partSubstringMatches(part, other)) {
1456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            msgStart=partIndex;
1466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
1476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        partIndex=pattern.getLimitPartIndex(partIndex);
1486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } while(++partIndex<count);
1496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return msgStart;
1506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormat* SelectFormat::clone() const
1536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return new SelectFormat(*this);
1556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat&
1586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat::operator=(const SelectFormat& other) {
1596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (this != &other) {
1606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        msgPattern = other.msgPattern;
1616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return *this;
1636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUBool
1666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat::operator==(const Format& other) const {
1676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (this == &other) {
1686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return TRUE;
1696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!Format::operator==(other)) {
1716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return FALSE;
1726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const SelectFormat& o = (const SelectFormat&)other;
1746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return msgPattern == o.msgPattern;
1756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUBool
1786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat::operator!=(const Format& other) const {
1796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return  !operator==(other);
1806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
1836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgSelectFormat::parseObject(const UnicodeString& /*source*/,
1846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        Formattable& /*result*/,
1856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        ParsePosition& pos) const
1866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Parsing not supported.
1886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pos.setErrorIndex(pos.getIndex());
1896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_NAMESPACE_END
1926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif /* #if !UCONFIG_NO_FORMATTING */
1946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//eof
196