configure.ac: Don't allow UNIX IPC to be configured for a native Windows build.
[mpd-mk.git] / src / songvec.c
blob38bcbac88448c6b1f1cc19eb62bbdbe33fb5ea17
1 /*
2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "config.h"
21 #include "songvec.h"
22 #include "song.h"
23 #include "tag.h"
25 #include <glib.h>
27 #include <assert.h>
28 #include <string.h>
29 #include <stdlib.h>
31 static GMutex *nr_lock = NULL;
33 static const char *
34 tag_get_value_checked(const struct tag *tag, enum tag_type type)
36 return tag != NULL
37 ? tag_get_value(tag, type)
38 : NULL;
41 static int
42 compare_utf8_string(const char *a, const char *b)
44 if (a == NULL)
45 return b == NULL ? 0 : -1;
47 if (b == NULL)
48 return 1;
50 return g_utf8_collate(a, b);
53 /**
54 * Compare two string tag values, ignoring case. Either one may be
55 * NULL.
57 static int
58 compare_string_tag_item(const struct tag *a, const struct tag *b,
59 enum tag_type type)
61 return compare_utf8_string(tag_get_value_checked(a, type),
62 tag_get_value_checked(b, type));
65 /**
66 * Compare two tag values which should contain an integer value
67 * (e.g. disc or track number). Either one may be NULL.
69 static int
70 compare_number_string(const char *a, const char *b)
72 long ai = a == NULL ? 0 : strtol(a, NULL, 10);
73 long bi = b == NULL ? 0 : strtol(b, NULL, 10);
75 if (ai <= 0)
76 return bi <= 0 ? 0 : -1;
78 if (bi <= 0)
79 return 1;
81 return ai - bi;
84 static int
85 compare_tag_item(const struct tag *a, const struct tag *b, enum tag_type type)
87 return compare_number_string(tag_get_value_checked(a, type),
88 tag_get_value_checked(b, type));
91 /* Only used for sorting/searchin a songvec, not general purpose compares */
92 static int songvec_cmp(const void *s1, const void *s2)
94 const struct song *a = ((const struct song * const *)s1)[0];
95 const struct song *b = ((const struct song * const *)s2)[0];
96 int ret;
98 /* first sort by album */
99 ret = compare_string_tag_item(a->tag, b->tag, TAG_ALBUM);
100 if (ret != 0)
101 return ret;
103 /* then sort by disc */
104 ret = compare_tag_item(a->tag, b->tag, TAG_DISC);
105 if (ret != 0)
106 return ret;
108 /* then by track number */
109 ret = compare_tag_item(a->tag, b->tag, TAG_TRACK);
110 if (ret != 0)
111 return ret;
113 /* still no difference? compare file name */
114 return g_utf8_collate(a->uri, b->uri);
117 static size_t sv_size(const struct songvec *sv)
119 return sv->nr * sizeof(struct song *);
122 void songvec_init(void)
124 g_assert(nr_lock == NULL);
125 nr_lock = g_mutex_new();
128 void songvec_deinit(void)
130 g_assert(nr_lock != NULL);
131 g_mutex_free(nr_lock);
132 nr_lock = NULL;
135 void songvec_sort(struct songvec *sv)
137 g_mutex_lock(nr_lock);
138 qsort(sv->base, sv->nr, sizeof(struct song *), songvec_cmp);
139 g_mutex_unlock(nr_lock);
142 struct song *
143 songvec_find(const struct songvec *sv, const char *uri)
145 int i;
146 struct song *ret = NULL;
148 g_mutex_lock(nr_lock);
149 for (i = sv->nr; --i >= 0; ) {
150 if (strcmp(sv->base[i]->uri, uri))
151 continue;
152 ret = sv->base[i];
153 break;
155 g_mutex_unlock(nr_lock);
156 return ret;
160 songvec_delete(struct songvec *sv, const struct song *del)
162 size_t i;
164 g_mutex_lock(nr_lock);
165 for (i = 0; i < sv->nr; ++i) {
166 if (sv->base[i] != del)
167 continue;
168 /* we _don't_ call song_free() here */
169 if (!--sv->nr) {
170 g_free(sv->base);
171 sv->base = NULL;
172 } else {
173 memmove(&sv->base[i], &sv->base[i + 1],
174 (sv->nr - i) * sizeof(struct song *));
175 sv->base = g_realloc(sv->base, sv_size(sv));
177 g_mutex_unlock(nr_lock);
178 return i;
180 g_mutex_unlock(nr_lock);
182 return -1; /* not found */
185 void
186 songvec_add(struct songvec *sv, struct song *add)
188 g_mutex_lock(nr_lock);
189 ++sv->nr;
190 sv->base = g_realloc(sv->base, sv_size(sv));
191 sv->base[sv->nr - 1] = add;
192 g_mutex_unlock(nr_lock);
195 void songvec_destroy(struct songvec *sv)
197 g_mutex_lock(nr_lock);
198 sv->nr = 0;
199 g_mutex_unlock(nr_lock);
201 g_free(sv->base);
202 sv->base = NULL;
206 songvec_for_each(const struct songvec *sv,
207 int (*fn)(struct song *, void *), void *arg)
209 size_t i;
210 size_t prev_nr;
212 g_mutex_lock(nr_lock);
213 for (i = 0; i < sv->nr; ) {
214 struct song *song = sv->base[i];
216 assert(song);
217 assert(*song->uri);
219 prev_nr = sv->nr;
220 g_mutex_unlock(nr_lock); /* fn() may block */
221 if (fn(song, arg) < 0)
222 return -1;
223 g_mutex_lock(nr_lock); /* sv->nr may change in fn() */
224 if (prev_nr == sv->nr)
225 ++i;
227 g_mutex_unlock(nr_lock);
229 return 0;