1 /* ncmpc (Ncurses MPD Client)
2 * (c) 2004-2010 The Music Player Daemon Project
3 * Project homepage: http://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.
22 #include <mpd/client.h>
31 struct filelist
*filelist
= g_malloc(sizeof(*filelist
));
33 filelist
->entries
= g_ptr_array_new();
39 filelist_free(struct filelist
*filelist
)
43 for (i
= 0; i
< filelist_length(filelist
); ++i
) {
44 struct filelist_entry
*entry
= filelist_get(filelist
, i
);
47 mpd_entity_free(entry
->entity
);
49 g_slice_free(struct filelist_entry
, entry
);
52 g_ptr_array_free(filelist
->entries
, TRUE
);
56 struct filelist_entry
*
57 filelist_append(struct filelist
*filelist
, struct mpd_entity
*entity
)
59 struct filelist_entry
*entry
= g_slice_new(struct filelist_entry
);
62 entry
->entity
= entity
;
64 g_ptr_array_add(filelist
->entries
, entry
);
70 filelist_move(struct filelist
*filelist
, struct filelist
*from
)
74 for (i
= 0; i
< filelist_length(from
); ++i
)
75 g_ptr_array_add(filelist
->entries
,
76 g_ptr_array_index(from
->entries
, i
));
78 g_ptr_array_set_size(from
->entries
, 0);
82 filelist_compare_indirect(gconstpointer ap
, gconstpointer bp
, gpointer data
)
84 GCompareFunc compare_func
= data
;
85 gconstpointer a
= *(const gconstpointer
*)ap
;
86 gconstpointer b
= *(const gconstpointer
*)bp
;
88 return compare_func(a
, b
);
92 compare_filelist_entry_path(gconstpointer filelist_entry1
,
93 gconstpointer filelist_entry2
)
95 const struct mpd_entity
*e1
, *e2
;
98 e1
= ((const struct filelist_entry
*)filelist_entry1
)->entity
;
99 e2
= ((const struct filelist_entry
*)filelist_entry2
)->entity
;
101 if (e1
!= NULL
&& e2
!= NULL
&&
102 mpd_entity_get_type(e1
) == mpd_entity_get_type(e2
)) {
103 switch (mpd_entity_get_type(e1
)) {
104 case MPD_ENTITY_TYPE_UNKNOWN
:
106 case MPD_ENTITY_TYPE_DIRECTORY
:
107 n
= g_utf8_collate(mpd_directory_get_path(mpd_entity_get_directory(e1
)),
108 mpd_directory_get_path(mpd_entity_get_directory(e2
)));
110 case MPD_ENTITY_TYPE_SONG
:
112 case MPD_ENTITY_TYPE_PLAYLIST
:
113 n
= g_utf8_collate(mpd_playlist_get_path(mpd_entity_get_playlist(e1
)),
114 mpd_playlist_get_path(mpd_entity_get_playlist(e2
)));
120 /* Sorts the whole filelist, at the moment used by filelist_search */
122 filelist_sort_all(struct filelist
*filelist
, GCompareFunc compare_func
)
124 g_ptr_array_sort_with_data(filelist
->entries
,
125 filelist_compare_indirect
,
130 /* Only sorts the directories and playlist files.
131 * The songs stay in the order it came from mpd. */
133 filelist_sort_dir_play(struct filelist
*filelist
, GCompareFunc compare_func
)
135 unsigned first
, last
;
136 const struct mpd_entity
*iter
;
138 assert(filelist
&& filelist
->entries
);
140 if (filelist
->entries
->len
< 2)
143 /* If the first entry is NULL, skip it, because NULL stands for "[..]" */
144 iter
= ((struct filelist_entry
*) g_ptr_array_index(filelist
->entries
, 0))->entity
;
145 first
= (iter
== NULL
)? 1 : 0;
147 /* find the last directory entry */
148 for (last
= first
+1; last
< filelist
->entries
->len
; last
++) {
149 iter
= ((struct filelist_entry
*) g_ptr_array_index(filelist
->entries
, last
))->entity
;
150 if (mpd_entity_get_type(iter
) != MPD_ENTITY_TYPE_DIRECTORY
)
153 if (last
== filelist
->entries
->len
- 1)
155 /* sort the directories */
156 if (last
- first
> 1)
157 g_qsort_with_data(filelist
->entries
->pdata
+ first
,
158 last
- first
, sizeof(gpointer
),
159 filelist_compare_indirect
, compare_func
);
160 /* find the first playlist entry */
161 for (first
= last
; first
< filelist
->entries
->len
; first
++) {
162 iter
= ((struct filelist_entry
*) g_ptr_array_index(filelist
->entries
, first
))->entity
;
163 if (mpd_entity_get_type(iter
) == MPD_ENTITY_TYPE_PLAYLIST
)
166 /* sort the playlist entries */
167 if (filelist
->entries
->len
- first
> 1)
168 g_qsort_with_data(filelist
->entries
->pdata
+ first
,
169 filelist
->entries
->len
- first
, sizeof(gpointer
),
170 filelist_compare_indirect
, compare_func
);
174 filelist_no_duplicates(struct filelist
*filelist
)
176 for (int i
= filelist_length(filelist
) - 1; i
>= 0; --i
) {
177 struct filelist_entry
*entry
= filelist_get(filelist
, i
);
178 const struct mpd_song
*song
;
180 if (entry
->entity
== NULL
||
181 mpd_entity_get_type(entry
->entity
) != MPD_ENTITY_TYPE_SONG
)
184 song
= mpd_entity_get_song(entry
->entity
);
185 if (filelist_find_song(filelist
, song
) < i
) {
186 g_ptr_array_remove_index(filelist
->entries
, i
);
187 mpd_entity_free(entry
->entity
);
188 g_slice_free(struct filelist_entry
, entry
);
194 same_song(const struct mpd_song
*a
, const struct mpd_song
*b
)
196 return strcmp(mpd_song_get_uri(a
), mpd_song_get_uri(b
)) == 0;
200 filelist_find_song(struct filelist
*fl
, const struct mpd_song
*song
)
204 assert(song
!= NULL
);
206 for (i
= 0; i
< filelist_length(fl
); ++i
) {
207 struct filelist_entry
*entry
= filelist_get(fl
, i
);
208 const struct mpd_entity
*entity
= entry
->entity
;
210 if (entity
!= NULL
&&
211 mpd_entity_get_type(entity
) == MPD_ENTITY_TYPE_SONG
) {
212 const struct mpd_song
*song2
=
213 mpd_entity_get_song(entity
);
215 if (same_song(song
, song2
))
224 filelist_find_directory(struct filelist
*filelist
, const char *name
)
228 assert(name
!= NULL
);
230 for (i
= 0; i
< filelist_length(filelist
); ++i
) {
231 struct filelist_entry
*entry
= filelist_get(filelist
, i
);
232 const struct mpd_entity
*entity
= entry
->entity
;
234 if (entity
!= NULL
&&
235 mpd_entity_get_type(entity
) == MPD_ENTITY_TYPE_DIRECTORY
&&
236 strcmp(mpd_directory_get_path(mpd_entity_get_directory(entity
)),
245 filelist_recv(struct filelist
*filelist
, struct mpd_connection
*connection
)
247 struct mpd_entity
*entity
;
249 while ((entity
= mpd_recv_entity(connection
)) != NULL
)
250 filelist_append(filelist
, entity
);
254 filelist_new_recv(struct mpd_connection
*connection
)
256 struct filelist
*filelist
= filelist_new();
257 filelist_recv(filelist
, connection
);