1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
/*
* Copyright Timo Hirvonen
*/
#include "search.h"
#include "editable.h"
#include "xmalloc.h"
struct searchable {
void *data;
struct iter head;
struct searchable_ops ops;
};
static void search_lock(void)
{
editable_lock();
}
static void search_unlock(void)
{
editable_unlock();
}
/* returns next matching track (can be current!) or NULL if not found */
static int do_search(struct searchable *s, struct iter *iter, const char *text, int direction)
{
while (1) {
if (s->ops.matches(s->data, iter, text))
return 1;
if (direction == SEARCH_FORWARD) {
if (!s->ops.get_next(iter))
return 0;
} else {
if (!s->ops.get_prev(iter))
return 0;
}
}
}
struct searchable *searchable_new(void *data, const struct iter *head, const struct searchable_ops *ops)
{
struct searchable *s;
s = xnew(struct searchable, 1);
s->data = data;
s->head = *head;
s->ops = *ops;
return s;
}
void searchable_free(struct searchable *s)
{
free(s);
}
int search(struct searchable *s, const char *text, enum search_direction dir, int beginning)
{
struct iter iter;
int ret;
search_lock();
if (beginning) {
/* first or last item */
iter = s->head;
if (dir == SEARCH_FORWARD){
ret = s->ops.get_next(&iter);
} else {
ret = s->ops.get_prev(&iter);
}
} else {
/* selected item */
ret = s->ops.get_current(s->data, &iter);
}
if (ret)
ret = do_search(s, &iter, text, dir);
search_unlock();
return ret;
}
int search_next(struct searchable *s, const char *text, enum search_direction dir)
{
struct iter iter;
int ret;
search_lock();
if (!s->ops.get_current(s->data, &iter)) {
search_unlock();
return 0;
}
if (dir == SEARCH_FORWARD) {
ret = s->ops.get_next(&iter);
} else {
ret = s->ops.get_prev(&iter);
}
if (ret)
ret = do_search(s, &iter, text, dir);
search_unlock();
return ret;
}
|