Disable TCP/IP server support
[cmus.git] / track.c
blobc8c9ef853ae573b5884aa9b79647b126946dfec5
1 /*
2 * Copyright 2006 Timo Hirvonen
3 */
5 #include "track.h"
6 #include "iter.h"
7 #include "track_info.h"
8 #include "search_mode.h"
9 #include "window.h"
10 #include "options.h"
11 #include "comment.h"
12 #include "uchar.h"
13 #include "xmalloc.h"
15 #include <string.h>
17 static int xstrcasecmp(const char *a, const char *b)
19 if (a == NULL) {
20 if (b == NULL)
21 return 0;
22 return -1;
23 } else if (b == NULL) {
24 return 1;
26 return u_strcasecmp(a, b);
29 void simple_track_init(struct simple_track *track, struct track_info *ti)
31 track->info = ti;
32 track->marked = 0;
33 track->disc = comments_get_int(ti->comments, "discnumber");
34 track->num = comments_get_int(ti->comments, "tracknumber");
37 struct simple_track *simple_track_new(struct track_info *ti)
39 struct simple_track *t = xnew(struct simple_track, 1);
41 track_info_ref(ti);
42 simple_track_init(t, ti);
43 return t;
46 GENERIC_ITER_PREV(simple_track_get_prev, struct simple_track, node)
47 GENERIC_ITER_NEXT(simple_track_get_next, struct simple_track, node)
49 int simple_track_search_get_current(void *data, struct iter *iter)
51 return window_get_sel(data, iter);
54 int simple_track_search_matches(void *data, struct iter *iter, const char *text)
56 unsigned int flags = TI_MATCH_TITLE;
57 struct simple_track *track = iter_to_simple_track(iter);
59 if (!search_restricted)
60 flags |= TI_MATCH_ARTIST | TI_MATCH_ALBUM;
62 if (!track_info_matches(track->info, text, flags))
63 return 0;
65 window_set_sel(data, iter);
66 return 1;
69 struct shuffle_track *shuffle_list_get_next(struct list_head *head, struct shuffle_track *cur,
70 int (*filter)(const struct simple_track *))
72 struct list_head *item;
74 if (cur == NULL)
75 return to_shuffle_track(head->next);
77 item = cur->node.next;
78 again:
79 while (item != head) {
80 struct shuffle_track *track = to_shuffle_track(item);
82 if (filter((struct simple_track *)track))
83 return track;
84 item = item->next;
86 if (repeat) {
87 if (auto_reshuffle)
88 reshuffle(head);
89 item = head->next;
90 goto again;
92 return NULL;
95 struct shuffle_track *shuffle_list_get_prev(struct list_head *head, struct shuffle_track *cur,
96 int (*filter)(const struct simple_track *))
98 struct list_head *item;
100 if (cur == NULL)
101 return to_shuffle_track(head->next);
103 item = cur->node.prev;
104 again:
105 while (item != head) {
106 struct shuffle_track *track = to_shuffle_track(item);
108 if (filter((struct simple_track *)track))
109 return track;
110 item = item->prev;
112 if (repeat) {
113 if (auto_reshuffle)
114 reshuffle(head);
115 item = head->prev;
116 goto again;
118 return NULL;
121 struct simple_track *simple_list_get_next(struct list_head *head, struct simple_track *cur,
122 int (*filter)(const struct simple_track *))
124 struct list_head *item;
126 if (cur == NULL)
127 return to_simple_track(head->next);
129 item = cur->node.next;
130 again:
131 while (item != head) {
132 struct simple_track *track = to_simple_track(item);
134 if (filter(track))
135 return track;
136 item = item->next;
138 item = head->next;
139 if (repeat)
140 goto again;
141 return NULL;
144 struct simple_track *simple_list_get_prev(struct list_head *head, struct simple_track *cur,
145 int (*filter)(const struct simple_track *))
147 struct list_head *item;
149 if (cur == NULL)
150 return to_simple_track(head->next);
152 item = cur->node.prev;
153 again:
154 while (item != head) {
155 struct simple_track *track = to_simple_track(item);
157 if (filter(track))
158 return track;
159 item = item->prev;
161 item = head->prev;
162 if (repeat)
163 goto again;
164 return NULL;
167 int simple_track_cmp(const struct list_head *a_head, const struct list_head *b_head, const char * const *keys)
169 const struct simple_track *a = to_simple_track(a_head);
170 const struct simple_track *b = to_simple_track(b_head);
171 int i, res = 0;
173 for (i = 0; keys[i]; i++) {
174 const char *key = keys[i];
175 const char *av, *bv;
176 const struct track_info *ai, *bi;
178 /* numeric compare for tracknumber and discnumber */
179 if (strcmp(key, "tracknumber") == 0) {
180 res = a->num - b->num;
181 if (res)
182 break;
183 continue;
185 if (strcmp(key, "discnumber") == 0) {
186 res = a->disc - b->disc;
187 if (res)
188 break;
189 continue;
191 ai = a->info;
192 bi = b->info;
193 if (strcmp(key, "filename") == 0) {
194 /* NOTE: filenames are not necessarily UTF-8 */
195 res = strcasecmp(ai->filename, bi->filename);
196 if (res)
197 break;
198 continue;
200 av = comments_get_val(ai->comments, key);
201 bv = comments_get_val(bi->comments, key);
202 res = xstrcasecmp(av, bv);
203 if (res)
204 break;
206 return res;
209 void sorted_list_add_track(struct list_head *head, struct simple_track *track, const char * const *keys)
211 struct list_head *item;
213 /* It is _much_ faster to iterate in reverse order because playlist
214 * file is usually sorted.
216 item = head->prev;
217 while (item != head) {
218 if (simple_track_cmp(&track->node, item, keys) >= 0)
219 break;
220 item = item->prev;
222 /* add after item */
223 list_add(&track->node, item);
226 void shuffle_list_add_track(struct list_head *head, struct list_head *node, int nr)
228 struct list_head *item;
229 int pos;
231 pos = rand() % (nr + 1);
232 item = head;
233 if (pos <= nr / 2) {
234 while (pos) {
235 item = item->next;
236 pos--;
238 /* add after item */
239 list_add(node, item);
240 } else {
241 pos = nr - pos;
242 while (pos) {
243 item = item->prev;
244 pos--;
246 /* add before item */
247 list_add_tail(node, item);
251 void reshuffle(struct list_head *head)
253 struct list_head *item, *last;
254 int i = 0;
256 if (list_empty(head))
257 return;
259 last = head->prev;
260 item = head->next;
261 list_init(head);
263 while (1) {
264 struct list_head *next = item->next;
266 shuffle_list_add_track(head, item, i++);
267 if (item == last)
268 break;
269 item = next;
273 int simple_list_for_each_marked(struct list_head *head,
274 int (*cb)(void *data, struct track_info *ti), void *data, int reverse)
276 struct simple_track *t;
277 int rc = 0;
279 if (reverse) {
280 list_for_each_entry_reverse(t, head, node) {
281 if (t->marked) {
282 rc = cb(data, t->info);
283 if (rc)
284 break;
287 } else {
288 list_for_each_entry(t, head, node) {
289 if (t->marked) {
290 rc = cb(data, t->info);
291 if (rc)
292 break;
296 return rc;