Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/intl/icu/source/i18n/search.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
**********************************************************************
5
*   Copyright (C) 2001-2008,2010 IBM and others. All rights reserved.
6
**********************************************************************
7
*   Date        Name        Description
8
*  03/22/2000   helena      Creation.
9
**********************************************************************
10
*/
11
12
#include "unicode/utypes.h"
13
14
#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_BREAK_ITERATION
15
16
#include "unicode/brkiter.h"
17
#include "unicode/schriter.h"
18
#include "unicode/search.h"
19
#include "usrchimp.h"
20
#include "cmemory.h"
21
22
// public constructors and destructors -----------------------------------
23
U_NAMESPACE_BEGIN
24
25
SearchIterator::SearchIterator(const SearchIterator &other)
26
    : UObject(other)
27
0
{   
28
0
    m_breakiterator_            = other.m_breakiterator_;
29
0
    m_text_                     = other.m_text_;
30
0
    m_search_                   = (USearch *)uprv_malloc(sizeof(USearch));   
31
0
    m_search_->breakIter        = other.m_search_->breakIter;
32
0
    m_search_->isCanonicalMatch = other.m_search_->isCanonicalMatch;
33
0
    m_search_->isOverlap        = other.m_search_->isOverlap;
34
0
    m_search_->elementComparisonType = other.m_search_->elementComparisonType;
35
0
    m_search_->matchedIndex     = other.m_search_->matchedIndex;
36
0
    m_search_->matchedLength    = other.m_search_->matchedLength;
37
0
    m_search_->text             = other.m_search_->text;
38
0
    m_search_->textLength       = other.m_search_->textLength;
39
0
}
40
41
SearchIterator::~SearchIterator()
42
0
{
43
0
    if (m_search_ != NULL) {
44
0
        uprv_free(m_search_);
45
0
    }
46
0
}
47
48
// public get and set methods ----------------------------------------
49
50
void SearchIterator::setAttribute(USearchAttribute       attribute,
51
                                  USearchAttributeValue  value,
52
                                  UErrorCode            &status)
53
0
{
54
0
    if (U_SUCCESS(status)) {
55
0
        switch (attribute)
56
0
        {
57
0
        case USEARCH_OVERLAP :
58
0
            m_search_->isOverlap = (value == USEARCH_ON ? TRUE : FALSE);
59
0
            break;
60
0
        case USEARCH_CANONICAL_MATCH :
61
0
            m_search_->isCanonicalMatch = (value == USEARCH_ON ? TRUE : FALSE);
62
0
            break;
63
0
        case USEARCH_ELEMENT_COMPARISON :
64
0
            if (value == USEARCH_PATTERN_BASE_WEIGHT_IS_WILDCARD || value == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD) {
65
0
                m_search_->elementComparisonType = (int16_t)value;
66
0
            } else {
67
0
                m_search_->elementComparisonType = 0;
68
0
            }
69
0
            break;
70
0
        default:
71
0
            status = U_ILLEGAL_ARGUMENT_ERROR;
72
0
        }
73
0
    }
74
0
    if (value == USEARCH_ATTRIBUTE_VALUE_COUNT) {
75
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
76
0
    }
77
0
}
78
79
USearchAttributeValue SearchIterator::getAttribute(
80
                                          USearchAttribute  attribute) const
81
0
{
82
0
    switch (attribute) {
83
0
    case USEARCH_OVERLAP :
84
0
        return (m_search_->isOverlap == TRUE ? USEARCH_ON : USEARCH_OFF);
85
0
    case USEARCH_CANONICAL_MATCH :
86
0
        return (m_search_->isCanonicalMatch == TRUE ? USEARCH_ON : 
87
0
                                                                USEARCH_OFF);
88
0
    case USEARCH_ELEMENT_COMPARISON :
89
0
        {
90
0
            int16_t value = m_search_->elementComparisonType;
91
0
            if (value == USEARCH_PATTERN_BASE_WEIGHT_IS_WILDCARD || value == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD) {
92
0
                return (USearchAttributeValue)value;
93
0
            } else {
94
0
                return USEARCH_STANDARD_ELEMENT_COMPARISON;
95
0
            }
96
0
        }
97
0
    default :
98
0
        return USEARCH_DEFAULT;
99
0
    }
100
0
}
101
    
102
int32_t SearchIterator::getMatchedStart() const
103
0
{
104
0
    return m_search_->matchedIndex;
105
0
}
106
107
int32_t SearchIterator::getMatchedLength() const
108
0
{
109
0
    return m_search_->matchedLength;
110
0
}
111
    
112
void SearchIterator::getMatchedText(UnicodeString &result) const
113
0
{
114
0
    int32_t matchedindex  = m_search_->matchedIndex;
115
0
    int32_t     matchedlength = m_search_->matchedLength;
116
0
    if (matchedindex != USEARCH_DONE && matchedlength != 0) {
117
0
        result.setTo(m_search_->text + matchedindex, matchedlength); 
118
0
    }
119
0
    else {
120
0
        result.remove();
121
0
    }
122
0
}
123
    
124
void SearchIterator::setBreakIterator(BreakIterator *breakiter, 
125
                                      UErrorCode &status)
126
0
{
127
0
    if (U_SUCCESS(status)) {
128
#if 0
129
        m_search_->breakIter = NULL;
130
        // the c++ breakiterator may not make use of ubreakiterator.
131
        // so we'll have to keep track of it ourselves.
132
#else
133
        // Well, gee... the Constructors that take a BreakIterator
134
0
        // all cast the BreakIterator to a UBreakIterator and
135
0
        // pass it to the corresponding usearch_openFromXXX
136
0
        // routine, so there's no reason not to do this.
137
0
        //
138
0
        // Besides, a UBreakIterator is a BreakIterator, so
139
0
        // any subclass of BreakIterator should work fine here...
140
0
        m_search_->breakIter = (UBreakIterator *) breakiter;
141
0
#endif
142
0
        
143
0
        m_breakiterator_ = breakiter;
144
0
    }
145
0
}
146
    
147
const BreakIterator * SearchIterator::getBreakIterator(void) const
148
0
{
149
0
    return m_breakiterator_;
150
0
}
151
152
void SearchIterator::setText(const UnicodeString &text, UErrorCode &status)
153
0
{
154
0
    if (U_SUCCESS(status)) {
155
0
        if (text.length() == 0) {
156
0
            status = U_ILLEGAL_ARGUMENT_ERROR;
157
0
        }
158
0
        else {
159
0
            m_text_        = text;
160
0
            m_search_->text = m_text_.getBuffer();
161
0
            m_search_->textLength = m_text_.length();
162
0
        }
163
0
    }
164
0
}
165
166
void SearchIterator::setText(CharacterIterator &text, UErrorCode &status)
167
0
{
168
0
    if (U_SUCCESS(status)) {
169
0
        text.getText(m_text_);
170
0
        setText(m_text_, status);
171
0
    }
172
0
}
173
    
174
const UnicodeString & SearchIterator::getText(void) const
175
0
{
176
0
    return m_text_;
177
0
}
178
179
// operator overloading ----------------------------------------------
180
181
UBool SearchIterator::operator==(const SearchIterator &that) const
182
0
{
183
0
    if (this == &that) {
184
0
        return TRUE;
185
0
    }
186
0
    return (m_breakiterator_            == that.m_breakiterator_ &&
187
0
            m_search_->isCanonicalMatch == that.m_search_->isCanonicalMatch &&
188
0
            m_search_->isOverlap        == that.m_search_->isOverlap &&
189
0
            m_search_->elementComparisonType == that.m_search_->elementComparisonType &&
190
0
            m_search_->matchedIndex     == that.m_search_->matchedIndex &&
191
0
            m_search_->matchedLength    == that.m_search_->matchedLength &&
192
0
            m_search_->textLength       == that.m_search_->textLength &&
193
0
            getOffset() == that.getOffset() &&
194
0
            (uprv_memcmp(m_search_->text, that.m_search_->text, 
195
0
                              m_search_->textLength * sizeof(UChar)) == 0));
196
0
}
197
198
// public methods ----------------------------------------------------
199
200
int32_t SearchIterator::first(UErrorCode &status)
201
0
{
202
0
    if (U_FAILURE(status)) {
203
0
        return USEARCH_DONE;
204
0
    }
205
0
    setOffset(0, status);
206
0
    return handleNext(0, status);
207
0
}
208
209
int32_t SearchIterator::following(int32_t position, 
210
                                      UErrorCode &status)
211
0
{
212
0
    if (U_FAILURE(status)) {
213
0
        return USEARCH_DONE;
214
0
    }
215
0
    setOffset(position, status);
216
0
    return handleNext(position, status);
217
0
}
218
    
219
int32_t SearchIterator::last(UErrorCode &status)
220
0
{
221
0
    if (U_FAILURE(status)) {
222
0
        return USEARCH_DONE;
223
0
    }
224
0
    setOffset(m_search_->textLength, status);
225
0
    return handlePrev(m_search_->textLength, status);
226
0
}
227
228
int32_t SearchIterator::preceding(int32_t position, 
229
                                      UErrorCode &status)
230
0
{
231
0
    if (U_FAILURE(status)) {
232
0
        return USEARCH_DONE;
233
0
    }
234
0
    setOffset(position, status);
235
0
    return handlePrev(position, status);
236
0
}
237
238
int32_t SearchIterator::next(UErrorCode &status)
239
0
{
240
0
    if (U_SUCCESS(status)) {
241
0
        int32_t offset = getOffset();
242
0
        int32_t matchindex  = m_search_->matchedIndex;
243
0
        int32_t     matchlength = m_search_->matchedLength;
244
0
        m_search_->reset = FALSE;
245
0
        if (m_search_->isForwardSearching == TRUE) {
246
0
            int32_t textlength = m_search_->textLength;
247
0
            if (offset == textlength || matchindex == textlength || 
248
0
                (matchindex != USEARCH_DONE && 
249
0
                matchindex + matchlength >= textlength)) {
250
0
                // not enough characters to match
251
0
                setMatchNotFound();
252
0
                return USEARCH_DONE; 
253
0
            }
254
0
        }
255
0
        else {
256
0
            // switching direction. 
257
0
            // if matchedIndex == USEARCH_DONE, it means that either a 
258
0
            // setOffset has been called or that previous ran off the text
259
0
            // string. the iterator would have been set to offset 0 if a 
260
0
            // match is not found.
261
0
            m_search_->isForwardSearching = TRUE;
262
0
            if (m_search_->matchedIndex != USEARCH_DONE) {
263
0
                // there's no need to set the collation element iterator
264
0
                // the next call to next will set the offset.
265
0
                return matchindex;
266
0
            }
267
0
        }
268
0
269
0
        if (matchlength > 0) {
270
0
            // if matchlength is 0 we are at the start of the iteration
271
0
            if (m_search_->isOverlap) {
272
0
                offset ++;
273
0
            }
274
0
            else {
275
0
                offset += matchlength;
276
0
            }
277
0
        }
278
0
        return handleNext(offset, status);
279
0
    }
280
0
    return USEARCH_DONE;
281
0
}
282
283
int32_t SearchIterator::previous(UErrorCode &status)
284
0
{
285
0
    if (U_SUCCESS(status)) {
286
0
        int32_t offset;
287
0
        if (m_search_->reset) {
288
0
            offset                       = m_search_->textLength;
289
0
            m_search_->isForwardSearching = FALSE;
290
0
            m_search_->reset              = FALSE;
291
0
            setOffset(offset, status);
292
0
        }
293
0
        else {
294
0
            offset = getOffset();
295
0
        }
296
0
        
297
0
        int32_t matchindex = m_search_->matchedIndex;
298
0
        if (m_search_->isForwardSearching == TRUE) {
299
0
            // switching direction. 
300
0
            // if matchedIndex == USEARCH_DONE, it means that either a 
301
0
            // setOffset has been called or that next ran off the text
302
0
            // string. the iterator would have been set to offset textLength if 
303
0
            // a match is not found.
304
0
            m_search_->isForwardSearching = FALSE;
305
0
            if (matchindex != USEARCH_DONE) {
306
0
                return matchindex;
307
0
            }
308
0
        }
309
0
        else {
310
0
            if (offset == 0 || matchindex == 0) {
311
0
                // not enough characters to match
312
0
                setMatchNotFound();
313
0
                return USEARCH_DONE; 
314
0
            }
315
0
        }
316
0
317
0
        if (matchindex != USEARCH_DONE) {
318
0
            if (m_search_->isOverlap) {
319
0
                matchindex += m_search_->matchedLength - 2;
320
0
            }
321
0
322
0
            return handlePrev(matchindex, status); 
323
0
        }
324
0
325
0
        return handlePrev(offset, status);
326
0
    }
327
0
328
0
    return USEARCH_DONE;
329
0
}
330
331
void SearchIterator::reset()
332
0
{
333
0
    UErrorCode status = U_ZERO_ERROR;
334
0
    setMatchNotFound();
335
0
    setOffset(0, status);
336
0
    m_search_->isOverlap          = FALSE;
337
0
    m_search_->isCanonicalMatch   = FALSE;
338
0
    m_search_->elementComparisonType = 0;
339
0
    m_search_->isForwardSearching = TRUE;
340
0
    m_search_->reset              = TRUE;
341
0
}
342
343
// protected constructors and destructors -----------------------------
344
345
SearchIterator::SearchIterator()
346
0
{
347
0
    m_search_                     = (USearch *)uprv_malloc(sizeof(USearch));
348
0
    m_search_->breakIter          = NULL;
349
0
    m_search_->isOverlap          = FALSE;
350
0
    m_search_->isCanonicalMatch   = FALSE;
351
0
    m_search_->elementComparisonType = 0;
352
0
    m_search_->isForwardSearching = TRUE;
353
0
    m_search_->reset              = TRUE;
354
0
    m_search_->matchedIndex       = USEARCH_DONE;
355
0
    m_search_->matchedLength      = 0;
356
0
    m_search_->text               = NULL;
357
0
    m_search_->textLength         = 0;
358
0
    m_breakiterator_              = NULL;
359
0
}
360
361
SearchIterator::SearchIterator(const UnicodeString &text, 
362
                                     BreakIterator *breakiter) :
363
                                     m_breakiterator_(breakiter),
364
                                     m_text_(text)
365
0
{
366
0
    m_search_                     = (USearch *)uprv_malloc(sizeof(USearch));
367
0
    m_search_->breakIter          = NULL;
368
0
    m_search_->isOverlap          = FALSE;
369
0
    m_search_->isCanonicalMatch   = FALSE;
370
0
    m_search_->elementComparisonType = 0;
371
0
    m_search_->isForwardSearching = TRUE;
372
0
    m_search_->reset              = TRUE;
373
0
    m_search_->matchedIndex       = USEARCH_DONE;
374
0
    m_search_->matchedLength      = 0;
375
0
    m_search_->text               = m_text_.getBuffer();
376
0
    m_search_->textLength         = text.length();
377
0
}
378
379
SearchIterator::SearchIterator(CharacterIterator &text, 
380
                               BreakIterator     *breakiter) :
381
                               m_breakiterator_(breakiter)
382
0
{
383
0
    m_search_                     = (USearch *)uprv_malloc(sizeof(USearch));
384
0
    m_search_->breakIter          = NULL;
385
0
    m_search_->isOverlap          = FALSE;
386
0
    m_search_->isCanonicalMatch   = FALSE;
387
0
    m_search_->elementComparisonType = 0;
388
0
    m_search_->isForwardSearching = TRUE;
389
0
    m_search_->reset              = TRUE;
390
0
    m_search_->matchedIndex       = USEARCH_DONE;
391
0
    m_search_->matchedLength      = 0;
392
0
    text.getText(m_text_);
393
0
    m_search_->text               = m_text_.getBuffer();
394
0
    m_search_->textLength         = m_text_.length();
395
0
    m_breakiterator_             = breakiter;
396
0
}
397
398
// protected methods ------------------------------------------------------
399
400
SearchIterator & SearchIterator::operator=(const SearchIterator &that)
401
0
{
402
0
    if (this != &that) {
403
0
        m_breakiterator_            = that.m_breakiterator_;
404
0
        m_text_                     = that.m_text_;
405
0
        m_search_->breakIter        = that.m_search_->breakIter;
406
0
        m_search_->isCanonicalMatch = that.m_search_->isCanonicalMatch;
407
0
        m_search_->isOverlap        = that.m_search_->isOverlap;
408
0
        m_search_->elementComparisonType = that.m_search_->elementComparisonType;
409
0
        m_search_->matchedIndex     = that.m_search_->matchedIndex;
410
0
        m_search_->matchedLength    = that.m_search_->matchedLength;
411
0
        m_search_->text             = that.m_search_->text;
412
0
        m_search_->textLength       = that.m_search_->textLength;
413
0
    }
414
0
    return *this;
415
0
}
416
417
void SearchIterator::setMatchLength(int32_t length)
418
0
{
419
0
    m_search_->matchedLength = length;
420
0
}
421
422
void SearchIterator::setMatchStart(int32_t position)
423
0
{
424
0
    m_search_->matchedIndex = position;
425
0
}
426
427
void SearchIterator::setMatchNotFound() 
428
0
{
429
0
    setMatchStart(USEARCH_DONE);
430
0
    setMatchLength(0);
431
0
    UErrorCode status = U_ZERO_ERROR;
432
0
    // by default no errors should be returned here since offsets are within 
433
0
    // range.
434
0
    if (m_search_->isForwardSearching) {
435
0
        setOffset(m_search_->textLength, status);
436
0
    }
437
0
    else {
438
0
        setOffset(0, status);
439
0
    }
440
0
}
441
442
443
U_NAMESPACE_END
444
445
#endif /* #if !UCONFIG_NO_COLLATION */