diff --git a/NEWS b/NEWS index a04b255ee..f2e49ce46 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ ver 0.20 (not yet released) * protocol - "commands" returns playlist commands only if playlist_directory configured + - "search"/"find" have a "window" parameter * output - pulse: set channel map to WAVE-EX diff --git a/doc/protocol.xml b/doc/protocol.xml index 858ca0990..a85bbbc86 100644 --- a/doc/protocol.xml +++ b/doc/protocol.xml @@ -1558,6 +1558,7 @@ OK TYPE WHAT ... + window START:END @@ -1602,6 +1603,13 @@ OK WHAT is what to find. + + + window can be used to query only a + portion of the real response. The parameter is two + zero-based record numbers; a start number and an end + number. + @@ -1794,6 +1802,7 @@ OK TYPE WHAT ... + window START:END diff --git a/src/command/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx index a3ea8d0ae..988542f44 100644 --- a/src/command/DatabaseCommands.cxx +++ b/src/command/DatabaseCommands.cxx @@ -32,6 +32,7 @@ #include "util/Error.hxx" #include "SongFilter.hxx" #include "protocol/Result.hxx" +#include "protocol/ArgParser.hxx" #include "BulkEdit.hxx" #include @@ -70,6 +71,16 @@ handle_match(Client &client, unsigned argc, char *argv[], bool fold_case) { ConstBuffer args(argv + 1, argc - 1); + unsigned window_start = 0, window_end = std::numeric_limits::max(); + if (args.size >= 2 && strcmp(args[args.size - 2], "window") == 0) { + if (!check_range(client, &window_start, &window_end, + args.back())) + return CommandResult::ERROR; + + args.pop_back(); + args.pop_back(); + } + SongFilter filter; if (!filter.Parse(args, fold_case)) { command_error(client, ACK_ERROR_ARG, "incorrect arguments"); @@ -79,7 +90,8 @@ handle_match(Client &client, unsigned argc, char *argv[], bool fold_case) const DatabaseSelection selection("", true, &filter); Error error; - return db_selection_print(client, selection, true, false, error) + return db_selection_print(client, selection, true, false, + window_start, window_end, error) ? CommandResult::OK : print_error(client, error); } diff --git a/src/db/DatabasePrint.cxx b/src/db/DatabasePrint.cxx index 498aedf97..945ac6ab9 100644 --- a/src/db/DatabasePrint.cxx +++ b/src/db/DatabasePrint.cxx @@ -147,27 +147,49 @@ PrintPlaylistFull(Client &client, bool base, bool db_selection_print(Client &client, const DatabaseSelection &selection, - bool full, bool base, Error &error) + bool full, bool base, + unsigned window_start, unsigned window_end, + Error &error) { const Database *db = client.GetDatabase(error); if (db == nullptr) return false; + unsigned i = 0; + using namespace std::placeholders; const auto d = selection.filter == nullptr ? std::bind(full ? PrintDirectoryFull : PrintDirectoryBrief, std::ref(client), base, _1) : VisitDirectory(); - const auto s = std::bind(full ? PrintSongFull : PrintSongBrief, - std::ref(client), base, _1); + VisitSong s = std::bind(full ? PrintSongFull : PrintSongBrief, + std::ref(client), base, _1); const auto p = selection.filter == nullptr ? std::bind(full ? PrintPlaylistFull : PrintPlaylistBrief, std::ref(client), base, _1, _2) : VisitPlaylist(); + if (window_start > 0 || window_end < std::numeric_limits::max()) + s = [s, window_start, window_end, &i](const LightSong &song, + Error &error2){ + const bool in_window = i >= window_start && i < window_end; + ++i; + return !in_window || s(song, error2); + }; + return db->Visit(selection, d, s, p, error); } +bool +db_selection_print(Client &client, const DatabaseSelection &selection, + bool full, bool base, + Error &error) +{ + return db_selection_print(client, selection, full, base, + 0, std::numeric_limits::max(), + error); +} + static bool PrintSongURIVisitor(Client &client, const LightSong &song) { diff --git a/src/db/DatabasePrint.hxx b/src/db/DatabasePrint.hxx index 2ab5e703d..7e4dd8572 100644 --- a/src/db/DatabasePrint.hxx +++ b/src/db/DatabasePrint.hxx @@ -37,6 +37,12 @@ bool db_selection_print(Client &client, const DatabaseSelection &selection, bool full, bool base, Error &error); +bool +db_selection_print(Client &client, const DatabaseSelection &selection, + bool full, bool base, + unsigned window_start, unsigned window_end, + Error &error); + bool PrintUniqueTags(Client &client, unsigned type, uint32_t group_mask, const SongFilter *filter,