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