Handle streams separately in tree_add_track()
[cmus.git] / search.c
blob9efb6cd3e6c3e35d5d7f92d2bf9c71ee713f21a0
1 /*
2 * Copyright Timo Hirvonen
3 */
5 #include "search.h"
6 #include "editable.h"
7 #include "xmalloc.h"
9 struct searchable {
10 void *data;
11 struct iter head;
12 struct searchable_ops ops;
15 static void search_lock(void)
17 editable_lock();
20 static void search_unlock(void)
22 editable_unlock();
25 /* returns next matching track (can be current!) or NULL if not found */
26 static int do_search(struct searchable *s, struct iter *iter, const char *text, int direction)
28 while (1) {
29 if (s->ops.matches(s->data, iter, text))
30 return 1;
31 if (direction == SEARCH_FORWARD) {
32 if (!s->ops.get_next(iter))
33 return 0;
34 } else {
35 if (!s->ops.get_prev(iter))
36 return 0;
41 struct searchable *searchable_new(void *data, const struct iter *head, const struct searchable_ops *ops)
43 struct searchable *s;
45 s = xnew(struct searchable, 1);
46 s->data = data;
47 s->head = *head;
48 s->ops = *ops;
49 return s;
52 void searchable_free(struct searchable *s)
54 free(s);
57 int search(struct searchable *s, const char *text, enum search_direction dir, int beginning)
59 struct iter iter;
60 int ret;
62 search_lock();
63 if (beginning) {
64 /* first or last item */
65 iter = s->head;
66 if (dir == SEARCH_FORWARD) {
67 ret = s->ops.get_next(&iter);
68 } else {
69 ret = s->ops.get_prev(&iter);
71 } else {
72 /* selected item */
73 ret = s->ops.get_current(s->data, &iter);
75 if (ret)
76 ret = do_search(s, &iter, text, dir);
77 search_unlock();
78 return ret;
81 int search_next(struct searchable *s, const char *text, enum search_direction dir)
83 struct iter iter;
84 int ret;
86 search_lock();
87 if (!s->ops.get_current(s->data, &iter)) {
88 search_unlock();
89 return 0;
91 if (dir == SEARCH_FORWARD) {
92 ret = s->ops.get_next(&iter);
93 } else {
94 ret = s->ops.get_prev(&iter);
96 if (ret)
97 ret = do_search(s, &iter, text, dir);
98 search_unlock();
99 return ret;