summaryrefslogtreecommitdiff
path: root/src/stringfilter.cpp
diff options
context:
space:
mode:
authorfrosch <frosch@openttd.org>2012-06-09 19:54:16 +0000
committerfrosch <frosch@openttd.org>2012-06-09 19:54:16 +0000
commit03046f614f4fb8c88d1a8ee05e0caee2bde887bc (patch)
tree8ee6fcb2c3c316b89bb884e10a52e42136674b94 /src/stringfilter.cpp
parentdb709aff32244d45e613d53dbf9f0ffbc3aa5cb1 (diff)
downloadopenttd-03046f614f4fb8c88d1a8ee05e0caee2bde887bc.tar.xz
(svn r24337) -Feature: Allow filtering for multiple words (separated by whitespace resp. quoted) in the sign list, content- and NewGRF-guis.
Diffstat (limited to 'src/stringfilter.cpp')
-rw-r--r--src/stringfilter.cpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/stringfilter.cpp b/src/stringfilter.cpp
new file mode 100644
index 000000000..616fd9854
--- /dev/null
+++ b/src/stringfilter.cpp
@@ -0,0 +1,120 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * 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.
+ * 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.
+ * 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/>.
+ */
+
+/** @file stringfilter.cpp Searching and filtering using a stringterm. */
+
+#include "stdafx.h"
+#include "string_func.h"
+#include "stringfilter_type.h"
+
+static const WChar STATE_WHITESPACE = ' ';
+static const WChar STATE_WORD = 'w';
+static const WChar STATE_QUOTE1 = '\'';
+static const WChar STATE_QUOTE2 = '"';
+
+/**
+ * Set the term to filter on.
+ * @param str Filter term
+ */
+void StringFilter::SetFilterTerm(const char *str)
+{
+ this->word_index.Reset();
+ this->word_matches = 0;
+ free(this->filter_buffer);
+
+ assert(str != NULL);
+
+ char *dest = (char *)malloc(strlen(str) + 1);
+ this->filter_buffer = dest;
+
+ WChar state = STATE_WHITESPACE;
+ const char *pos = str;
+ WordState *word = NULL;
+ size_t len;
+ for (;; pos += len) {
+ WChar c;
+ len = Utf8Decode(&c, pos);
+
+ if (c == 0 || (state == STATE_WORD && IsWhitespace(c))) {
+ /* Finish word */
+ if (word != NULL) {
+ *(dest++) = '\0';
+ word = NULL;
+ }
+ state = STATE_WHITESPACE;
+ if (c != 0) continue; else break;
+ }
+
+ if (state == STATE_WHITESPACE) {
+ /* Skip whitespace */
+ if (IsWhitespace(c)) continue;
+ state = STATE_WORD;
+ }
+
+ if (c == STATE_QUOTE1 || c == STATE_QUOTE2) {
+ if (state == c) {
+ /* Stop quoting */
+ state = STATE_WORD;
+ continue;
+ } else if (state == STATE_WORD) {
+ /* Start quoting */
+ state = c;
+ continue;
+ }
+ }
+
+ /* Add to word */
+ if (word == NULL) {
+ word = this->word_index.Append();
+ word->start = dest;
+ word->match = false;
+ }
+
+ memcpy(dest, pos, len);
+ dest += len;
+ }
+}
+
+/**
+ * Reset the matching state to process a new item.
+ */
+void StringFilter::ResetState()
+{
+ this->word_matches = 0;
+ const WordState *end = this->word_index.End();
+ for (WordState *it = this->word_index.Begin(); it != end; ++it) {
+ it->match = false;
+ }
+}
+
+/**
+ * Pass another text line from the current item to the filter.
+ *
+ * You can call this multiple times for a single item, if the filter shall apply to multiple things.
+ * Before processing the next item you have to call ResetState().
+ *
+ * @param str Another line from the item.
+ */
+void StringFilter::AddLine(const char *str)
+{
+ if (str == NULL) return;
+
+ bool match_case = this->case_sensitive != NULL && *this->case_sensitive;
+ const WordState *end = this->word_index.End();
+ for (WordState *it = this->word_index.Begin(); it != end; ++it) {
+ if (!it->match) {
+ if ((match_case ? strstr(str, it->start) : strcasestr(str, it->start)) != NULL) {
+ it->match = true;
+ this->word_matches++;
+ }
+ }
+ }
+}
+
+