Index: uspace/app/edit/search.c
===================================================================
--- uspace/app/edit/search.c	(revision 7feb86e6ab857c89a05076ceedd5635972e99f0a)
+++ uspace/app/edit/search.c	(revision 7feb86e6ab857c89a05076ceedd5635972e99f0a)
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2012 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup edit
+ * @{
+ */
+/**
+ * @file
+ * @brief Simple searching facility.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "search.h"
+#include "search_impl.h"
+
+search_t *search_init(const char *pattern, void *client_data, search_ops_t ops)
+{
+	search_t *search = calloc(1, sizeof(search_t));
+	if (search == NULL)
+		return NULL;
+	
+	search->pattern = str_to_awstr(pattern);
+	if (search->pattern == NULL) {
+		free(search);
+		return NULL;
+	}
+	
+	search->client_data = client_data;
+	search->ops = ops;
+	search->pattern_length = wstr_length(search->pattern);
+	search->back_table = calloc(search->pattern_length, sizeof(ssize_t));
+	if (search->back_table == NULL) {
+		free(search->pattern);
+		free(search);
+		return NULL;
+	}
+	
+	search->pattern_pos = 0;
+	
+	search->back_table[0] = -1;
+	search->back_table[1] = 0;
+	size_t table_idx = 2;
+	size_t pattern_idx = 0;
+	while (table_idx < search->pattern_length) {
+		if (ops.equals(search->pattern[table_idx - 1],
+		    search->pattern[pattern_idx])) {
+			pattern_idx++;
+			search->back_table[table_idx] = pattern_idx;
+			table_idx++;
+		}
+		else if (pattern_idx > 0) {
+			pattern_idx = search->back_table[pattern_idx];
+		}
+		else {
+			pattern_idx = 0;
+			table_idx++;
+		}
+	}
+	
+	return search;
+}
+
+int search_next_match(search_t *s, match_t *match)
+{
+	search_equals_fn eq = s->ops.equals;
+	
+	wchar_t cur_char;
+	int rc = EOK;
+	while ((rc = s->ops.producer(s->client_data, &cur_char)) == EOK && cur_char > 0) {
+		/* Deal with mismatches */
+		while (s->pattern_pos > 0 && !eq(cur_char, s->pattern[s->pattern_pos])) {
+			s->pattern_pos = s->back_table[s->pattern_pos];
+		}
+		/* Check if the character matched */
+		if (eq(cur_char, s->pattern[s->pattern_pos])) {
+			s->pattern_pos++;
+			if (s->pattern_pos == s->pattern_length) {
+				s->pattern_pos = s->back_table[s->pattern_pos];
+				rc = s->ops.mark(s->client_data, &match->end);
+				if (rc != EOK)
+					return rc;
+				match->length = s->pattern_length;
+				return EOK;
+			}
+		}
+	}
+	
+	match->end = NULL;
+	match->length = 0;
+	
+	return rc;
+}
+
+void search_fini(search_t *search)
+{
+	free(search->pattern);
+	free(search->back_table);
+	
+}
+
+bool char_exact_equals(const wchar_t a, const wchar_t b)
+{
+	return a == b;
+}
+
+/** @}
+ */
