diff options
author | Max Kellermann <max@duempel.org> | 2012-08-29 19:27:03 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2012-08-29 20:19:02 +0200 |
commit | 333d226ed0044cf6a6387e03805be2d7f6dac6f2 (patch) | |
tree | 7acb6fc795fcd2bb8aa75c16172de1ff7a761e8f /src | |
parent | 04a9dec9525a58d077da71a84655cb45b7838520 (diff) | |
download | mpd-333d226ed0044cf6a6387e03805be2d7f6dac6f2.tar.gz mpd-333d226ed0044cf6a6387e03805be2d7f6dac6f2.tar.xz mpd-333d226ed0044cf6a6387e03805be2d7f6dac6f2.zip |
SongFilter: convert to a C++ class
Diffstat (limited to 'src')
-rw-r--r-- | src/DatabaseCommands.cxx | 72 | ||||
-rw-r--r-- | src/DatabasePlaylist.cxx | 4 | ||||
-rw-r--r-- | src/DatabasePlaylist.hxx | 4 | ||||
-rw-r--r-- | src/DatabasePrint.cxx | 12 | ||||
-rw-r--r-- | src/DatabasePrint.hxx | 6 | ||||
-rw-r--r-- | src/DatabaseQueue.cxx | 4 | ||||
-rw-r--r-- | src/DatabaseQueue.hxx | 4 | ||||
-rw-r--r-- | src/DatabaseSelection.cxx | 2 | ||||
-rw-r--r-- | src/DatabaseSelection.hxx | 8 | ||||
-rw-r--r-- | src/Directory.cxx | 7 | ||||
-rw-r--r-- | src/PlaylistPrint.cxx | 6 | ||||
-rw-r--r-- | src/PlaylistPrint.hxx | 4 | ||||
-rw-r--r-- | src/QueueCommands.cxx | 11 | ||||
-rw-r--r-- | src/QueuePrint.cxx | 6 | ||||
-rw-r--r-- | src/QueuePrint.hxx (renamed from src/queue_print.h) | 10 | ||||
-rw-r--r-- | src/SongFilter.cxx | 191 | ||||
-rw-r--r-- | src/SongFilter.hxx | 88 | ||||
-rw-r--r-- | src/db/SimpleDatabasePlugin.cxx | 2 | ||||
-rw-r--r-- | src/directory.h | 7 |
19 files changed, 209 insertions, 239 deletions
diff --git a/src/DatabaseCommands.cxx b/src/DatabaseCommands.cxx index 047d3a550..14e83e96a 100644 --- a/src/DatabaseCommands.cxx +++ b/src/DatabaseCommands.cxx @@ -59,25 +59,18 @@ handle_lsinfo2(struct client *client, int argc, char *argv[]) static enum command_return handle_match(struct client *client, int argc, char *argv[], bool fold_case) { - struct locate_item_list *list = - locate_item_list_parse(argv + 1, argc - 1, fold_case); - - if (list == NULL) { + SongFilter filter; + if (!filter.Parse(argc - 1, argv + 1, fold_case)) { command_error(client, ACK_ERROR_ARG, "incorrect arguments"); return COMMAND_RETURN_ERROR; } - const DatabaseSelection selection("", true, list); + const DatabaseSelection selection("", true, &filter); GError *error = NULL; - enum command_return ret = - db_selection_print(client, selection, true, &error) + return db_selection_print(client, selection, true, &error) ? COMMAND_RETURN_OK : print_error(client, error); - - locate_item_list_free(list); - - return ret; } enum command_return @@ -95,22 +88,16 @@ handle_search(struct client *client, int argc, char *argv[]) static enum command_return handle_match_add(struct client *client, int argc, char *argv[], bool fold_case) { - struct locate_item_list *list = - locate_item_list_parse(argv + 1, argc - 1, fold_case); - if (list == NULL) { + SongFilter filter; + if (!filter.Parse(argc - 1, argv + 1, fold_case)) { command_error(client, ACK_ERROR_ARG, "incorrect arguments"); return COMMAND_RETURN_ERROR; } GError *error = NULL; - enum command_return ret = - findAddIn(client->player_control, "", list, &error) + return findAddIn(client->player_control, "", &filter, &error) ? COMMAND_RETURN_OK : print_error(client, error); - - locate_item_list_free(list); - - return ret; } enum command_return @@ -130,45 +117,31 @@ handle_searchaddpl(struct client *client, int argc, char *argv[]) { const char *playlist = argv[1]; - struct locate_item_list *list = - locate_item_list_parse(argv + 2, argc - 2, true); - - if (list == NULL) { + SongFilter filter; + if (!filter.Parse(argc - 2, argv + 2, true)) { command_error(client, ACK_ERROR_ARG, "incorrect arguments"); return COMMAND_RETURN_ERROR; } GError *error = NULL; - enum command_return ret = - search_add_to_playlist("", playlist, list, &error) + return search_add_to_playlist("", playlist, &filter, &error) ? COMMAND_RETURN_OK : print_error(client, error); - - locate_item_list_free(list); - - return ret; } enum command_return handle_count(struct client *client, int argc, char *argv[]) { - struct locate_item_list *list = - locate_item_list_parse(argv + 1, argc - 1, false); - - if (list == NULL) { + SongFilter filter; + if (!filter.Parse(argc - 1, argv + 1, false)) { command_error(client, ACK_ERROR_ARG, "incorrect arguments"); return COMMAND_RETURN_ERROR; } GError *error = NULL; - enum command_return ret = - searchStatsForSongsIn(client, "", list, &error) + return searchStatsForSongsIn(client, "", &filter, &error) ? COMMAND_RETURN_OK : print_error(client, error); - - locate_item_list_free(list); - - return ret; } enum command_return @@ -188,7 +161,6 @@ handle_listall(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) enum command_return handle_list(struct client *client, int argc, char *argv[]) { - struct locate_item_list *conditionals; unsigned tagType = locate_parse_type(argv[1]); if (tagType == TAG_NUM_OF_ITEM_TYPES) { @@ -203,6 +175,7 @@ handle_list(struct client *client, int argc, char *argv[]) } /* for compatibility with < 0.12.0 */ + SongFilter *filter; if (argc == 3) { if (tagType != TAG_ALBUM) { command_error(client, ACK_ERROR_ARG, @@ -211,28 +184,25 @@ handle_list(struct client *client, int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - conditionals = - locate_item_list_new_single((unsigned)TAG_ARTIST, - argv[2]); + filter = new SongFilter((unsigned)TAG_ARTIST, argv[2]); } else if (argc > 2) { - conditionals = - locate_item_list_parse(argv + 2, argc - 2, false); - if (conditionals == NULL) { + filter = new SongFilter(); + if (!filter->Parse(argc - 2, argv + 2, false)) { + delete filter; command_error(client, ACK_ERROR_ARG, "not able to parse args"); return COMMAND_RETURN_ERROR; } } else - conditionals = nullptr; + filter = nullptr; GError *error = NULL; enum command_return ret = - listAllUniqueTags(client, tagType, conditionals, &error) + listAllUniqueTags(client, tagType, filter, &error) ? COMMAND_RETURN_OK : print_error(client, error); - if (conditionals != nullptr) - locate_item_list_free(conditionals); + delete filter; return ret; } diff --git a/src/DatabasePlaylist.cxx b/src/DatabasePlaylist.cxx index 1faf79dad..f9934bab2 100644 --- a/src/DatabasePlaylist.cxx +++ b/src/DatabasePlaylist.cxx @@ -39,14 +39,14 @@ AddSong(const char *playlist_path_utf8, bool search_add_to_playlist(const char *uri, const char *playlist_path_utf8, - const struct locate_item_list *criteria, + const SongFilter *filter, GError **error_r) { const Database *db = GetDatabase(error_r); if (db == nullptr) return false; - const DatabaseSelection selection(uri, true, criteria); + const DatabaseSelection selection(uri, true, filter); using namespace std::placeholders; const auto f = std::bind(AddSong, playlist_path_utf8, _1, _2); diff --git a/src/DatabasePlaylist.hxx b/src/DatabasePlaylist.hxx index 269585c32..7c6952ffa 100644 --- a/src/DatabasePlaylist.hxx +++ b/src/DatabasePlaylist.hxx @@ -23,12 +23,12 @@ #include "gcc.h" #include "gerror.h" -struct locate_item_list; +class SongFilter; gcc_nonnull(1,2) bool search_add_to_playlist(const char *uri, const char *path_utf8, - const struct locate_item_list *criteria, + const SongFilter *filter, GError **error_r); #endif diff --git a/src/DatabasePrint.cxx b/src/DatabasePrint.cxx index 9ff833ffd..97ff9c12c 100644 --- a/src/DatabasePrint.cxx +++ b/src/DatabasePrint.cxx @@ -120,12 +120,12 @@ db_selection_print(struct client *client, const DatabaseSelection &selection, return false; using namespace std::placeholders; - const auto d = selection.match == nullptr + const auto d = selection.filter == nullptr ? std::bind(PrintDirectory, client, _1) : VisitDirectory(); const auto s = std::bind(full ? PrintSongFull : PrintSongBrief, client, _1); - const auto p = selection.match == nullptr + const auto p = selection.filter == nullptr ? std::bind(full ? PrintPlaylistFull : PrintPlaylistBrief, client, _1, _2) : VisitPlaylist(); @@ -155,14 +155,14 @@ stats_visitor_song(SearchStats &stats, song &song) bool searchStatsForSongsIn(struct client *client, const char *name, - const struct locate_item_list *criteria, + const SongFilter *filter, GError **error_r) { const Database *db = GetDatabase(error_r); if (db == nullptr) return false; - const DatabaseSelection selection(name, true, criteria); + const DatabaseSelection selection(name, true, filter); SearchStats stats; stats.numberOfSongs = 0; @@ -211,14 +211,14 @@ PrintUniqueTag(struct client *client, enum tag_type tag_type, bool listAllUniqueTags(struct client *client, int type, - const struct locate_item_list *criteria, + const SongFilter *filter, GError **error_r) { const Database *db = GetDatabase(error_r); if (db == nullptr) return false; - const DatabaseSelection selection("", true, criteria); + const DatabaseSelection selection("", true, filter); if (type == LOCATE_TAG_FILE_TYPE) { using namespace std::placeholders; diff --git a/src/DatabasePrint.hxx b/src/DatabasePrint.hxx index e9a19cd52..4aacd9363 100644 --- a/src/DatabasePrint.hxx +++ b/src/DatabasePrint.hxx @@ -26,7 +26,7 @@ #include <stdbool.h> struct client; -struct locate_item_list; +class SongFilter; struct DatabaseSelection; struct db_visitor; @@ -47,13 +47,13 @@ printInfoForAllIn(struct client *client, const char *uri_utf8, gcc_nonnull(1,2) bool searchStatsForSongsIn(struct client *client, const char *name, - const struct locate_item_list *criteria, + const SongFilter *filter, GError **error_r); gcc_nonnull(1) bool listAllUniqueTags(struct client *client, int type, - const struct locate_item_list *criteria, + const SongFilter *filter, GError **error_r); #endif diff --git a/src/DatabaseQueue.cxx b/src/DatabaseQueue.cxx index 527539401..325748d02 100644 --- a/src/DatabaseQueue.cxx +++ b/src/DatabaseQueue.cxx @@ -46,13 +46,13 @@ AddToQueue(struct player_control *pc, song &song, GError **error_r) bool findAddIn(struct player_control *pc, const char *uri, - const struct locate_item_list *criteria, GError **error_r) + const SongFilter *filter, GError **error_r) { const Database *db = GetDatabase(error_r); if (db == nullptr) return false; - const DatabaseSelection selection(uri, true, criteria); + const DatabaseSelection selection(uri, true, filter); using namespace std::placeholders; const auto f = std::bind(AddToQueue, pc, _1, _2); diff --git a/src/DatabaseQueue.hxx b/src/DatabaseQueue.hxx index cf8c3ba5d..21ffe0fb0 100644 --- a/src/DatabaseQueue.hxx +++ b/src/DatabaseQueue.hxx @@ -23,12 +23,12 @@ #include "gcc.h" #include "gerror.h" -struct locate_item_list; +class SongFilter; struct player_control; gcc_nonnull(1,2) bool findAddIn(struct player_control *pc, const char *name, - const struct locate_item_list *criteria, GError **error_r); + const SongFilter *filter, GError **error_r); #endif diff --git a/src/DatabaseSelection.cxx b/src/DatabaseSelection.cxx index 72c3f9196..bd756f5f9 100644 --- a/src/DatabaseSelection.cxx +++ b/src/DatabaseSelection.cxx @@ -23,5 +23,5 @@ bool DatabaseSelection::Match(const song &song) const { - return match == nullptr || locate_list_song_match(&song, match); + return filter == nullptr || filter->Match(song); } diff --git a/src/DatabaseSelection.hxx b/src/DatabaseSelection.hxx index c5ee5cf0d..3a81c01ec 100644 --- a/src/DatabaseSelection.hxx +++ b/src/DatabaseSelection.hxx @@ -25,7 +25,7 @@ #include <assert.h> #include <stddef.h> -struct locate_item_list; +class SongFilter; struct song; struct DatabaseSelection { @@ -41,11 +41,11 @@ struct DatabaseSelection { */ bool recursive; - const locate_item_list *match; + const SongFilter *filter; DatabaseSelection(const char *_uri, bool _recursive, - const locate_item_list *_match=nullptr) - :uri(_uri), recursive(_recursive), match(_match) { + const SongFilter *_filter=nullptr) + :uri(_uri), recursive(_recursive), filter(_filter) { assert(uri != NULL); } diff --git a/src/Directory.cxx b/src/Directory.cxx index d4564d69e..eeba903d1 100644 --- a/src/Directory.cxx +++ b/src/Directory.cxx @@ -291,7 +291,7 @@ directory_sort(struct directory *directory) } bool -directory::Walk(bool recursive, const locate_item_list *match, +directory::Walk(bool recursive, const SongFilter *filter, VisitDirectory visit_directory, VisitSong visit_song, VisitPlaylist visit_playlist, GError **error_r) const @@ -301,8 +301,7 @@ directory::Walk(bool recursive, const locate_item_list *match, if (visit_song) { struct song *song; directory_for_each_song(song, this) - if ((match == NULL || - locate_list_song_match(song, match)) && + if ((filter == nullptr || filter->Match(*song)) && !visit_song(*song, error_r)) return false; } @@ -321,7 +320,7 @@ directory::Walk(bool recursive, const locate_item_list *match, return false; if (recursive && - !child->Walk(recursive, match, + !child->Walk(recursive, filter, visit_directory, visit_song, visit_playlist, error_r)) return false; diff --git a/src/PlaylistPrint.cxx b/src/PlaylistPrint.cxx index 9ff7f270e..345506d5e 100644 --- a/src/PlaylistPrint.cxx +++ b/src/PlaylistPrint.cxx @@ -19,6 +19,7 @@ #include "config.h" #include "PlaylistPrint.hxx" +#include "QueuePrint.hxx" extern "C" { #include "playlist_list.h" @@ -26,7 +27,6 @@ extern "C" { #include "playlist_any.h" #include "playlist_song.h" #include "playlist.h" -#include "queue_print.h" #include "stored_playlist.h" #include "song_print.h" #include "song.h" @@ -91,9 +91,9 @@ playlist_print_current(struct client *client, const struct playlist *playlist) void playlist_print_find(struct client *client, const struct playlist *playlist, - const struct locate_item_list *list) + const SongFilter &filter) { - queue_find(client, &playlist->queue, list); + queue_find(client, &playlist->queue, filter); } void diff --git a/src/PlaylistPrint.hxx b/src/PlaylistPrint.hxx index c6be5a93f..ac0712f01 100644 --- a/src/PlaylistPrint.hxx +++ b/src/PlaylistPrint.hxx @@ -26,7 +26,7 @@ struct client; struct playlist; -struct locate_item_list; +class SongFilter; /** * Sends the whole playlist to the client, song URIs only. @@ -66,7 +66,7 @@ playlist_print_current(struct client *client, const struct playlist *playlist); */ void playlist_print_find(struct client *client, const struct playlist *playlist, - const struct locate_item_list *list); + const SongFilter &filter); /** * Print detailed changes since the specified playlist version. diff --git a/src/QueueCommands.cxx b/src/QueueCommands.cxx index c47454e08..5dac6a8a0 100644 --- a/src/QueueCommands.cxx +++ b/src/QueueCommands.cxx @@ -246,18 +246,13 @@ static enum command_return handle_playlist_match(struct client *client, int argc, char *argv[], bool fold_case) { - struct locate_item_list *list = - locate_item_list_parse(argv + 1, argc - 1, fold_case); - - if (list == NULL) { + SongFilter filter; + if (!filter.Parse(argc - 1, argv + 1, fold_case)) { command_error(client, ACK_ERROR_ARG, "incorrect arguments"); return COMMAND_RETURN_ERROR; } - playlist_print_find(client, &g_playlist, list); - - locate_item_list_free(list); - + playlist_print_find(client, &g_playlist, filter); return COMMAND_RETURN_OK; } diff --git a/src/QueuePrint.cxx b/src/QueuePrint.cxx index 0a61cc5dd..edac7c7ad 100644 --- a/src/QueuePrint.cxx +++ b/src/QueuePrint.cxx @@ -18,10 +18,10 @@ */ #include "config.h" +#include "QueuePrint.hxx" #include "SongFilter.hxx" extern "C" { -#include "queue_print.h" #include "queue.h" #include "song.h" #include "song_print.h" @@ -96,12 +96,12 @@ queue_print_changes_position(struct client *client, const struct queue *queue, void queue_find(struct client *client, const struct queue *queue, - const struct locate_item_list *criteria) + const SongFilter &filter) { for (unsigned i = 0; i < queue_length(queue); i++) { const struct song *song = queue_get(queue, i); - if (locate_list_song_match(song, criteria)) + if (filter.Match(*song)) queue_print_song_info(client, queue, i); } } diff --git a/src/queue_print.h b/src/QueuePrint.hxx index 28620c41f..808b8dec1 100644 --- a/src/queue_print.h +++ b/src/QueuePrint.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * Copyright (C) 2003-2012 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -22,14 +22,14 @@ * client. */ -#ifndef QUEUE_PRINT_H -#define QUEUE_PRINT_H +#ifndef MPD_QUEUE_PRINT_HXX +#define MPD_QUEUE_PRINT_HXX #include <stdint.h> struct client; struct queue; -struct locate_item_list; +class SongFilter; void queue_print_info(struct client *client, const struct queue *queue, @@ -49,6 +49,6 @@ queue_print_changes_position(struct client *client, const struct queue *queue, void queue_find(struct client *client, const struct queue *queue, - const struct locate_item_list *criteria); + const SongFilter &filter); #endif diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx index c99776e18..6803b453e 100644 --- a/src/SongFilter.cxx +++ b/src/SongFilter.cxx @@ -35,27 +35,6 @@ extern "C" { #define LOCATE_TAG_FILE_KEY_OLD "filename" #define LOCATE_TAG_ANY_KEY "any" -/* struct used for search, find, list queries */ -struct locate_item { - uint8_t tag; - - bool fold_case; - - /* what we are looking for */ - char *needle; -}; - -/** - * An array of struct locate_item objects. - */ -struct locate_item_list { - /** number of items */ - unsigned length; - - /** this is a variable length array */ - struct locate_item items[1]; -}; - unsigned locate_parse_type(const char *str) { @@ -69,107 +48,52 @@ locate_parse_type(const char *str) return tag_name_parse_i(str); } -static bool -locate_item_init(struct locate_item *item, - const char *type_string, const char *needle, - bool fold_case) -{ - item->tag = locate_parse_type(type_string); - - if (item->tag == TAG_NUM_OF_ITEM_TYPES) - return false; - - item->fold_case = fold_case; - item->needle = fold_case - ? g_utf8_casefold(needle, -1) - : g_strdup(needle); - - return true; -} - -void -locate_item_list_free(struct locate_item_list *list) +SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case) + :tag(_tag), fold_case(_fold_case), + value(fold_case + ? g_utf8_casefold(_value, -1) + : g_strdup(_value)) { - for (unsigned i = 0; i < list->length; ++i) - g_free(list->items[i].needle); - - g_free(list); -} - -static struct locate_item_list * -locate_item_list_new(unsigned length) -{ - struct locate_item_list *list = (struct locate_item_list *) - g_malloc(sizeof(*list) - sizeof(list->items[0]) + - length * sizeof(list->items[0])); - list->length = length; - - return list; -} - -struct locate_item_list * -locate_item_list_new_single(unsigned tag, const char *needle) -{ - struct locate_item_list *list = locate_item_list_new(1); - list->items[0].tag = tag; - list->items[0].fold_case = false; - list->items[0].needle = g_strdup(needle); - return list; } -struct locate_item_list * -locate_item_list_parse(char *argv[], unsigned argc, bool fold_case) +SongFilter::Item::~Item() { - if (argc == 0 || argc % 2 != 0) - return NULL; - - struct locate_item_list *list = locate_item_list_new(argc / 2); - - for (unsigned i = 0; i < list->length; ++i) { - if (!locate_item_init(&list->items[i], argv[i * 2], - argv[i * 2 + 1], fold_case)) { - locate_item_list_free(list); - return NULL; - } - } - - return list; + g_free(value); } -gcc_pure -static bool -locate_string_match(const struct locate_item *item, const char *value) +bool +SongFilter::Item::StringMatch(const char *s) const { - assert(item != NULL); - assert(value != NULL); + assert(value != nullptr); + assert(s != nullptr); - if (item->fold_case) { - char *p = g_utf8_casefold(value, -1); - const bool result = strstr(p, item->needle) != NULL; + if (fold_case) { + char *p = g_utf8_casefold(s, -1); + const bool result = strstr(p, value) != NULL; g_free(p); return result; } else { - return strcmp(value, item->needle) == 0; + return strcmp(s, value) == 0; } } -gcc_pure -static bool -locate_tag_match(const struct locate_item *item, const struct tag *tag) +bool +SongFilter::Item::Match(const tag_item &item) const { - assert(item != NULL); - assert(tag != NULL); + return (tag == LOCATE_TAG_ANY_TYPE || (unsigned)item.type == tag) && + StringMatch(item.value); +} +bool +SongFilter::Item::Match(const struct tag &_tag) const +{ bool visited_types[TAG_NUM_OF_ITEM_TYPES]; - memset(visited_types, 0, sizeof(visited_types)); + std::fill(visited_types, visited_types + TAG_NUM_OF_ITEM_TYPES, false); - for (unsigned i = 0; i < tag->num_items; i++) { - visited_types[tag->items[i]->type] = true; - if (item->tag != LOCATE_TAG_ANY_TYPE && - tag->items[i]->type != item->tag) - continue; + for (unsigned i = 0; i < _tag.num_items; i++) { + visited_types[_tag.items[i]->type] = true; - if (locate_string_match(item, tag->items[i]->value)) + if (Match(*_tag.items[i])) return true; } @@ -179,36 +103,67 @@ locate_tag_match(const struct locate_item *item, const struct tag *tag) * empty (first char is a \0), then it's a match as well and * we should return true. */ - if (*item->needle == 0 && item->tag != LOCATE_TAG_ANY_TYPE && - !visited_types[item->tag]) + if (*value == 0 && tag < TAG_NUM_OF_ITEM_TYPES && + !visited_types[tag]) return true; return false; } -gcc_pure -static bool -locate_song_match(const struct locate_item *item, const struct song *song) +bool +SongFilter::Item::Match(const song &song) const { - if (item->tag == LOCATE_TAG_FILE_TYPE || - item->tag == LOCATE_TAG_ANY_TYPE) { - char *uri = song_get_uri(song); - const bool result = locate_string_match(item, uri); + if (tag == LOCATE_TAG_FILE_TYPE || tag == LOCATE_TAG_ANY_TYPE) { + char *uri = song_get_uri(&song); + const bool result = StringMatch(uri); g_free(uri); - if (result || item->tag == LOCATE_TAG_FILE_TYPE) + if (result || tag == LOCATE_TAG_FILE_TYPE) return result; } - return song->tag != NULL && locate_tag_match(item, song->tag); + return song.tag != NULL && Match(*song.tag); +} + +SongFilter::SongFilter(unsigned tag, const char *value, bool fold_case) +{ + items.push_back(Item(tag, value, fold_case)); +} + +SongFilter::~SongFilter() +{ + /* this destructor exists here just so it won't get inlined */ +} + +bool +SongFilter::Parse(const char *tag_string, const char *value, bool fold_case) +{ + unsigned tag = locate_parse_type(tag_string); + if (tag == TAG_NUM_OF_ITEM_TYPES) + return false; + + items.push_back(Item(tag, value, fold_case)); + return true; +} + +bool +SongFilter::Parse(unsigned argc, char *argv[], bool fold_case) +{ + if (argc == 0 || argc % 2 != 0) + return false; + + for (unsigned i = 0; i < argc; i += 2) + if (!Parse(argv[i], argv[i + 1], fold_case)) + return false; + + return true; } bool -locate_list_song_match(const struct song *song, - const struct locate_item_list *criteria) +SongFilter::Match(const song &song) const { - for (unsigned i = 0; i < criteria->length; i++) - if (!locate_song_match(&criteria->items[i], song)) + for (const auto &i : items) + if (!i.Match(song)) return false; return true; diff --git a/src/SongFilter.hxx b/src/SongFilter.hxx index 38c1dae67..a3068a970 100644 --- a/src/SongFilter.hxx +++ b/src/SongFilter.hxx @@ -22,15 +22,82 @@ #include "gcc.h" +#include <list> + #include <stdint.h> #include <stdbool.h> #define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10 #define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20 -struct locate_item_list; +struct tag; +struct tag_item; struct song; +class SongFilter { + class Item { + uint8_t tag; + + bool fold_case; + + char *value; + + public: + gcc_nonnull(3) + Item(unsigned tag, const char *value, bool fold_case=false); + + Item(const Item &other) = delete; + + Item(Item &&other) + :tag(other.tag), fold_case(other.fold_case), + value(other.value) { + other.value = nullptr; + } + + ~Item(); + + Item &operator=(const Item &other) = delete; + + unsigned GetTag() const { + return tag; + } + + gcc_pure gcc_nonnull(2) + bool StringMatch(const char *s) const; + + gcc_pure + bool Match(const tag_item &tag_item) const; + + gcc_pure + bool Match(const struct tag &tag) const; + + gcc_pure + bool Match(const song &song) const; + }; + + std::list<Item> items; + +public: + SongFilter() = default; + + gcc_nonnull(3) + SongFilter(unsigned tag, const char *value, bool fold_case=false); + + ~SongFilter(); + + gcc_nonnull(2,3) + bool Parse(const char *tag, const char *value, bool fold_case=false); + + gcc_nonnull(3) + bool Parse(unsigned argc, char *argv[], bool fold_case=false); + + gcc_pure + bool Match(const tag &tag) const; + + gcc_pure + bool Match(const song &song) const; +}; + /** * @return #TAG_NUM_OF_ITEM_TYPES on error */ @@ -38,23 +105,4 @@ gcc_pure unsigned locate_parse_type(const char *str); -gcc_malloc -struct locate_item_list * -locate_item_list_new_single(unsigned tag, const char *needle); - -/* return number of items or -1 on error */ -gcc_nonnull(1) -struct locate_item_list * -locate_item_list_parse(char *argv[], unsigned argc, bool fold_case); - -gcc_nonnull(1) -void -locate_item_list_free(struct locate_item_list *list); - -gcc_pure -gcc_nonnull(1,2) -bool -locate_list_song_match(const struct song *song, - const struct locate_item_list *criteria); - #endif diff --git a/src/db/SimpleDatabasePlugin.cxx b/src/db/SimpleDatabasePlugin.cxx index 1a16c336f..54441f4cd 100644 --- a/src/db/SimpleDatabasePlugin.cxx +++ b/src/db/SimpleDatabasePlugin.cxx @@ -282,7 +282,7 @@ SimpleDatabase::Visit(const DatabaseSelection &selection, return false; db_lock(); - bool ret = directory->Walk(selection.recursive, selection.match, + bool ret = directory->Walk(selection.recursive, selection.filter, visit_directory, visit_song, visit_playlist, error_r); db_unlock(); diff --git a/src/directory.h b/src/directory.h index d569fee9e..607e812cd 100644 --- a/src/directory.h +++ b/src/directory.h @@ -55,7 +55,10 @@ struct song; struct db_visitor; -struct locate_item_list; + +#ifdef __cplusplus +class SongFilter; +#endif struct directory { /** @@ -97,7 +100,7 @@ struct directory { /** * Caller must lock #db_mutex. */ - bool Walk(bool recursive, const locate_item_list *match, + bool Walk(bool recursive, const SongFilter *match, VisitDirectory visit_directory, VisitSong visit_song, VisitPlaylist visit_playlist, GError **error_r) const; |