Commit 333d226e authored by Max Kellermann's avatar Max Kellermann

SongFilter: convert to a C++ class

parent 04a9dec9
...@@ -177,7 +177,6 @@ mpd_headers = \ ...@@ -177,7 +177,6 @@ mpd_headers = \
src/riff.h \ src/riff.h \
src/aiff.h \ src/aiff.h \
src/queue.h \ src/queue.h \
src/queue_print.h \
src/queue_save.h \ src/queue_save.h \
src/refcount.h \ src/refcount.h \
src/replay_gain_config.h \ src/replay_gain_config.h \
...@@ -333,7 +332,7 @@ src_mpd_SOURCES = \ ...@@ -333,7 +332,7 @@ src_mpd_SOURCES = \
src/playlist_vector.c \ src/playlist_vector.c \
src/playlist_database.c \ src/playlist_database.c \
src/queue.c \ src/queue.c \
src/QueuePrint.cxx \ src/QueuePrint.cxx src/QueuePrint.hxx \
src/queue_save.c \ src/queue_save.c \
src/replay_gain_config.c \ src/replay_gain_config.c \
src/replay_gain_info.c \ src/replay_gain_info.c \
......
...@@ -59,25 +59,18 @@ handle_lsinfo2(struct client *client, int argc, char *argv[]) ...@@ -59,25 +59,18 @@ handle_lsinfo2(struct client *client, int argc, char *argv[])
static enum command_return static enum command_return
handle_match(struct client *client, int argc, char *argv[], bool fold_case) handle_match(struct client *client, int argc, char *argv[], bool fold_case)
{ {
struct locate_item_list *list = SongFilter filter;
locate_item_list_parse(argv + 1, argc - 1, fold_case); if (!filter.Parse(argc - 1, argv + 1, fold_case)) {
if (list == NULL) {
command_error(client, ACK_ERROR_ARG, "incorrect arguments"); command_error(client, ACK_ERROR_ARG, "incorrect arguments");
return COMMAND_RETURN_ERROR; return COMMAND_RETURN_ERROR;
} }
const DatabaseSelection selection("", true, list); const DatabaseSelection selection("", true, &filter);
GError *error = NULL; GError *error = NULL;
enum command_return ret = return db_selection_print(client, selection, true, &error)
db_selection_print(client, selection, true, &error)
? COMMAND_RETURN_OK ? COMMAND_RETURN_OK
: print_error(client, error); : print_error(client, error);
locate_item_list_free(list);
return ret;
} }
enum command_return enum command_return
...@@ -95,22 +88,16 @@ handle_search(struct client *client, int argc, char *argv[]) ...@@ -95,22 +88,16 @@ handle_search(struct client *client, int argc, char *argv[])
static enum command_return static enum command_return
handle_match_add(struct client *client, int argc, char *argv[], bool fold_case) handle_match_add(struct client *client, int argc, char *argv[], bool fold_case)
{ {
struct locate_item_list *list = SongFilter filter;
locate_item_list_parse(argv + 1, argc - 1, fold_case); if (!filter.Parse(argc - 1, argv + 1, fold_case)) {
if (list == NULL) {
command_error(client, ACK_ERROR_ARG, "incorrect arguments"); command_error(client, ACK_ERROR_ARG, "incorrect arguments");
return COMMAND_RETURN_ERROR; return COMMAND_RETURN_ERROR;
} }
GError *error = NULL; GError *error = NULL;
enum command_return ret = return findAddIn(client->player_control, "", &filter, &error)
findAddIn(client->player_control, "", list, &error)
? COMMAND_RETURN_OK ? COMMAND_RETURN_OK
: print_error(client, error); : print_error(client, error);
locate_item_list_free(list);
return ret;
} }
enum command_return enum command_return
...@@ -130,45 +117,31 @@ handle_searchaddpl(struct client *client, int argc, char *argv[]) ...@@ -130,45 +117,31 @@ handle_searchaddpl(struct client *client, int argc, char *argv[])
{ {
const char *playlist = argv[1]; const char *playlist = argv[1];
struct locate_item_list *list = SongFilter filter;
locate_item_list_parse(argv + 2, argc - 2, true); if (!filter.Parse(argc - 2, argv + 2, true)) {
if (list == NULL) {
command_error(client, ACK_ERROR_ARG, "incorrect arguments"); command_error(client, ACK_ERROR_ARG, "incorrect arguments");
return COMMAND_RETURN_ERROR; return COMMAND_RETURN_ERROR;
} }
GError *error = NULL; GError *error = NULL;
enum command_return ret = return search_add_to_playlist("", playlist, &filter, &error)
search_add_to_playlist("", playlist, list, &error)
? COMMAND_RETURN_OK ? COMMAND_RETURN_OK
: print_error(client, error); : print_error(client, error);
locate_item_list_free(list);
return ret;
} }
enum command_return enum command_return
handle_count(struct client *client, int argc, char *argv[]) handle_count(struct client *client, int argc, char *argv[])
{ {
struct locate_item_list *list = SongFilter filter;
locate_item_list_parse(argv + 1, argc - 1, false); if (!filter.Parse(argc - 1, argv + 1, false)) {
if (list == NULL) {
command_error(client, ACK_ERROR_ARG, "incorrect arguments"); command_error(client, ACK_ERROR_ARG, "incorrect arguments");
return COMMAND_RETURN_ERROR; return COMMAND_RETURN_ERROR;
} }
GError *error = NULL; GError *error = NULL;
enum command_return ret = return searchStatsForSongsIn(client, "", &filter, &error)
searchStatsForSongsIn(client, "", list, &error)
? COMMAND_RETURN_OK ? COMMAND_RETURN_OK
: print_error(client, error); : print_error(client, error);
locate_item_list_free(list);
return ret;
} }
enum command_return enum command_return
...@@ -188,7 +161,6 @@ handle_listall(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) ...@@ -188,7 +161,6 @@ handle_listall(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
enum command_return enum command_return
handle_list(struct client *client, int argc, char *argv[]) handle_list(struct client *client, int argc, char *argv[])
{ {
struct locate_item_list *conditionals;
unsigned tagType = locate_parse_type(argv[1]); unsigned tagType = locate_parse_type(argv[1]);
if (tagType == TAG_NUM_OF_ITEM_TYPES) { if (tagType == TAG_NUM_OF_ITEM_TYPES) {
...@@ -203,6 +175,7 @@ handle_list(struct client *client, int argc, char *argv[]) ...@@ -203,6 +175,7 @@ handle_list(struct client *client, int argc, char *argv[])
} }
/* for compatibility with < 0.12.0 */ /* for compatibility with < 0.12.0 */
SongFilter *filter;
if (argc == 3) { if (argc == 3) {
if (tagType != TAG_ALBUM) { if (tagType != TAG_ALBUM) {
command_error(client, ACK_ERROR_ARG, command_error(client, ACK_ERROR_ARG,
...@@ -211,28 +184,25 @@ handle_list(struct client *client, int argc, char *argv[]) ...@@ -211,28 +184,25 @@ handle_list(struct client *client, int argc, char *argv[])
return COMMAND_RETURN_ERROR; return COMMAND_RETURN_ERROR;
} }
conditionals = filter = new SongFilter((unsigned)TAG_ARTIST, argv[2]);
locate_item_list_new_single((unsigned)TAG_ARTIST,
argv[2]);
} else if (argc > 2) { } else if (argc > 2) {
conditionals = filter = new SongFilter();
locate_item_list_parse(argv + 2, argc - 2, false); if (!filter->Parse(argc - 2, argv + 2, false)) {
if (conditionals == NULL) { delete filter;
command_error(client, ACK_ERROR_ARG, command_error(client, ACK_ERROR_ARG,
"not able to parse args"); "not able to parse args");
return COMMAND_RETURN_ERROR; return COMMAND_RETURN_ERROR;
} }
} else } else
conditionals = nullptr; filter = nullptr;
GError *error = NULL; GError *error = NULL;
enum command_return ret = enum command_return ret =
listAllUniqueTags(client, tagType, conditionals, &error) listAllUniqueTags(client, tagType, filter, &error)
? COMMAND_RETURN_OK ? COMMAND_RETURN_OK
: print_error(client, error); : print_error(client, error);
if (conditionals != nullptr) delete filter;
locate_item_list_free(conditionals);
return ret; return ret;
} }
......
...@@ -39,14 +39,14 @@ AddSong(const char *playlist_path_utf8, ...@@ -39,14 +39,14 @@ AddSong(const char *playlist_path_utf8,
bool bool
search_add_to_playlist(const char *uri, const char *playlist_path_utf8, search_add_to_playlist(const char *uri, const char *playlist_path_utf8,
const struct locate_item_list *criteria, const SongFilter *filter,
GError **error_r) GError **error_r)
{ {
const Database *db = GetDatabase(error_r); const Database *db = GetDatabase(error_r);
if (db == nullptr) if (db == nullptr)
return false; return false;
const DatabaseSelection selection(uri, true, criteria); const DatabaseSelection selection(uri, true, filter);
using namespace std::placeholders; using namespace std::placeholders;
const auto f = std::bind(AddSong, playlist_path_utf8, _1, _2); const auto f = std::bind(AddSong, playlist_path_utf8, _1, _2);
......
...@@ -23,12 +23,12 @@ ...@@ -23,12 +23,12 @@
#include "gcc.h" #include "gcc.h"
#include "gerror.h" #include "gerror.h"
struct locate_item_list; class SongFilter;
gcc_nonnull(1,2) gcc_nonnull(1,2)
bool bool
search_add_to_playlist(const char *uri, const char *path_utf8, search_add_to_playlist(const char *uri, const char *path_utf8,
const struct locate_item_list *criteria, const SongFilter *filter,
GError **error_r); GError **error_r);
#endif #endif
...@@ -120,12 +120,12 @@ db_selection_print(struct client *client, const DatabaseSelection &selection, ...@@ -120,12 +120,12 @@ db_selection_print(struct client *client, const DatabaseSelection &selection,
return false; return false;
using namespace std::placeholders; using namespace std::placeholders;
const auto d = selection.match == nullptr const auto d = selection.filter == nullptr
? std::bind(PrintDirectory, client, _1) ? std::bind(PrintDirectory, client, _1)
: VisitDirectory(); : VisitDirectory();
const auto s = std::bind(full ? PrintSongFull : PrintSongBrief, const auto s = std::bind(full ? PrintSongFull : PrintSongBrief,
client, _1); client, _1);
const auto p = selection.match == nullptr const auto p = selection.filter == nullptr
? std::bind(full ? PrintPlaylistFull : PrintPlaylistBrief, ? std::bind(full ? PrintPlaylistFull : PrintPlaylistBrief,
client, _1, _2) client, _1, _2)
: VisitPlaylist(); : VisitPlaylist();
...@@ -155,14 +155,14 @@ stats_visitor_song(SearchStats &stats, song &song) ...@@ -155,14 +155,14 @@ stats_visitor_song(SearchStats &stats, song &song)
bool bool
searchStatsForSongsIn(struct client *client, const char *name, searchStatsForSongsIn(struct client *client, const char *name,
const struct locate_item_list *criteria, const SongFilter *filter,
GError **error_r) GError **error_r)
{ {
const Database *db = GetDatabase(error_r); const Database *db = GetDatabase(error_r);
if (db == nullptr) if (db == nullptr)
return false; return false;
const DatabaseSelection selection(name, true, criteria); const DatabaseSelection selection(name, true, filter);
SearchStats stats; SearchStats stats;
stats.numberOfSongs = 0; stats.numberOfSongs = 0;
...@@ -211,14 +211,14 @@ PrintUniqueTag(struct client *client, enum tag_type tag_type, ...@@ -211,14 +211,14 @@ PrintUniqueTag(struct client *client, enum tag_type tag_type,
bool bool
listAllUniqueTags(struct client *client, int type, listAllUniqueTags(struct client *client, int type,
const struct locate_item_list *criteria, const SongFilter *filter,
GError **error_r) GError **error_r)
{ {
const Database *db = GetDatabase(error_r); const Database *db = GetDatabase(error_r);
if (db == nullptr) if (db == nullptr)
return false; return false;
const DatabaseSelection selection("", true, criteria); const DatabaseSelection selection("", true, filter);
if (type == LOCATE_TAG_FILE_TYPE) { if (type == LOCATE_TAG_FILE_TYPE) {
using namespace std::placeholders; using namespace std::placeholders;
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <stdbool.h> #include <stdbool.h>
struct client; struct client;
struct locate_item_list; class SongFilter;
struct DatabaseSelection; struct DatabaseSelection;
struct db_visitor; struct db_visitor;
...@@ -47,13 +47,13 @@ printInfoForAllIn(struct client *client, const char *uri_utf8, ...@@ -47,13 +47,13 @@ printInfoForAllIn(struct client *client, const char *uri_utf8,
gcc_nonnull(1,2) gcc_nonnull(1,2)
bool bool
searchStatsForSongsIn(struct client *client, const char *name, searchStatsForSongsIn(struct client *client, const char *name,
const struct locate_item_list *criteria, const SongFilter *filter,
GError **error_r); GError **error_r);
gcc_nonnull(1) gcc_nonnull(1)
bool bool
listAllUniqueTags(struct client *client, int type, listAllUniqueTags(struct client *client, int type,
const struct locate_item_list *criteria, const SongFilter *filter,
GError **error_r); GError **error_r);
#endif #endif
...@@ -46,13 +46,13 @@ AddToQueue(struct player_control *pc, song &song, GError **error_r) ...@@ -46,13 +46,13 @@ AddToQueue(struct player_control *pc, song &song, GError **error_r)
bool bool
findAddIn(struct player_control *pc, const char *uri, 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); const Database *db = GetDatabase(error_r);
if (db == nullptr) if (db == nullptr)
return false; return false;
const DatabaseSelection selection(uri, true, criteria); const DatabaseSelection selection(uri, true, filter);
using namespace std::placeholders; using namespace std::placeholders;
const auto f = std::bind(AddToQueue, pc, _1, _2); const auto f = std::bind(AddToQueue, pc, _1, _2);
......
...@@ -23,12 +23,12 @@ ...@@ -23,12 +23,12 @@
#include "gcc.h" #include "gcc.h"
#include "gerror.h" #include "gerror.h"
struct locate_item_list; class SongFilter;
struct player_control; struct player_control;
gcc_nonnull(1,2) gcc_nonnull(1,2)
bool bool
findAddIn(struct player_control *pc, const char *name, findAddIn(struct player_control *pc, const char *name,
const struct locate_item_list *criteria, GError **error_r); const SongFilter *filter, GError **error_r);
#endif #endif
...@@ -23,5 +23,5 @@ ...@@ -23,5 +23,5 @@
bool bool
DatabaseSelection::Match(const song &song) const DatabaseSelection::Match(const song &song) const
{ {
return match == nullptr || locate_list_song_match(&song, match); return filter == nullptr || filter->Match(song);
} }
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <assert.h> #include <assert.h>
#include <stddef.h> #include <stddef.h>
struct locate_item_list; class SongFilter;
struct song; struct song;
struct DatabaseSelection { struct DatabaseSelection {
...@@ -41,11 +41,11 @@ struct DatabaseSelection { ...@@ -41,11 +41,11 @@ struct DatabaseSelection {
*/ */
bool recursive; bool recursive;
const locate_item_list *match; const SongFilter *filter;
DatabaseSelection(const char *_uri, bool _recursive, DatabaseSelection(const char *_uri, bool _recursive,
const locate_item_list *_match=nullptr) const SongFilter *_filter=nullptr)
:uri(_uri), recursive(_recursive), match(_match) { :uri(_uri), recursive(_recursive), filter(_filter) {
assert(uri != NULL); assert(uri != NULL);
} }
......
...@@ -291,7 +291,7 @@ directory_sort(struct directory *directory) ...@@ -291,7 +291,7 @@ directory_sort(struct directory *directory)
} }
bool bool
directory::Walk(bool recursive, const locate_item_list *match, directory::Walk(bool recursive, const SongFilter *filter,
VisitDirectory visit_directory, VisitSong visit_song, VisitDirectory visit_directory, VisitSong visit_song,
VisitPlaylist visit_playlist, VisitPlaylist visit_playlist,
GError **error_r) const GError **error_r) const
...@@ -301,8 +301,7 @@ directory::Walk(bool recursive, const locate_item_list *match, ...@@ -301,8 +301,7 @@ directory::Walk(bool recursive, const locate_item_list *match,
if (visit_song) { if (visit_song) {
struct song *song; struct song *song;
directory_for_each_song(song, this) directory_for_each_song(song, this)
if ((match == NULL || if ((filter == nullptr || filter->Match(*song)) &&
locate_list_song_match(song, match)) &&
!visit_song(*song, error_r)) !visit_song(*song, error_r))
return false; return false;
} }
...@@ -321,7 +320,7 @@ directory::Walk(bool recursive, const locate_item_list *match, ...@@ -321,7 +320,7 @@ directory::Walk(bool recursive, const locate_item_list *match,
return false; return false;
if (recursive && if (recursive &&
!child->Walk(recursive, match, !child->Walk(recursive, filter,
visit_directory, visit_song, visit_playlist, visit_directory, visit_song, visit_playlist,
error_r)) error_r))
return false; return false;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "config.h" #include "config.h"
#include "PlaylistPrint.hxx" #include "PlaylistPrint.hxx"
#include "QueuePrint.hxx"
extern "C" { extern "C" {
#include "playlist_list.h" #include "playlist_list.h"
...@@ -26,7 +27,6 @@ extern "C" { ...@@ -26,7 +27,6 @@ extern "C" {
#include "playlist_any.h" #include "playlist_any.h"
#include "playlist_song.h" #include "playlist_song.h"
#include "playlist.h" #include "playlist.h"
#include "queue_print.h"
#include "stored_playlist.h" #include "stored_playlist.h"
#include "song_print.h" #include "song_print.h"
#include "song.h" #include "song.h"
...@@ -91,9 +91,9 @@ playlist_print_current(struct client *client, const struct playlist *playlist) ...@@ -91,9 +91,9 @@ playlist_print_current(struct client *client, const struct playlist *playlist)
void void
playlist_print_find(struct client *client, const struct playlist *playlist, 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 void
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
struct client; struct client;
struct playlist; struct playlist;
struct locate_item_list; class SongFilter;
/** /**
* Sends the whole playlist to the client, song URIs only. * Sends the whole playlist to the client, song URIs only.
...@@ -66,7 +66,7 @@ playlist_print_current(struct client *client, const struct playlist *playlist); ...@@ -66,7 +66,7 @@ playlist_print_current(struct client *client, const struct playlist *playlist);
*/ */
void void
playlist_print_find(struct client *client, const struct playlist *playlist, 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. * Print detailed changes since the specified playlist version.
......
...@@ -246,18 +246,13 @@ static enum command_return ...@@ -246,18 +246,13 @@ static enum command_return
handle_playlist_match(struct client *client, int argc, char *argv[], handle_playlist_match(struct client *client, int argc, char *argv[],
bool fold_case) bool fold_case)
{ {
struct locate_item_list *list = SongFilter filter;
locate_item_list_parse(argv + 1, argc - 1, fold_case); if (!filter.Parse(argc - 1, argv + 1, fold_case)) {
if (list == NULL) {
command_error(client, ACK_ERROR_ARG, "incorrect arguments"); command_error(client, ACK_ERROR_ARG, "incorrect arguments");
return COMMAND_RETURN_ERROR; return COMMAND_RETURN_ERROR;
} }
playlist_print_find(client, &g_playlist, list); playlist_print_find(client, &g_playlist, filter);
locate_item_list_free(list);
return COMMAND_RETURN_OK; return COMMAND_RETURN_OK;
} }
......
...@@ -18,10 +18,10 @@ ...@@ -18,10 +18,10 @@
*/ */
#include "config.h" #include "config.h"
#include "QueuePrint.hxx"
#include "SongFilter.hxx" #include "SongFilter.hxx"
extern "C" { extern "C" {
#include "queue_print.h"
#include "queue.h" #include "queue.h"
#include "song.h" #include "song.h"
#include "song_print.h" #include "song_print.h"
...@@ -96,12 +96,12 @@ queue_print_changes_position(struct client *client, const struct queue *queue, ...@@ -96,12 +96,12 @@ queue_print_changes_position(struct client *client, const struct queue *queue,
void void
queue_find(struct client *client, const struct queue *queue, 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++) { for (unsigned i = 0; i < queue_length(queue); i++) {
const struct song *song = queue_get(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); queue_print_song_info(client, queue, i);
} }
} }
/* /*
* Copyright (C) 2003-2011 The Music Player Daemon Project * Copyright (C) 2003-2012 The Music Player Daemon Project
* http://www.musicpd.org * http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -22,14 +22,14 @@ ...@@ -22,14 +22,14 @@
* client. * client.
*/ */
#ifndef QUEUE_PRINT_H #ifndef MPD_QUEUE_PRINT_HXX
#define QUEUE_PRINT_H #define MPD_QUEUE_PRINT_HXX
#include <stdint.h> #include <stdint.h>
struct client; struct client;
struct queue; struct queue;
struct locate_item_list; class SongFilter;
void void
queue_print_info(struct client *client, const struct queue *queue, 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, ...@@ -49,6 +49,6 @@ queue_print_changes_position(struct client *client, const struct queue *queue,
void void
queue_find(struct client *client, const struct queue *queue, queue_find(struct client *client, const struct queue *queue,
const struct locate_item_list *criteria); const SongFilter &filter);
#endif #endif
...@@ -35,27 +35,6 @@ extern "C" { ...@@ -35,27 +35,6 @@ extern "C" {
#define LOCATE_TAG_FILE_KEY_OLD "filename" #define LOCATE_TAG_FILE_KEY_OLD "filename"
#define LOCATE_TAG_ANY_KEY "any" #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 unsigned
locate_parse_type(const char *str) locate_parse_type(const char *str)
{ {
...@@ -69,107 +48,52 @@ locate_parse_type(const char *str) ...@@ -69,107 +48,52 @@ locate_parse_type(const char *str)
return tag_name_parse_i(str); return tag_name_parse_i(str);
} }
static bool SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case)
locate_item_init(struct locate_item *item, :tag(_tag), fold_case(_fold_case),
const char *type_string, const char *needle, value(fold_case
bool fold_case) ? g_utf8_casefold(_value, -1)
{ : g_strdup(_value))
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)
{ {
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 * SongFilter::Item::~Item()
locate_item_list_parse(char *argv[], unsigned argc, bool fold_case)
{ {
if (argc == 0 || argc % 2 != 0) g_free(value);
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;
} }
gcc_pure bool
static bool SongFilter::Item::StringMatch(const char *s) const
locate_string_match(const struct locate_item *item, const char *value)
{ {
assert(item != NULL); assert(value != nullptr);
assert(value != NULL); assert(s != nullptr);
if (item->fold_case) { if (fold_case) {
char *p = g_utf8_casefold(value, -1); char *p = g_utf8_casefold(s, -1);
const bool result = strstr(p, item->needle) != NULL; const bool result = strstr(p, value) != NULL;
g_free(p); g_free(p);
return result; return result;
} else { } else {
return strcmp(value, item->needle) == 0; return strcmp(s, value) == 0;
} }
} }
gcc_pure bool
static bool SongFilter::Item::Match(const tag_item &item) const
locate_tag_match(const struct locate_item *item, const struct tag *tag)
{ {
assert(item != NULL); return (tag == LOCATE_TAG_ANY_TYPE || (unsigned)item.type == tag) &&
assert(tag != NULL); StringMatch(item.value);
}
bool
SongFilter::Item::Match(const struct tag &_tag) const
{
bool visited_types[TAG_NUM_OF_ITEM_TYPES]; 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++) { for (unsigned i = 0; i < _tag.num_items; i++) {
visited_types[tag->items[i]->type] = true; visited_types[_tag.items[i]->type] = true;
if (item->tag != LOCATE_TAG_ANY_TYPE &&
tag->items[i]->type != item->tag)
continue;
if (locate_string_match(item, tag->items[i]->value)) if (Match(*_tag.items[i]))
return true; return true;
} }
...@@ -179,36 +103,67 @@ locate_tag_match(const struct locate_item *item, const struct tag *tag) ...@@ -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 * empty (first char is a \0), then it's a match as well and
* we should return true. * we should return true.
*/ */
if (*item->needle == 0 && item->tag != LOCATE_TAG_ANY_TYPE && if (*value == 0 && tag < TAG_NUM_OF_ITEM_TYPES &&
!visited_types[item->tag]) !visited_types[tag])
return true; return true;
return false; return false;
} }
gcc_pure bool
static bool SongFilter::Item::Match(const song &song) const
locate_song_match(const struct locate_item *item, const struct song *song)
{ {
if (item->tag == LOCATE_TAG_FILE_TYPE || if (tag == LOCATE_TAG_FILE_TYPE || tag == LOCATE_TAG_ANY_TYPE) {
item->tag == LOCATE_TAG_ANY_TYPE) { char *uri = song_get_uri(&song);
char *uri = song_get_uri(song); const bool result = StringMatch(uri);
const bool result = locate_string_match(item, uri);
g_free(uri); g_free(uri);
if (result || item->tag == LOCATE_TAG_FILE_TYPE) if (result || tag == LOCATE_TAG_FILE_TYPE)
return result; 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 bool
locate_list_song_match(const struct song *song, SongFilter::Match(const song &song) const
const struct locate_item_list *criteria)
{ {
for (unsigned i = 0; i < criteria->length; i++) for (const auto &i : items)
if (!locate_song_match(&criteria->items[i], song)) if (!i.Match(song))
return false; return false;
return true; return true;
......
...@@ -22,15 +22,82 @@ ...@@ -22,15 +22,82 @@
#include "gcc.h" #include "gcc.h"
#include <list>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10 #define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10
#define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20 #define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20
struct locate_item_list; struct tag;
struct tag_item;
struct song; 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 * @return #TAG_NUM_OF_ITEM_TYPES on error
*/ */
...@@ -38,23 +105,4 @@ gcc_pure ...@@ -38,23 +105,4 @@ gcc_pure
unsigned unsigned
locate_parse_type(const char *str); 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 #endif
...@@ -282,7 +282,7 @@ SimpleDatabase::Visit(const DatabaseSelection &selection, ...@@ -282,7 +282,7 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
return false; return false;
db_lock(); db_lock();
bool ret = directory->Walk(selection.recursive, selection.match, bool ret = directory->Walk(selection.recursive, selection.filter,
visit_directory, visit_song, visit_playlist, visit_directory, visit_song, visit_playlist,
error_r); error_r);
db_unlock(); db_unlock();
......
...@@ -55,7 +55,10 @@ ...@@ -55,7 +55,10 @@
struct song; struct song;
struct db_visitor; struct db_visitor;
struct locate_item_list;
#ifdef __cplusplus
class SongFilter;
#endif
struct directory { struct directory {
/** /**
...@@ -97,7 +100,7 @@ struct directory { ...@@ -97,7 +100,7 @@ struct directory {
/** /**
* Caller must lock #db_mutex. * 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, VisitDirectory visit_directory, VisitSong visit_song,
VisitPlaylist visit_playlist, VisitPlaylist visit_playlist,
GError **error_r) const; GError **error_r) const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment