Commit 1bff786c authored by Noah Levitt's avatar Noah Levitt

2004-01-18 Noah Levitt

	* gucharmap/Makefile.am:
	* gucharmap/gucharmap-block-chapters.c:
	* gucharmap/gucharmap-chapters.c:
	* gucharmap/gucharmap-chapters.h:
	* gucharmap/gucharmap-charmap.c:
	* gucharmap/gucharmap-charmap.h:
	* gucharmap/gucharmap-codepoint-list.h:
	* gucharmap/gucharmap-script-chapters.c:
	* gucharmap/gucharmap-script-codepoint-list.c:
	* gucharmap/gucharmap-script-codepoint-list.h:
	* gucharmap/gucharmap-search.c:
	* gucharmap/gucharmap-search.h:
	* gucharmap/gucharmap-unicode-info.c:
	* gucharmap/gucharmap-unicode-info.h:
	* gucharmap/gucharmap-window.c: New search implementation that works
	with chapters.
parent 1378cf74
2004-01-18 Noah Levitt
* gucharmap/Makefile.am:
* gucharmap/gucharmap-block-chapters.c:
* gucharmap/gucharmap-chapters.c:
* gucharmap/gucharmap-chapters.h:
* gucharmap/gucharmap-charmap.c:
* gucharmap/gucharmap-charmap.h:
* gucharmap/gucharmap-codepoint-list.h:
* gucharmap/gucharmap-script-chapters.c:
* gucharmap/gucharmap-script-codepoint-list.c:
* gucharmap/gucharmap-script-codepoint-list.h:
* gucharmap/gucharmap-search.c:
* gucharmap/gucharmap-search.h:
* gucharmap/gucharmap-unicode-info.c:
* gucharmap/gucharmap-unicode-info.h:
* gucharmap/gucharmap-window.c: New search implementation that works
with chapters.
2004-01-16 Noah Levitt
* gucharmap/gucharmap-script-codepoint-list.c:
......
......@@ -45,7 +45,8 @@ libgucharmap_la_SOURCES = gucharmap-marshal.c gucharmap-marshal.h \
gucharmap-block-chapters.c gucharmap-block-chapters.h \
gucharmap-script-chapters.c gucharmap-script-chapters.h \
unicode-blocks.h unicode-categories.h unicode-names.h \
unicode-nameslist.h unicode-scripts.h unicode-unihan.h
unicode-nameslist.h unicode-scripts.h unicode-unihan.h \
gucharmap-search.h gucharmap-search.c
# this is different from the project version
libgucharmap_la_LDFLAGS = -version-info 3:3:0
......
......@@ -52,6 +52,7 @@ gucharmap_block_chapters_init (GucharmapBlockChapters *chapters)
GtkTreeSelection *selection;
gint i;
parent->book_list = NULL;
parent->tree_model = GTK_TREE_MODEL (gtk_list_store_new (BLOCK_CHAPTERS_NUM_COLUMNS,
G_TYPE_STRING, G_TYPE_POINTER));
......@@ -99,6 +100,9 @@ finalize (GObject *object)
/* XXX: what to free and how? */
g_object_unref (chapters->tree_model);
/* g_object_unref (chapters->tree_view); */
if (chapters->book_list)
g_object_unref (chapters->book_list);
}
static GucharmapCodepointList *
......@@ -125,6 +129,55 @@ get_codepoint_list (GucharmapChapters *chapters)
return NULL;
}
static G_CONST_RETURN GucharmapCodepointList *
get_book_codepoint_list (GucharmapChapters *chapters)
{
if (chapters->book_list == NULL)
chapters->book_list = gucharmap_codepoint_list_new (0, UNICHAR_MAX);
return chapters->book_list;
}
/* XXX linear search */
static gboolean
go_to_character (GucharmapChapters *chapters,
gunichar wc)
{
GucharmapChapters *parent = GUCHARMAP_CHAPTERS (chapters);
GtkTreeSelection *selection;
GtkTreeIter iter;
if (wc > UNICHAR_MAX)
return FALSE;
/* skip "All" block */
if (!gtk_tree_model_get_iter_first (parent->tree_model, &iter))
return FALSE;
while (gtk_tree_model_iter_next (parent->tree_model, &iter))
{
UnicodeBlock *unicode_block;
gtk_tree_model_get (parent->tree_model, &iter, BLOCK_CHAPTERS_UNICODE_BLOCK_PTR, &unicode_block, -1);
if (wc >= unicode_block->start && wc <= unicode_block->end)
{
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (parent->tree_view));
if (!gtk_tree_selection_iter_is_selected (selection, &iter))
gtk_tree_selection_select_iter (selection, &iter);
return TRUE;
}
}
/* "All" is the last resort */
if (!gtk_tree_model_get_iter_first (parent->tree_model, &iter))
return FALSE;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (parent->tree_view));
if (!gtk_tree_selection_iter_is_selected (selection, &iter))
gtk_tree_selection_select_iter (selection, &iter);
return TRUE;
}
static void
gucharmap_block_chapters_class_init (GucharmapBlockChaptersClass *clazz)
{
......@@ -133,6 +186,8 @@ gucharmap_block_chapters_class_init (GucharmapBlockChaptersClass *clazz)
gobject_class->finalize = finalize;
chapters_class->get_codepoint_list = get_codepoint_list;
chapters_class->get_book_codepoint_list = get_book_codepoint_list;
chapters_class->go_to_character = go_to_character;
}
GType
......
......@@ -87,7 +87,7 @@ gucharmap_chapters_get_type ()
/**
* gucharmap_chapters_get_codepoint_list:
* @chapters: a #Gucharmap
* @chapters: a #GucharmapChapters
*
* Creates a new #GucharmapCodepointList representing the characters in the
* current chapter.
......@@ -103,3 +103,34 @@ gucharmap_chapters_get_codepoint_list (GucharmapChapters *chapters)
return GUCHARMAP_CHAPTERS_GET_CLASS (chapters)->get_codepoint_list (chapters);
}
/**
* gucharmap_chapters_get_codepoint_list:
* @chapters: a #GucharmapChapters
*
* Return value: a #GucharmapCodepointList representing all the characters
* in all the chapters. It should not be modified or freed.
**/
G_CONST_RETURN GucharmapCodepointList *
gucharmap_chapters_get_book_codepoint_list (GucharmapChapters *chapters)
{
g_return_val_if_fail (IS_GUCHARMAP_CHAPTERS (chapters), NULL);
return GUCHARMAP_CHAPTERS_GET_CLASS (chapters)->get_book_codepoint_list (chapters);
}
/**
* gucharmap_chapters_go_to_character:
* @chapters: a #GucharmapChapters
* @wc: a character
*
* Return value: %TRUE on success, %FALSE on failure.
**/
gboolean
gucharmap_chapters_go_to_character (GucharmapChapters *chapters,
gunichar wc)
{
g_return_val_if_fail (IS_GUCHARMAP_CHAPTERS (chapters), FALSE);
return GUCHARMAP_CHAPTERS_GET_CLASS (chapters)->go_to_character (chapters, wc);
}
......@@ -45,20 +45,27 @@ struct _GucharmapChapters
GtkScrolledWindow parent;
/*< protected >*/
GtkTreeModel *tree_model;
GtkWidget *tree_view;
GtkTreeModel *tree_model;
GtkWidget *tree_view;
GucharmapCodepointList *book_list;
};
struct _GucharmapChaptersClass
{
GtkScrolledWindowClass parent_class;
void (* changed) (GucharmapChapters *chapters);
GucharmapCodepointList * (* get_codepoint_list) (GucharmapChapters *chapters);
void (* changed) (GucharmapChapters *chapters);
GucharmapCodepointList * (* get_codepoint_list) (GucharmapChapters *chapters);
G_CONST_RETURN GucharmapCodepointList * (* get_book_codepoint_list) (GucharmapChapters *chapters);
gboolean (* go_to_character) (GucharmapChapters *chapters,
gunichar wc);
};
GType gucharmap_chapters_get_type ();
GucharmapCodepointList * gucharmap_chapters_get_codepoint_list (GucharmapChapters *chapters);
GType gucharmap_chapters_get_type ();
GucharmapCodepointList * gucharmap_chapters_get_codepoint_list (GucharmapChapters *chapters);
G_CONST_RETURN GucharmapCodepointList * gucharmap_chapters_get_book_codepoint_list (GucharmapChapters *chapters);
gboolean gucharmap_chapters_go_to_character (GucharmapChapters *chapters,
gunichar wc);
G_END_DECLS
......
......@@ -823,54 +823,17 @@ gucharmap_charmap_identify_clipboard (GucharmapCharmap *charmap,
void
gucharmap_charmap_go_to_character (GucharmapCharmap *charmap,
gunichar uc)
gunichar wc)
{
if (uc >= 0 && uc <= UNICHAR_MAX)
gucharmap_table_set_active_character (charmap->chartable, uc);
}
/* direction is +1 (forward) or -1 (backward) */
GucharmapSearchResult
gucharmap_charmap_search (GucharmapCharmap *charmap,
const gchar *search_text,
gint direction)
{
GucharmapSearchResult result;
gunichar wc, first_wc;
g_assert (direction == -1 || direction == 1);
if (search_text[0] == '\0')
return GUCHARMAP_NOTHING_TO_SEARCH_FOR;
wc = gucharmap_find_substring_match (gucharmap_table_get_active_character (charmap->chartable), search_text, direction);
first_wc = wc;
GucharmapChapters *chapters = gucharmap_charmap_get_chapters (charmap);
gboolean status;
while (wc != (gunichar)(-1) && wc <= UNICHAR_MAX
&& gucharmap_codepoint_list_get_index (charmap->chartable->codepoint_list, wc) == (guint)(-1))
{
wc = gucharmap_find_substring_match (wc, search_text, direction);
if (wc == first_wc)
{
wc = (gunichar)(-1);
break;
}
}
status = gucharmap_chapters_go_to_character (chapters, wc);
if (!status)
g_warning ("gucharmap_chapters_go_to_character failed (%04X)\n", wc);
if (wc != (gunichar)(-1) && wc <= UNICHAR_MAX)
{
if ((direction == 1 && wc <= charmap->chartable->active_cell)
|| (direction == -1 && wc >= charmap->chartable->active_cell))
result = GUCHARMAP_WRAPPED;
else
result = GUCHARMAP_FOUND;
gucharmap_table_set_active_character (charmap->chartable, wc);
}
else
result = GUCHARMAP_NOT_FOUND;
return result;
if (wc >= 0 && wc <= UNICHAR_MAX)
gucharmap_table_set_active_character (charmap->chartable, wc);
}
GucharmapTable *
......@@ -889,3 +852,9 @@ gucharmap_charmap_set_chapters (GucharmapCharmap *charmap,
g_signal_connect (G_OBJECT (chapters), "changed", G_CALLBACK (chapter_changed), charmap);
gtk_widget_show (GTK_WIDGET (chapters));
}
GucharmapChapters *
gucharmap_charmap_get_chapters (GucharmapCharmap *charmap)
{
return GUCHARMAP_CHAPTERS (GTK_PANED (charmap)->child1);
}
......@@ -42,15 +42,6 @@ G_BEGIN_DECLS
typedef struct _GucharmapCharmap GucharmapCharmap;
typedef struct _GucharmapCharmapClass GucharmapCharmapClass;
typedef enum
{
GUCHARMAP_NOT_FOUND,
GUCHARMAP_FOUND,
GUCHARMAP_WRAPPED,
GUCHARMAP_NOTHING_TO_SEARCH_FOR
}
GucharmapSearchResult;
struct _GucharmapCharmap
{
GtkHPaned parent;
......@@ -87,12 +78,10 @@ void gucharmap_charmap_identify_clipboard (GucharmapCharmap *c
GtkClipboard *clipboard);
void gucharmap_charmap_go_to_character (GucharmapCharmap *charmap,
gunichar uc);
GucharmapSearchResult gucharmap_charmap_search (GucharmapCharmap *charmap,
const gchar *search_text,
gint direction);
GucharmapTable * gucharmap_charmap_get_chartable (GucharmapCharmap *charmap);
void gucharmap_charmap_set_chapters (GucharmapCharmap *charmap,
GucharmapChapters *chapters);
GucharmapChapters * gucharmap_charmap_get_chapters (GucharmapCharmap *charmap);
G_END_DECLS
......
......@@ -60,7 +60,7 @@ GType gucharmap_codepoint_list_get_type ();
GucharmapCodepointList * gucharmap_codepoint_list_new (gunichar start,
gunichar end);
gunichar gucharmap_codepoint_list_get_char (GucharmapCodepointList *list,
gint index);
gint index);
gint gucharmap_codepoint_list_get_index (GucharmapCodepointList *list,
gunichar wc);
gint gucharmap_codepoint_list_get_last_index (GucharmapCodepointList *list);
......
......@@ -17,8 +17,11 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include "config.h"
#include <gtk/gtk.h>
#include <string.h>
#include "gucharmap_intl.h"
#include "gucharmap-unicode-info.h"
#include "gucharmap-script-chapters.h"
......@@ -127,6 +130,65 @@ get_codepoint_list (GucharmapChapters *chapters)
return NULL;
}
static gboolean
append_script (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
GucharmapScriptCodepointList *list)
{
gchar *script_untranslated;
gtk_tree_model_get (model, iter, SCRIPT_CHAPTERS_SCRIPT_UNTRANSLATED, &script_untranslated, -1);
gucharmap_script_codepoint_list_append_script (list, script_untranslated);
return FALSE;
}
static G_CONST_RETURN GucharmapCodepointList *
get_book_codepoint_list (GucharmapChapters *chapters)
{
if (chapters->book_list == NULL)
{
chapters->book_list = gucharmap_script_codepoint_list_new ();
gtk_tree_model_foreach (chapters->tree_model, (GtkTreeModelForeachFunc) append_script, chapters->book_list);
}
return chapters->book_list;
}
static gboolean
go_to_character (GucharmapChapters *chapters,
gunichar wc)
{
GucharmapChapters *parent = GUCHARMAP_CHAPTERS (chapters);
GtkTreeSelection *selection;
const gchar *script, *temp;
GtkTreeIter iter;
script = gucharmap_unicode_get_script_for_char (wc);
if (script == NULL)
return FALSE;
if (!gtk_tree_model_get_iter_first (parent->tree_model, &iter))
return FALSE;
do
{
gtk_tree_model_get (parent->tree_model, &iter, SCRIPT_CHAPTERS_SCRIPT_UNTRANSLATED, &temp, -1);
if (strcmp (script, temp) == 0)
{
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (parent->tree_view));
if (!gtk_tree_selection_iter_is_selected (selection, &iter))
gtk_tree_selection_select_iter (selection, &iter);
return TRUE;
}
}
while (gtk_tree_model_iter_next (parent->tree_model, &iter));
return FALSE;
}
static void
gucharmap_script_chapters_class_init (GucharmapScriptChaptersClass *clazz)
{
......@@ -135,6 +197,8 @@ gucharmap_script_chapters_class_init (GucharmapScriptChaptersClass *clazz)
gobject_class->finalize = finalize;
chapters_class->get_codepoint_list = get_codepoint_list;
chapters_class->get_book_codepoint_list = get_book_codepoint_list;
chapters_class->go_to_character = go_to_character;
}
GType
......
......@@ -42,34 +42,6 @@ struct _ScriptCodepointListPrivate
(G_TYPE_INSTANCE_GET_PRIVATE ((o), gucharmap_script_codepoint_list_get_type (), \
ScriptCodepointListPrivate))
#if 0
G_CONST_RETURN gchar *
gucharmap_get_script_for_char (gunichar wc)
{
gint min = 0;
gint mid;
gint max = sizeof (unicode_scripts) / sizeof (UnicodeScript) - 1;
if (!gucharmap_unichar_isdefined (wc))
return NULL;
while (max >= min)
{
mid = (min + max) / 2;
if (wc > unicode_scripts[mid].end)
min = mid + 1;
else if (wc < unicode_scripts[mid].start)
max = mid - 1;
else
return unicode_scripts[mid].script;
}
/* Unicode assigns "Common" as the script name for any character not
* specifically listed in Scripts.txt */
return _("Common");
}
#endif
static gint
find_script (const gchar *script)
{
......@@ -227,31 +199,21 @@ get_char (GucharmapCodepointList *list,
return (gunichar)(-1);
}
/* XXX: linear search */
static gint
get_index (GucharmapCodepointList *list,
gunichar wc)
{
GucharmapScriptCodepointList *guscl = GUCHARMAP_SCRIPT_CODEPOINT_LIST (list);
ScriptCodepointListPrivate *priv = GUCHARMAP_SCRIPT_CODEPOINT_LIST_GET_PRIVATE (guscl);
gint min, mid, max;
gint i;
ensure_initialized (guscl);
min = 0;
max = priv->ranges->len - 1;
while (max >= min)
for (i = 0; i < priv->ranges->len; i++)
{
UnicodeRange *range;
mid = (min + max) / 2;
range = (UnicodeRange *) (priv->ranges->pdata[mid]);
if (wc > range->end)
min = mid + 1;
else if (wc < range->start)
max = mid - 1;
else
UnicodeRange *range = (UnicodeRange *) priv->ranges->pdata[i];
if (wc >= range->start && wc <= range->end)
return range->index + wc - range->start;
}
......@@ -404,6 +366,51 @@ gucharmap_script_codepoint_list_set_scripts (GucharmapScriptCodepointList *list
return TRUE;
}
/**
* gucharmap_script_codepoint_list_append_script:
* @list: a GucharmapScriptCodepointList
* @script: the script name
*
* Appends the characters in @script to the codepoint list.
*
* Return value: %TRUE on success, %FALSE if there is no such script, in
* which case the codepoint list is not changed.
**/
gboolean
gucharmap_script_codepoint_list_append_script (GucharmapScriptCodepointList *list,
const gchar *script)
{
ScriptCodepointListPrivate *priv = GUCHARMAP_SCRIPT_CODEPOINT_LIST_GET_PRIVATE (list);
UnicodeRange *ranges;
gint j, size, index0;
if (priv->ranges == NULL)
priv->ranges = g_ptr_array_new ();
if (priv->ranges->len > 0)
{
UnicodeRange *last_range = (UnicodeRange *) priv->ranges->pdata[priv->ranges->len - 1];
index0 = last_range->index + last_range->end - last_range->start + 1;
}
else
index0 = 0;
if (get_chars_for_script (script, &ranges, &size))
{
for (j = 0; j < size; j++)
{
UnicodeRange *range = g_memdup (ranges + j, sizeof (ranges[j]));
range->index += index0;
g_ptr_array_add (priv->ranges, range);
}
g_free (ranges);
return TRUE;
}
return FALSE;
}
/**
* gucharmap_unicode_list_scripts:
*
......@@ -417,4 +424,36 @@ gucharmap_unicode_list_scripts ()
return unicode_script_list;
}
/**
* gucharmap_unicode_get_script_for_char:
* @wc: a character
*
* Return value: The English (untranslated) name of the script to which the
* character belongs. Characters that don't belong to an actual script
* return %"Common".
**/
G_CONST_RETURN gchar *
gucharmap_unicode_get_script_for_char (gunichar wc)
{
gint min = 0;
gint mid;
gint max = sizeof (unicode_scripts) / sizeof (UnicodeScript) - 1;
if (wc > UNICHAR_MAX)
return NULL;
while (max >= min)
{
mid = (min + max) / 2;
if (wc > unicode_scripts[mid].end)
min = mid + 1;
else if (wc < unicode_scripts[mid].start)
max = mid - 1;
else
return unicode_script_list[unicode_scripts[mid].script_index];
}
/* Unicode assigns "Common" as the script name for any character not
* specifically listed in Scripts.txt */
return N_("Common");
}
......@@ -58,6 +58,8 @@ gboolean gucharmap_script_codepoint_list_set_script (Gucharm
const gchar *script);
gboolean gucharmap_script_codepoint_list_set_scripts (GucharmapScriptCodepointList *list,
const gchar **scripts);
gboolean gucharmap_script_codepoint_list_append_script (GucharmapScriptCodepointList *list,
const gchar *script);
/* XXX: gucharmap_script_codepoint_list_get_script? seems unnecessary */
G_END_DECLS
......
/* $Id$ */
/*
* Copyright (c) 2004 Noah Levitt
*
* This program 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; either version 2 of the License, or (at your
* option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <glib.h>
#include <string.h>
#include <stdlib.h>
#include "gucharmap-codepoint-list.h"
#include "gucharmap-search.h"
#include "gucharmap-unicode-info.h"
static const gchar *
utf8_strcasestr (const gchar *haystack,
const gchar *needle)
{
gint needle_len = strlen (needle);
gint haystack_len = strlen (haystack);
const gchar *p, *q, *r;
for (p = haystack; p + needle_len <= haystack + haystack_len; p = g_utf8_next_char (p))
{
for (q = needle, r = p; *q && *r; q = g_utf8_next_char (q), r = g_utf8_next_char (r))
{
gunichar lc0 = g_unichar_tolower (g_utf8_get_char (r));
gunichar lc1 = g_unichar_tolower (g_utf8_get_char (q));
if (lc0 != lc1)
goto next;
}
return p;
next:
;
}
return NULL;
}
static gboolean
matches (gunichar wc,
const gchar *search_string)
{
const gchar *haystack, *haystack_nfd;
gboolean matches;
gchar *needle_nfd;
needle_nfd = g_utf8_normalize (search_string, -1, G_NORMALIZE_NFD);
haystack = gucharmap_get_unicode_name (wc);
if (haystack)
{
/* character names are ascii, so are nfd */
haystack_nfd = haystack;
/* haystack_nfd = g_utf8_normalize (haystack, -1, G_NORMALIZE_NFD); */
matches = utf8_strcasestr (haystack_nfd, needle_nfd) != NULL;
/* g_free (haystack_nfd); */
if (matches)
goto yes;
}
/* XXX: other strings */
g_free (needle_nfd);
return FALSE;
yes:
g_free (needle_nfd);
return TRUE;
}
static gint
find_next (const GucharmapCodepointList *list,
const gchar *search_string,
gint start_index,
GucharmapDirection direction,
gboolean whole_word)
{
gint i;
gint n = gucharmap_codepoint_list_get_last_index ((GucharmapCodepointList *) list) + 1;
gint inc = (direction == GUCHARMAP_BACKWARD) ? -1 : 1;
i = start_index;
do
{
i = (i + inc + n) % n;
gunichar wc = gucharmap_codepoint_list_get_char ((GucharmapCodepointList *) list, i);
if (!gucharmap_unichar_validate (wc) || !gucharmap_unichar_isdefined (wc))
continue;
if (matches (wc, search_string))
return i;
}
while (i != start_index);
return -1;
}
/* string should have no leading spaces */
static gint
check_for_explicit_codepoint (const GucharmapCodepointList *list,
const gchar *string)
{
const gchar *nptr;
gchar *endptr;
/* check for explicit decimal codepoint */
nptr = string;
if (g_ascii_strncasecmp (string, "&#", 2) == 0)
nptr = string + 2;
else if (*string == '#')
nptr = string + 1;
if (nptr != string)
{
gunichar wc = strtoul (nptr, &endptr, 10);
if (endptr != nptr)
{
gint index = gucharmap_codepoint_list_get_index ((GucharmapCodepointList *) list, wc);
if (index != -1)
return index;
}
}
/* check for explicit hex code point */
nptr = string;
if (g_ascii_strncasecmp (string, "&#x", 3) == 0)
nptr = string + 3;
else if (g_ascii_strncasecmp (string, "U+", 2) == 0 || g_ascii_strncasecmp (string, "0x", 2) == 0)
nptr = string + 2;
if (nptr != string)
{
gunichar wc = strtoul (nptr, &endptr, 16);
if (endptr != nptr)
{
gint index = gucharmap_codepoint_list_get_index ((GucharmapCodepointList *) list, wc);
if (index != -1)
return index;
}
}
return -1;
}
/**
* gucharmap_find_next:
* @list: a #GucharmapCodepointList to be searched
* @search_string: the text to search for
* @start_index: the starting point within @list
* @direction: forward or backward
* @whole_word: %TRUE if it should match whole words
*