Coverage Report

Created: 2025-06-24 06:43

/src/icu/source/i18n/selfmt.cpp
Line
Count
Source (jump to first uncovered line)
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
0
                           UErrorCode& status) : msgPattern(status) {
48
0
   applyPattern(pat, status);
49
0
}
50
51
0
SelectFormat::SelectFormat(const SelectFormat& other) : Format(other),
52
0
                                                        msgPattern(other.msgPattern) {
53
0
}
54
55
0
SelectFormat::~SelectFormat() {
56
0
}
57
58
void
59
0
SelectFormat::applyPattern(const UnicodeString& newPattern, UErrorCode& status) {
60
0
    if (U_FAILURE(status)) {
61
0
      return;
62
0
    }
63
64
0
    msgPattern.parseSelectStyle(newPattern, NULL, status);
65
0
    if (U_FAILURE(status)) {
66
0
        msgPattern.clear();
67
0
    }
68
0
}
69
70
UnicodeString&
71
SelectFormat::format(const Formattable& obj,
72
                   UnicodeString& appendTo,
73
                   FieldPosition& pos,
74
                   UErrorCode& status) const
75
0
{
76
0
    if (U_FAILURE(status)) {
77
0
        return appendTo;
78
0
    }
79
0
    if (obj.getType() == Formattable::kString) {
80
0
        return format(obj.getString(status), appendTo, pos, status);
81
0
    } else {
82
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
83
0
        return appendTo;
84
0
    }
85
0
}
86
87
UnicodeString&
88
SelectFormat::format(const UnicodeString& keyword,
89
                     UnicodeString& appendTo,
90
                     FieldPosition& /*pos */,
91
0
                     UErrorCode& status) const {
92
0
    if (U_FAILURE(status)) {
93
0
        return appendTo;
94
0
    }
95
    // Check for the validity of the keyword
96
0
    if (!PatternProps::isIdentifier(keyword.getBuffer(), keyword.length())) {
97
0
        status = U_ILLEGAL_ARGUMENT_ERROR;  // Invalid formatting argument.
98
0
    }
99
0
    if (msgPattern.countParts() == 0) {
100
0
        status = U_INVALID_STATE_ERROR;
101
0
        return appendTo;
102
0
    }
103
0
    int32_t msgStart = findSubMessage(msgPattern, 0, keyword, status);
104
0
    if (!MessageImpl::jdkAposMode(msgPattern)) {
105
0
        int32_t patternStart = msgPattern.getPart(msgStart).getLimit();
106
0
        int32_t msgLimit = msgPattern.getLimitPartIndex(msgStart);
107
0
        appendTo.append(msgPattern.getPatternString(),
108
0
                        patternStart,
109
0
                        msgPattern.getPatternIndex(msgLimit) - patternStart);
110
0
        return appendTo;
111
0
    }
112
    // JDK compatibility mode: Remove SKIP_SYNTAX.
113
0
    return MessageImpl::appendSubMessageWithoutSkipSyntax(msgPattern, msgStart, appendTo);
114
0
}
115
116
UnicodeString&
117
0
SelectFormat::toPattern(UnicodeString& appendTo) {
118
0
    if (0 == msgPattern.countParts()) {
119
0
        appendTo.setToBogus();
120
0
    } else {
121
0
        appendTo.append(msgPattern.getPatternString());
122
0
    }
123
0
    return appendTo;
124
0
}
125
126
127
int32_t SelectFormat::findSubMessage(const MessagePattern& pattern, int32_t partIndex,
128
0
                                     const UnicodeString& keyword, UErrorCode& ec) {
129
0
    if (U_FAILURE(ec)) {
130
0
        return 0;
131
0
    }
132
0
    UnicodeString other(FALSE, SELECT_KEYWORD_OTHER, 5);
133
0
    int32_t count = pattern.countParts();
134
0
    int32_t msgStart=0;
135
    // Iterate over (ARG_SELECTOR, message) pairs until ARG_LIMIT or end of select-only pattern.
136
0
    do {
137
0
        const MessagePattern::Part& part=pattern.getPart(partIndex++);
138
0
        const UMessagePatternPartType type=part.getType();
139
0
        if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
140
0
            break;
141
0
        }
142
        // part is an ARG_SELECTOR followed by a message
143
0
        if(pattern.partSubstringMatches(part, keyword)) {
144
            // keyword matches
145
0
            return partIndex;
146
0
        } else if(msgStart==0 && pattern.partSubstringMatches(part, other)) {
147
0
            msgStart=partIndex;
148
0
        }
149
0
        partIndex=pattern.getLimitPartIndex(partIndex);
150
0
    } while(++partIndex<count);
151
0
    return msgStart;
152
0
}
153
154
SelectFormat* SelectFormat::clone() const
155
0
{
156
0
    return new SelectFormat(*this);
157
0
}
158
159
SelectFormat&
160
0
SelectFormat::operator=(const SelectFormat& other) {
161
0
    if (this != &other) {
162
0
        msgPattern = other.msgPattern;
163
0
    }
164
0
    return *this;
165
0
}
166
167
bool
168
0
SelectFormat::operator==(const Format& other) const {
169
0
    if (this == &other) {
170
0
        return TRUE;
171
0
    }
172
0
    if (!Format::operator==(other)) {
173
0
        return FALSE;
174
0
    }
175
0
    const SelectFormat& o = (const SelectFormat&)other;
176
0
    return msgPattern == o.msgPattern;
177
0
}
178
179
bool
180
0
SelectFormat::operator!=(const Format& other) const {
181
0
    return  !operator==(other);
182
0
}
183
184
void
185
SelectFormat::parseObject(const UnicodeString& /*source*/,
186
                        Formattable& /*result*/,
187
                        ParsePosition& pos) const
188
0
{
189
    // Parsing not supported.
190
0
    pos.setErrorIndex(pos.getIndex());
191
0
}
192
193
U_NAMESPACE_END
194
195
#endif /* #if !UCONFIG_NO_FORMATTING */
196
197
//eof