diff options
author | Max Kellermann <max@duempel.org> | 2011-09-10 19:24:30 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2011-09-13 19:37:28 +0200 |
commit | 169db88c20dc7601f8589cfa298254c932f0947a (patch) | |
tree | b0cc3af153237379a1dbbb2fa90eb37eed05752f | |
parent | ca419c84b83d017c3e4309e22f92273500197eea (diff) | |
download | mpd-169db88c20dc7601f8589cfa298254c932f0947a.tar.gz mpd-169db88c20dc7601f8589cfa298254c932f0947a.tar.xz mpd-169db88c20dc7601f8589cfa298254c932f0947a.zip |
database: add struct db_visitor
Use this struct for db_walk().
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/command.c | 91 | ||||
-rw-r--r-- | src/database.c | 34 | ||||
-rw-r--r-- | src/database.h | 8 | ||||
-rw-r--r-- | src/dbUtils.c | 91 | ||||
-rw-r--r-- | src/dbUtils.h | 8 | ||||
-rw-r--r-- | src/db_error.h | 39 | ||||
-rw-r--r-- | src/db_print.c | 144 | ||||
-rw-r--r-- | src/db_print.h | 31 | ||||
-rw-r--r-- | src/db_visitor.h | 43 | ||||
-rw-r--r-- | src/directory.c | 44 | ||||
-rw-r--r-- | src/directory.h | 10 | ||||
-rw-r--r-- | src/stats.c | 14 |
13 files changed, 363 insertions, 196 deletions
diff --git a/Makefile.am b/Makefile.am index b883531f2..4b69a8d59 100644 --- a/Makefile.am +++ b/Makefile.am @@ -271,9 +271,11 @@ src_mpd_SOURCES = \ src/directory_save.c \ src/directory_print.c \ src/database.c \ + src/db_error.h \ src/db_save.c src/db_save.h \ src/db_print.c src/db_print.h \ src/db_plugin.h \ + src/db_visitor.h \ src/db/simple_db_plugin.c src/db/simple_db_plugin.h \ src/dirvec.c \ src/exclude.c \ diff --git a/src/command.c b/src/command.c index 42d09cf8d..864b65354 100644 --- a/src/command.c +++ b/src/command.c @@ -43,6 +43,7 @@ #include "output_print.h" #include "locate.h" #include "dbUtils.h" +#include "db_error.h" #include "db_print.h" #include "tag.h" #include "client.h" @@ -392,6 +393,13 @@ print_error(struct client *client, GError *error) enum playlist_result result = error->code; g_error_free(error); return print_playlist_result(client, result); + } else if (error->domain == db_quark()) { + switch ((enum db_error)error->code) { + case DB_NOT_FOUND: + g_error_free(error); + command_error(client, ACK_ERROR_NO_EXIST, "Not found"); + return COMMAND_RETURN_ERROR; + } } else if (error->domain == g_file_error_quark()) { command_error(client, ACK_ERROR_SYSTEM, "%s", g_strerror(error->code)); @@ -657,14 +665,10 @@ handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) return print_playlist_result(client, result); } - result = addAllIn(client->player_control, uri); - if (result == (enum playlist_result)-1) { - command_error(client, ACK_ERROR_NO_EXIST, - "directory or file not found"); - return COMMAND_RETURN_ERROR; - } - - return print_playlist_result(client, result); + GError *error = NULL; + return addAllIn(client->player_control, uri, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); } static enum command_return @@ -941,7 +945,6 @@ handle_playlistid(struct client *client, int argc, char *argv[]) static enum command_return handle_find(struct client *client, int argc, char *argv[]) { - int ret; struct locate_item_list *list = locate_item_list_parse(argv + 1, argc - 1); @@ -953,10 +956,10 @@ handle_find(struct client *client, int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - ret = findSongsIn(client, NULL, list); - if (ret == -1) - command_error(client, ACK_ERROR_NO_EXIST, - "directory or file not found"); + GError *error = NULL; + enum command_return ret = findSongsIn(client, NULL, list, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); locate_item_list_free(list); @@ -966,7 +969,6 @@ handle_find(struct client *client, int argc, char *argv[]) static enum command_return handle_findadd(struct client *client, int argc, char *argv[]) { - int ret; struct locate_item_list *list = locate_item_list_parse(argv + 1, argc - 1); if (list == NULL || list->length == 0) { @@ -977,10 +979,11 @@ handle_findadd(struct client *client, int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - ret = findAddIn(client->player_control, NULL, list); - if (ret == -1) - command_error(client, ACK_ERROR_NO_EXIST, - "directory or file not found"); + GError *error = NULL; + enum command_return ret = + findAddIn(client->player_control, NULL, list, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); locate_item_list_free(list); @@ -990,7 +993,6 @@ handle_findadd(struct client *client, int argc, char *argv[]) static enum command_return handle_search(struct client *client, int argc, char *argv[]) { - int ret; struct locate_item_list *list = locate_item_list_parse(argv + 1, argc - 1); @@ -1002,10 +1004,10 @@ handle_search(struct client *client, int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - ret = searchForSongsIn(client, NULL, list); - if (ret == -1) - command_error(client, ACK_ERROR_NO_EXIST, - "directory or file not found"); + GError *error = NULL; + enum command_return ret = searchForSongsIn(client, NULL, list, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); locate_item_list_free(list); @@ -1015,7 +1017,6 @@ handle_search(struct client *client, int argc, char *argv[]) static enum command_return handle_count(struct client *client, int argc, char *argv[]) { - int ret; struct locate_item_list *list = locate_item_list_parse(argv + 1, argc - 1); @@ -1027,10 +1028,11 @@ handle_count(struct client *client, int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - ret = searchStatsForSongsIn(client, NULL, list); - if (ret == -1) - command_error(client, ACK_ERROR_NO_EXIST, - "directory or file not found"); + GError *error = NULL; + enum command_return ret = + searchStatsForSongsIn(client, NULL, list, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); locate_item_list_free(list); @@ -1259,17 +1261,14 @@ static enum command_return handle_listall(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) { char *directory = NULL; - int ret; if (argc == 2) directory = argv[1]; - ret = printAllIn(client, directory); - if (ret == -1) - command_error(client, ACK_ERROR_NO_EXIST, - "directory or file not found"); - - return ret; + GError *error = NULL; + return printAllIn(client, directory, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); } static enum command_return @@ -1388,7 +1387,6 @@ handle_list(struct client *client, int argc, char *argv[]) { struct locate_item_list *conditionals; int tagType = locate_parse_type(argv[1]); - int ret; if (tagType < 0) { command_error(client, ACK_ERROR_ARG, "\"%s\" is not known", argv[1]); @@ -1425,14 +1423,14 @@ handle_list(struct client *client, int argc, char *argv[]) } } - ret = listAllUniqueTags(client, tagType, conditionals); + GError *error = NULL; + enum command_return ret = + listAllUniqueTags(client, tagType, conditionals, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); locate_item_list_free(conditionals); - if (ret == -1) - command_error(client, ACK_ERROR_NO_EXIST, - "directory or file not found"); - return ret; } @@ -1534,17 +1532,14 @@ static enum command_return handle_listallinfo(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) { char *directory = NULL; - int ret; if (argc == 2) directory = argv[1]; - ret = printInfoForAllIn(client, directory); - if (ret == -1) - command_error(client, ACK_ERROR_NO_EXIST, - "directory or file not found"); - - return ret; + GError *error = NULL; + return printInfoForAllIn(client, directory, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); } static enum command_return diff --git a/src/database.c b/src/database.c index ea7f01eb1..6d7cc3e23 100644 --- a/src/database.c +++ b/src/database.c @@ -19,7 +19,9 @@ #include "config.h" #include "database.h" +#include "db_error.h" #include "db_save.h" +#include "db_visitor.h" #include "db_plugin.h" #include "db/simple_db_plugin.h" #include "directory.h" @@ -41,15 +43,6 @@ static struct db *db; static bool db_is_open; -/** - * The quark used for GError.domain. - */ -static inline GQuark -db_quark(void) -{ - return g_quark_from_static_string("database"); -} - bool db_init(const struct config_param *path, GError **error_r) { @@ -114,25 +107,28 @@ db_get_song(const char *file) return directory_lookup_song(music_root, file); } -int -db_walk(const char *name, - int (*forEachSong)(struct song *, void *), - int (*forEachDir)(struct directory *, void *), void *data) +bool +db_walk(const char *uri, + const struct db_visitor *visitor, void *ctx, + GError **error_r) { struct directory *directory; if (db == NULL) return -1; - if ((directory = db_get_directory(name)) == NULL) { + if ((directory = db_get_directory(uri)) == NULL) { struct song *song; - if ((song = db_get_song(name)) && forEachSong) { - return forEachSong(song, data); - } - return -1; + if (visitor->song != NULL && + (song = db_get_song(uri)) != NULL) + return visitor->song(song, ctx, error_r); + + g_set_error(error_r, db_quark(), DB_NOT_FOUND, + "No such directory: %s", uri); + return false; } - return directory_walk(directory, forEachSong, forEachDir, data); + return directory_walk(directory, visitor, ctx, error_r); } bool diff --git a/src/database.h b/src/database.h index 3e834ab84..ab9114f2d 100644 --- a/src/database.h +++ b/src/database.h @@ -27,6 +27,7 @@ struct config_param; struct directory; +struct db_visitor; /** * Initialize the database library. @@ -52,9 +53,10 @@ db_get_directory(const char *name); struct song * db_get_song(const char *file); -int db_walk(const char *name, - int (*forEachSong)(struct song *, void *), - int (*forEachDir)(struct directory *, void *), void *data); +bool +db_walk(const char *uri, + const struct db_visitor *visitor, void *ctx, + GError **error_r); bool db_check(GError **error_r); diff --git a/src/dbUtils.c b/src/dbUtils.c index e0d8c5379..827d0a0c1 100644 --- a/src/dbUtils.c +++ b/src/dbUtils.c @@ -21,52 +21,66 @@ #include "dbUtils.h" #include "locate.h" #include "database.h" +#include "db_visitor.h" #include "playlist.h" #include "stored_playlist.h" #include <glib.h> -static int -directoryAddSongToPlaylist(struct song *song, void *data) +static bool +add_to_queue_song(struct song *song, void *ctx, GError **error_r) { - struct player_control *pc = data; + struct player_control *pc = ctx; + + enum playlist_result result = + playlist_append_song(&g_playlist, pc, song, NULL); + if (result != PLAYLIST_RESULT_SUCCESS) { + g_set_error(error_r, playlist_quark(), result, + "Playlist error"); + return false; + } + + return true; +} + +static const struct db_visitor add_to_queue_visitor = { + .song = add_to_queue_song, +}; - return playlist_append_song(&g_playlist, pc, song, NULL); +bool +addAllIn(struct player_control *pc, const char *uri, GError **error_r) +{ + return db_walk(uri, &add_to_queue_visitor, pc, error_r); } struct add_data { const char *path; - GError **error_r; }; -static int -directoryAddSongToStoredPlaylist(struct song *song, void *_data) +static bool +add_to_spl_song(struct song *song, void *ctx, GError **error_r) { - struct add_data *data = _data; + struct add_data *data = ctx; - if (!spl_append_song(data->path, song, data->error_r)) { - return -1; - } + if (!spl_append_song(data->path, song, error_r)) + return false; - return 0; + return true; } -int -addAllIn(struct player_control *pc, const char *name) -{ - return db_walk(name, directoryAddSongToPlaylist, NULL, pc); -} +static const struct db_visitor add_to_spl_visitor = { + .song = add_to_spl_song, +}; bool -addAllInToStoredPlaylist(const char *name, const char *utf8file, +addAllInToStoredPlaylist(const char *uri_utf8, const char *path_utf8, GError **error_r) { struct add_data data = { - .path = utf8file, - .error_r = error_r, + .path = path_utf8, }; - return db_walk(name, directoryAddSongToStoredPlaylist, NULL, &data) == 0; + return db_walk(uri_utf8, &add_to_spl_visitor, &data, error_r); } struct find_add_data { @@ -74,26 +88,37 @@ struct find_add_data { const struct locate_item_list *criteria; }; -static int -findAddInDirectory(struct song *song, void *_data) +static bool +find_add_song(struct song *song, void *ctx, GError **error_r) { - struct find_add_data *data = _data; - - if (locate_song_match(song, data->criteria)) - return playlist_append_song(&g_playlist, - data->pc, - song, NULL); + struct find_add_data *data = ctx; + + if (!locate_song_match(song, data->criteria)) + return true; + + enum playlist_result result = + playlist_append_song(&g_playlist, data->pc, + song, NULL); + if (result != PLAYLIST_RESULT_SUCCESS) { + g_set_error(error_r, playlist_quark(), result, + "Playlist error"); + return false; + } - return 0; + return true; } -int +static const struct db_visitor find_add_visitor = { + .song = find_add_song, +}; + +bool findAddIn(struct player_control *pc, const char *name, - const struct locate_item_list *criteria) + const struct locate_item_list *criteria, GError **error_r) { struct find_add_data data; data.pc = pc; data.criteria = criteria; - return db_walk(name, findAddInDirectory, NULL, &data); + return db_walk(name, &find_add_visitor, &data, error_r); } diff --git a/src/dbUtils.h b/src/dbUtils.h index 65349a32f..f693a7793 100644 --- a/src/dbUtils.h +++ b/src/dbUtils.h @@ -26,16 +26,16 @@ struct locate_item_list; struct player_control; -int -addAllIn(struct player_control *pc, const char *name); +bool +addAllIn(struct player_control *pc, const char *uri, GError **error_r); bool addAllInToStoredPlaylist(const char *uri_utf8, const char *path_utf8, GError **error_r); -int +bool findAddIn(struct player_control *pc, const char *name, - const struct locate_item_list *criteria); + const struct locate_item_list *criteria, GError **error_r); unsigned long sumSongTimesIn(const char *name); diff --git a/src/db_error.h b/src/db_error.h new file mode 100644 index 000000000..35051c40c --- /dev/null +++ b/src/db_error.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_DB_ERROR_H +#define MPD_DB_ERROR_H + +#include <glib.h> + +enum db_error { + DB_NOT_FOUND, +}; + +/** + * Quark for GError.domain; the code is an enum #db_error. + */ +G_GNUC_CONST +static inline GQuark +db_quark(void) +{ + return g_quark_from_static_string("db"); +} + +#endif diff --git a/src/db_print.c b/src/db_print.c index 629832a3d..c4086a387 100644 --- a/src/db_print.c +++ b/src/db_print.c @@ -19,6 +19,7 @@ #include "config.h" #include "db_print.h" +#include "db_visitor.h" #include "locate.h" #include "directory.h" #include "database.h" @@ -41,46 +42,72 @@ typedef struct _SearchStats { unsigned long playTime; } SearchStats; -static int -printDirectoryInDirectory(struct directory *directory, void *data) +static bool +print_visitor_directory(const struct directory *directory, void *data, + G_GNUC_UNUSED GError **error_r) { struct client *client = data; if (!directory_is_root(directory)) client_printf(client, "directory: %s\n", directory_get_path(directory)); - return 0; + return true; } -static int -printSongInDirectory(struct song *song, G_GNUC_UNUSED void *data) +static bool +print_visitor_song(struct song *song, void *data, + G_GNUC_UNUSED GError **error_r) { struct client *client = data; song_print_uri(client, song); - return 0; + return true; } +static bool +print_visitor_song_info(struct song *song, void *data, + G_GNUC_UNUSED GError **error_r) +{ + struct client *client = data; + song_print_info(client, song); + return true; +} + +static const struct db_visitor print_visitor = { + .directory = print_visitor_directory, + .song = print_visitor_song, +}; + +static const struct db_visitor print_info_visitor = { + .directory = print_visitor_directory, + .song = print_visitor_song_info, +}; + struct search_data { struct client *client; const struct locate_item_list *criteria; }; -static int -searchInDirectory(struct song *song, void *_data) +static bool +search_visitor_song(struct song *song, void *_data, + G_GNUC_UNUSED GError **error_r) { struct search_data *data = _data; if (locate_song_search(song, data->criteria)) song_print_info(data->client, song); - return 0; + return true; } -int +static const struct db_visitor search_visitor = { + .song = search_visitor_song, +}; + +bool searchForSongsIn(struct client *client, const char *name, - const struct locate_item_list *criteria) + const struct locate_item_list *criteria, + GError **error_r) { - int ret; struct locate_item_list *new_list = locate_item_list_casefold(criteria); struct search_data data; @@ -88,34 +115,40 @@ searchForSongsIn(struct client *client, const char *name, data.client = client; data.criteria = new_list; - ret = db_walk(name, searchInDirectory, NULL, &data); + bool success = db_walk(name, &search_visitor, &data, error_r); locate_item_list_free(new_list); - return ret; + return success; } -static int -findInDirectory(struct song *song, void *_data) +static bool +find_visitor_song(struct song *song, void *_data, + G_GNUC_UNUSED GError **error_r) { struct search_data *data = _data; if (locate_song_match(song, data->criteria)) song_print_info(data->client, song); - return 0; + return true; } -int +static const struct db_visitor find_visitor = { + .song = find_visitor_song, +}; + +bool findSongsIn(struct client *client, const char *name, - const struct locate_item_list *criteria) + const struct locate_item_list *criteria, + GError **error_r) { struct search_data data; data.client = client; data.criteria = criteria; - return db_walk(name, findInDirectory, NULL, &data); + return db_walk(name, &find_visitor, &data, error_r); } static void printSearchStats(struct client *client, SearchStats *stats) @@ -124,8 +157,9 @@ static void printSearchStats(struct client *client, SearchStats *stats) client_printf(client, "playtime: %li\n", stats->playTime); } -static int -searchStatsInDirectory(struct song *song, void *data) +static bool +stats_visitor_song(struct song *song, void *data, + G_GNUC_UNUSED GError **error_r) { SearchStats *stats = data; @@ -134,45 +168,42 @@ searchStatsInDirectory(struct song *song, void *data) stats->playTime += song_get_duration(song); } - return 0; + return true; } -int +static const struct db_visitor stats_visitor = { + .song = stats_visitor_song, +}; + +bool searchStatsForSongsIn(struct client *client, const char *name, - const struct locate_item_list *criteria) + const struct locate_item_list *criteria, + GError **error_r) { SearchStats stats; - int ret; stats.criteria = criteria; stats.numberOfSongs = 0; stats.playTime = 0; - ret = db_walk(name, searchStatsInDirectory, NULL, &stats); - if (ret == 0) - printSearchStats(client, &stats); + if (!db_walk(name, &stats_visitor, &stats, error_r)) + return false; - return ret; + printSearchStats(client, &stats); + return true; } -int printAllIn(struct client *client, const char *name) +bool +printAllIn(struct client *client, const char *uri_utf8, GError **error_r) { - return db_walk(name, printSongInDirectory, - printDirectoryInDirectory, client); + return db_walk(uri_utf8, &print_visitor, client, error_r); } -static int -directoryPrintSongInfo(struct song *song, void *data) +bool +printInfoForAllIn(struct client *client, const char *uri_utf8, + GError **error_r) { - struct client *client = data; - song_print_info(client, song); - return 0; -} - -int printInfoForAllIn(struct client *client, const char *name) -{ - return db_walk(name, directoryPrintSongInfo, - printDirectoryInDirectory, client); + return db_walk(uri_utf8, &print_info_visitor, client, error_r); } static ListCommandItem * @@ -223,8 +254,9 @@ struct list_tags_data { struct strset *set; }; -static int -listUniqueTagsInDirectory(struct song *song, void *_data) +static bool +unique_tags_visitor_song(struct song *song, void *_data, + G_GNUC_UNUSED GError **error_r) { struct list_tags_data *data = _data; ListCommandItem *item = data->item; @@ -232,13 +264,18 @@ listUniqueTagsInDirectory(struct song *song, void *_data) if (locate_song_match(song, item->criteria)) visitTag(data->client, data->set, song, item->tagType); - return 0; + return true; } -int listAllUniqueTags(struct client *client, int type, - const struct locate_item_list *criteria) +static const struct db_visitor unique_tags_visitor = { + .song = unique_tags_visitor_song, +}; + +bool +listAllUniqueTags(struct client *client, int type, + const struct locate_item_list *criteria, + GError **error_r) { - int ret; ListCommandItem *item = newListCommandItem(type, criteria); struct list_tags_data data = { .client = client, @@ -249,7 +286,10 @@ int listAllUniqueTags(struct client *client, int type, data.set = strset_new(); } - ret = db_walk(NULL, listUniqueTagsInDirectory, NULL, &data); + if (!db_walk(NULL, &unique_tags_visitor, &data, error_r)) { + freeListCommandItem(item); + return false; + } if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) { const char *value; @@ -266,5 +306,5 @@ int listAllUniqueTags(struct client *client, int type, freeListCommandItem(item); - return ret; + return true; } diff --git a/src/db_print.h b/src/db_print.h index a02e7e3d8..7d6309517 100644 --- a/src/db_print.h +++ b/src/db_print.h @@ -20,27 +20,38 @@ #ifndef MPD_DB_PRINT_H #define MPD_DB_PRINT_H +#include <glib.h> +#include <stdbool.h> + struct client; struct locate_item_list; +struct db_visitor; -int printAllIn(struct client *client, const char *name); +bool +printAllIn(struct client *client, const char *uri_utf8, GError **error_r); -int printInfoForAllIn(struct client *client, const char *name); +bool +printInfoForAllIn(struct client *client, const char *uri_utf8, + GError **error_r); -int +bool searchForSongsIn(struct client *client, const char *name, - const struct locate_item_list *criteria); + const struct locate_item_list *criteria, + GError **error_r); -int +bool findSongsIn(struct client *client, const char *name, - const struct locate_item_list *criteria); + const struct locate_item_list *criteria, + GError **error_r); -int +bool searchStatsForSongsIn(struct client *client, const char *name, - const struct locate_item_list *criteria); + const struct locate_item_list *criteria, + GError **error_r); -int +bool listAllUniqueTags(struct client *client, int type, - const struct locate_item_list *criteria); + const struct locate_item_list *criteria, + GError **error_r); #endif diff --git a/src/db_visitor.h b/src/db_visitor.h new file mode 100644 index 000000000..3eb215c86 --- /dev/null +++ b/src/db_visitor.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_DB_VISITOR_H +#define MPD_DB_VISITOR_H + +struct directory; +struct song; + +struct db_visitor { + /** + * Visit a directory. Optional method. + * + * @return true to continue the operation, false on error (set error_r) + */ + bool (*directory)(const struct directory *directory, void *ctx, + GError **error_r); + + /** + * Visit a song. Optional method. + * + * @return true to continue the operation, false on error (set error_r) + */ + bool (*song)(struct song *song, void *ctx, GError **error_r); +}; + +#endif diff --git a/src/directory.c b/src/directory.c index d8b241118..eb076d94d 100644 --- a/src/directory.c +++ b/src/directory.c @@ -21,6 +21,7 @@ #include "directory.h" #include "song.h" #include "path.h" +#include "db_visitor.h" #include <glib.h> @@ -167,28 +168,33 @@ directory_sort(struct directory *directory) directory_sort(dv->base[i]); } -int +bool directory_walk(struct directory *directory, - int (*forEachSong)(struct song *, void *), - int (*forEachDir)(struct directory *, void *), - void *data) + const struct db_visitor *visitor, void *ctx, + GError **error_r) { - struct dirvec *dv = &directory->children; - int err = 0; - size_t j; - - if (forEachDir && (err = forEachDir(directory, data)) < 0) - return err; - - if (forEachSong) { - err = songvec_for_each(&directory->songs, forEachSong, data); - if (err < 0) - return err; + assert(directory != NULL); + assert(visitor != NULL); + assert(error_r == NULL || *error_r == NULL); + + if (visitor->directory != NULL && + !visitor->directory(directory, ctx, error_r)) + return false; + + if (visitor->song != NULL) { + struct songvec *sv = &directory->songs; + for (size_t i = 0; i < sv->nr; ++i) + if (!visitor->song(sv->base[i], ctx, error_r)) + return false; } - for (j = 0; err >= 0 && j < dv->nr; ++j) - err = directory_walk(dv->base[j], forEachSong, - forEachDir, data); + if (visitor->directory != NULL) { + const struct dirvec *dv = &directory->children; + for (size_t i = 0; i < dv->nr; ++i) + if (!directory_walk(dv->base[i], visitor, ctx, + error_r)) + return false; + } - return err; + return true; } diff --git a/src/directory.h b/src/directory.h index a3ad0ffa3..3359a2e99 100644 --- a/src/directory.h +++ b/src/directory.h @@ -25,6 +25,7 @@ #include "songvec.h" #include "playlist_vector.h" +#include <glib.h> #include <stdbool.h> #include <sys/types.h> @@ -33,6 +34,8 @@ #define DEVICE_INARCHIVE (dev_t)(-1) #define DEVICE_CONTAINER (dev_t)(-2) +struct db_visitor; + struct directory { struct dirvec children; struct songvec songs; @@ -127,10 +130,9 @@ directory_lookup_song(struct directory *directory, const char *uri); void directory_sort(struct directory *directory); -int +bool directory_walk(struct directory *directory, - int (*forEachSong)(struct song *, void *), - int (*forEachDir)(struct directory *, void *), - void *data); + const struct db_visitor *visitor, void *ctx, + GError **error_r); #endif diff --git a/src/stats.c b/src/stats.c index 8f9ef0dbf..fe0c2a476 100644 --- a/src/stats.c +++ b/src/stats.c @@ -20,6 +20,7 @@ #include "config.h" #include "stats.h" #include "database.h" +#include "db_visitor.h" #include "tag.h" #include "song.h" #include "client.h" @@ -68,8 +69,9 @@ visit_tag(struct visit_data *data, const struct tag *tag) } } -static int -stats_collect_song(struct song *song, void *_data) +static bool +collect_stats_song(struct song *song, void *_data, + G_GNUC_UNUSED GError **error_r) { struct visit_data *data = _data; @@ -78,9 +80,13 @@ stats_collect_song(struct song *song, void *_data) if (song->tag != NULL) visit_tag(data, song->tag); - return 0; + return true; } +static const struct db_visitor collect_stats_visitor = { + .song = collect_stats_song, +}; + void stats_update(void) { struct visit_data data; @@ -92,7 +98,7 @@ void stats_update(void) data.artists = strset_new(); data.albums = strset_new(); - db_walk(NULL, stats_collect_song, NULL, &data); + db_walk(NULL, &collect_stats_visitor, &data, NULL); stats.artist_count = strset_size(data.artists); stats.album_count = strset_size(data.albums); |