screen: remove redundant #ifndef
[ncmpc.git] / src / filelist.c
blob0b85868ec6ddb5f065e053e69dfcfd85abbb4b5a
1 /* ncmpc (Ncurses MPD Client)
2 * (c) 2004-2017 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.
20 #include "filelist.h"
22 #include <mpd/client.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <assert.h>
28 struct filelist *
29 filelist_new(void)
31 struct filelist *filelist = g_malloc(sizeof(*filelist));
33 filelist->entries = g_ptr_array_new();
35 return filelist;
38 void
39 filelist_free(struct filelist *filelist)
41 for (unsigned i = 0; i < filelist_length(filelist); ++i) {
42 struct filelist_entry *entry = filelist_get(filelist, i);
44 if (entry->entity)
45 mpd_entity_free(entry->entity);
47 g_slice_free(struct filelist_entry, entry);
50 g_ptr_array_free(filelist->entries, TRUE);
51 g_free(filelist);
54 struct filelist_entry *
55 filelist_append(struct filelist *filelist, struct mpd_entity *entity)
57 struct filelist_entry *entry = g_slice_new(struct filelist_entry);
59 entry->flags = 0;
60 entry->entity = entity;
62 g_ptr_array_add(filelist->entries, entry);
64 return entry;
67 void
68 filelist_move(struct filelist *filelist, struct filelist *from)
70 for (unsigned i = 0; i < filelist_length(from); ++i)
71 g_ptr_array_add(filelist->entries,
72 g_ptr_array_index(from->entries, i));
74 g_ptr_array_set_size(from->entries, 0);
77 static gint
78 filelist_compare_indirect(gconstpointer ap, gconstpointer bp, gpointer data)
80 GCompareFunc compare_func = data;
81 gconstpointer a = *(const gconstpointer*)ap;
82 gconstpointer b = *(const gconstpointer*)bp;
84 return compare_func(a, b);
87 gint
88 compare_filelist_entry_path(gconstpointer filelist_entry1,
89 gconstpointer filelist_entry2)
91 const struct mpd_entity *e1, *e2;
93 e1 = ((const struct filelist_entry *)filelist_entry1)->entity;
94 e2 = ((const struct filelist_entry *)filelist_entry2)->entity;
96 int n = 0;
97 if (e1 != NULL && e2 != NULL &&
98 mpd_entity_get_type(e1) == mpd_entity_get_type(e2)) {
99 switch (mpd_entity_get_type(e1)) {
100 case MPD_ENTITY_TYPE_UNKNOWN:
101 break;
102 case MPD_ENTITY_TYPE_DIRECTORY:
103 n = g_utf8_collate(mpd_directory_get_path(mpd_entity_get_directory(e1)),
104 mpd_directory_get_path(mpd_entity_get_directory(e2)));
105 break;
106 case MPD_ENTITY_TYPE_SONG:
107 break;
108 case MPD_ENTITY_TYPE_PLAYLIST:
109 n = g_utf8_collate(mpd_playlist_get_path(mpd_entity_get_playlist(e1)),
110 mpd_playlist_get_path(mpd_entity_get_playlist(e2)));
113 return n;
116 /* Sorts the whole filelist, at the moment used by filelist_search */
117 void
118 filelist_sort_all(struct filelist *filelist, GCompareFunc compare_func)
120 g_ptr_array_sort_with_data(filelist->entries,
121 filelist_compare_indirect,
122 compare_func);
126 /* Only sorts the directories and playlist files.
127 * The songs stay in the order it came from mpd. */
128 void
129 filelist_sort_dir_play(struct filelist *filelist, GCompareFunc compare_func)
131 const struct mpd_entity *iter;
133 assert(filelist && filelist->entries);
135 if (filelist->entries->len < 2)
136 return;
138 /* If the first entry is NULL, skip it, because NULL stands for "[..]" */
139 iter = ((struct filelist_entry*) g_ptr_array_index(filelist->entries, 0))->entity;
140 unsigned first = iter == NULL ? 1 : 0, last;
142 /* find the last directory entry */
143 for (last = first+1; last < filelist->entries->len; last++) {
144 iter = ((struct filelist_entry*) g_ptr_array_index(filelist->entries, last))->entity;
145 if (mpd_entity_get_type(iter) != MPD_ENTITY_TYPE_DIRECTORY)
146 break;
148 if (last == filelist->entries->len - 1)
149 last++;
150 /* sort the directories */
151 if (last - first > 1)
152 g_qsort_with_data(filelist->entries->pdata + first,
153 last - first, sizeof(gpointer),
154 filelist_compare_indirect, compare_func);
155 /* find the first playlist entry */
156 for (first = last; first < filelist->entries->len; first++) {
157 iter = ((struct filelist_entry*) g_ptr_array_index(filelist->entries, first))->entity;
158 if (mpd_entity_get_type(iter) == MPD_ENTITY_TYPE_PLAYLIST)
159 break;
161 /* sort the playlist entries */
162 if (filelist->entries->len - first > 1)
163 g_qsort_with_data(filelist->entries->pdata + first,
164 filelist->entries->len - first, sizeof(gpointer),
165 filelist_compare_indirect, compare_func);
168 void
169 filelist_no_duplicates(struct filelist *filelist)
171 for (int i = filelist_length(filelist) - 1; i >= 0; --i) {
172 struct filelist_entry *entry = filelist_get(filelist, i);
173 const struct mpd_song *song;
175 if (entry->entity == NULL ||
176 mpd_entity_get_type(entry->entity) != MPD_ENTITY_TYPE_SONG)
177 continue;
179 song = mpd_entity_get_song(entry->entity);
180 if (filelist_find_song(filelist, song) < i) {
181 g_ptr_array_remove_index(filelist->entries, i);
182 mpd_entity_free(entry->entity);
183 g_slice_free(struct filelist_entry, entry);
188 static bool
189 same_song(const struct mpd_song *a, const struct mpd_song *b)
191 return strcmp(mpd_song_get_uri(a), mpd_song_get_uri(b)) == 0;
195 filelist_find_song(const struct filelist *fl, const struct mpd_song *song)
197 assert(song != NULL);
199 for (unsigned i = 0; i < filelist_length(fl); ++i) {
200 struct filelist_entry *entry = filelist_get(fl, i);
201 const struct mpd_entity *entity = entry->entity;
203 if (entity != NULL &&
204 mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
205 const struct mpd_song *song2 =
206 mpd_entity_get_song(entity);
208 if (same_song(song, song2))
209 return i;
213 return -1;
217 filelist_find_directory(const struct filelist *filelist, const char *name)
219 assert(name != NULL);
221 for (unsigned i = 0; i < filelist_length(filelist); ++i) {
222 struct filelist_entry *entry = filelist_get(filelist, i);
223 const struct mpd_entity *entity = entry->entity;
225 if (entity != NULL &&
226 mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_DIRECTORY &&
227 strcmp(mpd_directory_get_path(mpd_entity_get_directory(entity)),
228 name) == 0)
229 return i;
232 return -1;
235 void
236 filelist_recv(struct filelist *filelist, struct mpd_connection *connection)
238 struct mpd_entity *entity;
240 while ((entity = mpd_recv_entity(connection)) != NULL)
241 filelist_append(filelist, entity);
244 struct filelist *
245 filelist_new_recv(struct mpd_connection *connection)
247 struct filelist *filelist = filelist_new();
248 filelist_recv(filelist, connection);
249 return filelist;