2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 /** @file stringfilter.cpp Searching and filtering using a stringterm. */
11 #include "core/alloc_func.hpp"
12 #include "string_func.h"
13 #include "strings_func.h"
14 #include "stringfilter_type.h"
17 #include "safeguards.h"
19 static const char32_t STATE_WHITESPACE
= ' ';
20 static const char32_t STATE_WORD
= 'w';
21 static const char32_t STATE_QUOTE1
= '\'';
22 static const char32_t STATE_QUOTE2
= '"';
25 * Set the term to filter on.
26 * @param str Filter term
28 void StringFilter::SetFilterTerm(const char *str
)
30 this->word_index
.clear();
31 this->word_index
.shrink_to_fit();
32 this->word_matches
= 0;
33 free(this->filter_buffer
);
35 assert(str
!= nullptr);
37 char *dest
= MallocT
<char>(strlen(str
) + 1);
38 this->filter_buffer
= dest
;
40 char32_t state
= STATE_WHITESPACE
;
41 const char *pos
= str
;
42 WordState
*word
= nullptr;
46 len
= Utf8Decode(&c
, pos
);
48 if (c
== 0 || (state
== STATE_WORD
&& IsWhitespace(c
))) {
50 if (word
!= nullptr) {
54 state
= STATE_WHITESPACE
;
55 if (c
!= 0) continue; else break;
58 if (state
== STATE_WHITESPACE
) {
60 if (IsWhitespace(c
)) continue;
64 if (c
== STATE_QUOTE1
|| c
== STATE_QUOTE2
) {
69 } else if (state
== STATE_WORD
) {
77 if (word
== nullptr) {
78 word
= &this->word_index
.emplace_back(WordState
{ dest
, false });
81 memcpy(dest
, pos
, len
);
87 * Set the term to filter on.
88 * @param str Filter term
90 void StringFilter::SetFilterTerm(const std::string
&str
)
92 this->SetFilterTerm(str
.c_str());
96 * Reset the matching state to process a new item.
98 void StringFilter::ResetState()
100 this->word_matches
= 0;
101 for (WordState
&ws
: this->word_index
) {
107 * Pass another text line from the current item to the filter.
109 * You can call this multiple times for a single item, if the filter shall apply to multiple things.
110 * Before processing the next item you have to call ResetState().
112 * @param str Another line from the item.
114 void StringFilter::AddLine(const char *str
)
116 if (str
== nullptr) return;
118 bool match_case
= this->case_sensitive
!= nullptr && *this->case_sensitive
;
119 for (WordState
&ws
: this->word_index
) {
121 if (this->locale_aware
) {
122 if (match_case
? StrNaturalContains(str
, ws
.start
) : StrNaturalContainsIgnoreCase(str
, ws
.start
)) {
124 this->word_matches
++;
127 if ((match_case
? strstr(str
, ws
.start
) : strcasestr(str
, ws
.start
)) != nullptr) {
129 this->word_matches
++;
137 * Pass another text line from the current item to the filter.
139 * You can call this multiple times for a single item, if the filter shall apply to multiple things.
140 * Before processing the next item you have to call ResetState().
142 * @param str Another line from the item.
144 void StringFilter::AddLine(const std::string
&str
)
146 AddLine(str
.c_str());
150 * Pass another text line from the current item to the filter.
152 * You can call this multiple times for a single item, if the filter shall apply to multiple things.
153 * Before processing the next item you have to call ResetState().
155 * @param str Another line from the item.
157 void StringFilter::AddLine(StringID str
)
159 AddLine(GetString(str
));