Home | History | Annotate | Download | only in i18n
      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 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