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.
31 static GMutex
*nr_lock
= NULL
;
34 tag_get_value_checked(const struct tag
*tag
, enum tag_type type
)
37 ? tag_get_value(tag
, type
)
42 compare_utf8_string(const char *a
, const char *b
)
45 return b
== NULL
? 0 : -1;
50 return g_utf8_collate(a
, b
);
54 * Compare two string tag values, ignoring case. Either one may be
58 compare_string_tag_item(const struct tag
*a
, const struct tag
*b
,
61 return compare_utf8_string(tag_get_value_checked(a
, type
),
62 tag_get_value_checked(b
, type
));
66 * Compare two tag values which should contain an integer value
67 * (e.g. disc or track number). Either one may be NULL.
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);
76 return bi
<= 0 ? 0 : -1;
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];
98 /* first sort by album */
99 ret
= compare_string_tag_item(a
->tag
, b
->tag
, TAG_ALBUM
);
103 /* then sort by disc */
104 ret
= compare_tag_item(a
->tag
, b
->tag
, TAG_DISC
);
108 /* then by track number */
109 ret
= compare_tag_item(a
->tag
, b
->tag
, TAG_TRACK
);
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
);
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
);
143 songvec_find(const struct songvec
*sv
, const char *uri
)
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
))
155 g_mutex_unlock(nr_lock
);
160 songvec_delete(struct songvec
*sv
, const struct song
*del
)
164 g_mutex_lock(nr_lock
);
165 for (i
= 0; i
< sv
->nr
; ++i
) {
166 if (sv
->base
[i
] != del
)
168 /* we _don't_ call song_free() here */
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
);
180 g_mutex_unlock(nr_lock
);
182 return -1; /* not found */
186 songvec_add(struct songvec
*sv
, struct song
*add
)
188 g_mutex_lock(nr_lock
);
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
);
199 g_mutex_unlock(nr_lock
);
206 songvec_for_each(const struct songvec
*sv
,
207 int (*fn
)(struct song
*, void *), void *arg
)
212 g_mutex_lock(nr_lock
);
213 for (i
= 0; i
< sv
->nr
; ) {
214 struct song
*song
= sv
->base
[i
];
220 g_mutex_unlock(nr_lock
); /* fn() may block */
221 if (fn(song
, arg
) < 0)
223 g_mutex_lock(nr_lock
); /* sv->nr may change in fn() */
224 if (prev_nr
== sv
->nr
)
227 g_mutex_unlock(nr_lock
);