From 2aee1b86f364dfc9d897939081eb4f0403f9a729 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 29 Oct 2013 18:54:34 +0100 Subject: [PATCH] SongFilter: add special keyword "base" Restores the features from the previous draft commands "findin" / "searchin". --- NEWS | 1 + doc/protocol.xml | 8 ++++++-- src/DatabaseSelection.cxx | 10 ++++++++++ src/DatabaseSelection.hxx | 4 +--- src/SongFilter.cxx | 27 +++++++++++++++++++++++++++ src/SongFilter.hxx | 12 ++++++++++++ 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 8922ff562..15b88ff64 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ ver 0.18 (2012/??/??) - new command "readcomments" lists arbitrary file tags - new command "toggleoutput" - "find"/"search" with "any" does not match file name + - "search" and "find" with base URI (keyword "base") - search for album artist falls back to the artist tag - re-add the "volume" command * input: diff --git a/doc/protocol.xml b/doc/protocol.xml index 234db46db..2068b6925 100644 --- a/doc/protocol.xml +++ b/doc/protocol.xml @@ -1483,9 +1483,13 @@ OK Finds songs in the db that are exactly WHAT. TYPE can - be any tag supported by MPD, or one of the two special + be any tag supported by MPD, or one of the three special parameters — file to search by - full path (relative to database root), and + + full path (relative to the music directory), + in to restrict the search to + songs in the given directory (also relative to the music + directory) and any to match against all available tags. WHAT is what to find. diff --git a/src/DatabaseSelection.cxx b/src/DatabaseSelection.cxx index a372d5862..2164ba2cd 100644 --- a/src/DatabaseSelection.cxx +++ b/src/DatabaseSelection.cxx @@ -20,6 +20,16 @@ #include "DatabaseSelection.hxx" #include "SongFilter.hxx" +DatabaseSelection::DatabaseSelection(const char *_uri, bool _recursive, + const SongFilter *_filter) + :uri(_uri), recursive(_recursive), filter(_filter) +{ + /* optimization: if the caller didn't specify a base URI, pick + the one from SongFilter */ + if (uri.empty() && filter != nullptr) + uri = filter->GetBase(); +} + bool DatabaseSelection::Match(const Song &song) const { diff --git a/src/DatabaseSelection.hxx b/src/DatabaseSelection.hxx index 67a88b945..cdc0a8fef 100644 --- a/src/DatabaseSelection.hxx +++ b/src/DatabaseSelection.hxx @@ -42,9 +42,7 @@ struct DatabaseSelection { const SongFilter *filter; DatabaseSelection(const char *_uri, bool _recursive, - const SongFilter *_filter=nullptr) - :uri(_uri), recursive(_recursive), filter(_filter) { - } + const SongFilter *_filter=nullptr); gcc_pure bool Match(const Song &song) const; diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx index 7592f2665..396bd7191 100644 --- a/src/SongFilter.cxx +++ b/src/SongFilter.cxx @@ -22,6 +22,7 @@ #include "Song.hxx" #include "tag/Tag.hxx" #include "util/ASCII.hxx" +#include "util/UriUtil.hxx" #include @@ -43,6 +44,9 @@ locate_parse_type(const char *str) if (StringEqualsCaseASCII(str, LOCATE_TAG_ANY_KEY)) return LOCATE_TAG_ANY_TYPE; + if (strcmp(str, "base") == 0) + return LOCATE_TAG_BASE_TYPE; + return tag_name_parse_i(str); } @@ -134,6 +138,11 @@ SongFilter::Item::Match(const Tag &_tag) const bool SongFilter::Item::Match(const Song &song) const { + if (tag == LOCATE_TAG_BASE_TYPE) { + const auto uri = song.GetURI(); + return uri_is_child_or_same(value.c_str(), uri.c_str()); + } + if (tag == LOCATE_TAG_FILE_TYPE) { const auto uri = song.GetURI(); return StringMatch(uri.c_str()); @@ -159,6 +168,14 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case) if (tag == TAG_NUM_OF_ITEM_TYPES) return false; + if (tag == LOCATE_TAG_BASE_TYPE) { + if (!uri_safe_local(value)) + return false; + + /* case folding doesn't work with "base" */ + fold_case = false; + } + items.push_back(Item(tag, value, fold_case)); return true; } @@ -185,3 +202,13 @@ SongFilter::Match(const Song &song) const return true; } + +std::string +SongFilter::GetBase() const +{ + for (const auto &i : items) + if (i.GetTag() == LOCATE_TAG_BASE_TYPE) + return i.GetValue(); + + return std::string(); +} diff --git a/src/SongFilter.hxx b/src/SongFilter.hxx index 6f77ecc7e..a71fe2cb1 100644 --- a/src/SongFilter.hxx +++ b/src/SongFilter.hxx @@ -27,6 +27,11 @@ #include +/** + * Limit the search to files within the given directory. + */ +#define LOCATE_TAG_BASE_TYPE (TAG_NUM_OF_ITEM_TYPES + 1) + #define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10 #define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20 @@ -99,6 +104,13 @@ public: const std::list &GetItems() const { return items; } + + /** + * Returns the "base" specification (if there is one) or an + * empty string. + */ + gcc_pure + std::string GetBase() const; }; /**