Commit ac0852b4 authored by Max Kellermann's avatar Max Kellermann

song/Filter: operator "==" never searches substrings in filter expressions

The protocol documentation says that the difference between `find` and `search` is that `search` is case insensitive, but that's only half the truth: `search` also searches for sub strings instead of matching the whole string. This part is undocumented and unfortunate, but at this point, we can't change it. However leaking this surprising behavior to the new filter expressions was a bad idea; the "==" operator should never match substrings. For people who need that, we should add a new operator.
parent 6fe43ed9
ver 0.21.1 (not yet released) ver 0.21.1 (not yet released)
* protocol * protocol
- allow escaping quotes in filter expressions - allow escaping quotes in filter expressions
- operator "==" never searches substrings in filter expressions
* decoder * decoder
- ffmpeg: fix build failure with non-standard FFmpeg installation path - ffmpeg: fix build failure with non-standard FFmpeg installation path
- flac: fix linker failure when building without FLAC support - flac: fix linker failure when building without FLAC support
......
...@@ -91,8 +91,11 @@ locate_parse_type(const char *str) noexcept ...@@ -91,8 +91,11 @@ locate_parse_type(const char *str) noexcept
SongFilter::SongFilter(TagType tag, const char *value, bool fold_case) SongFilter::SongFilter(TagType tag, const char *value, bool fold_case)
{ {
/* for compatibility with MPD 0.20 and older, "fold_case" also
switches on "substring" */
and_filter.AddItem(std::make_unique<TagSongFilter>(tag, value, and_filter.AddItem(std::make_unique<TagSongFilter>(tag, value,
fold_case, false)); fold_case, fold_case,
false));
} }
SongFilter::~SongFilter() SongFilter::~SongFilter()
...@@ -296,11 +299,13 @@ SongFilter::ParseExpression(const char *&s, bool fold_case) ...@@ -296,11 +299,13 @@ SongFilter::ParseExpression(const char *&s, bool fold_case)
if (type == LOCATE_TAG_FILE_TYPE) if (type == LOCATE_TAG_FILE_TYPE)
return std::make_unique<UriSongFilter>(std::move(value), return std::make_unique<UriSongFilter>(std::move(value),
fold_case, fold_case,
false,
negated); negated);
return std::make_unique<TagSongFilter>(TagType(type), return std::make_unique<TagSongFilter>(TagType(type),
std::move(value), std::move(value),
fold_case, negated); fold_case, false,
negated);
} }
} }
...@@ -325,8 +330,11 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case) ...@@ -325,8 +330,11 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
break; break;
case LOCATE_TAG_FILE_TYPE: case LOCATE_TAG_FILE_TYPE:
/* for compatibility with MPD 0.20 and older,
"fold_case" also switches on "substring" */
and_filter.AddItem(std::make_unique<UriSongFilter>(value, and_filter.AddItem(std::make_unique<UriSongFilter>(value,
fold_case, fold_case,
fold_case,
false)); false));
break; break;
...@@ -334,9 +342,12 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case) ...@@ -334,9 +342,12 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
if (tag == LOCATE_TAG_ANY_TYPE) if (tag == LOCATE_TAG_ANY_TYPE)
tag = TAG_NUM_OF_ITEM_TYPES; tag = TAG_NUM_OF_ITEM_TYPES;
/* for compatibility with MPD 0.20 and older,
"fold_case" also switches on "substring" */
and_filter.AddItem(std::make_unique<TagSongFilter>(TagType(tag), and_filter.AddItem(std::make_unique<TagSongFilter>(TagType(tag),
value, value,
fold_case, fold_case,
fold_case,
false)); false));
break; break;
} }
......
...@@ -40,12 +40,12 @@ class StringFilter { ...@@ -40,12 +40,12 @@ class StringFilter {
public: public:
template<typename V> template<typename V>
StringFilter(V &&_value, bool _fold_case) StringFilter(V &&_value, bool _fold_case, bool _substring)
:value(std::forward<V>(_value)), :value(std::forward<V>(_value)),
fold_case(_fold_case fold_case(_fold_case
? IcuCompare(value.c_str()) ? IcuCompare(value.c_str())
: IcuCompare()), : IcuCompare()),
substring(_fold_case) {} substring(_substring) {}
bool empty() const noexcept { bool empty() const noexcept {
return value.empty(); return value.empty();
......
...@@ -42,9 +42,10 @@ class TagSongFilter final : public ISongFilter { ...@@ -42,9 +42,10 @@ class TagSongFilter final : public ISongFilter {
public: public:
template<typename V> template<typename V>
TagSongFilter(TagType _type, V &&_value, bool fold_case, bool _negated) TagSongFilter(TagType _type, V &&_value, bool fold_case, bool substring,
bool _negated)
:type(_type), negated(_negated), :type(_type), negated(_negated),
filter(std::forward<V>(_value), fold_case) {} filter(std::forward<V>(_value), fold_case, substring) {}
TagType GetTagType() const { TagType GetTagType() const {
return type; return type;
......
...@@ -32,8 +32,9 @@ class UriSongFilter final : public ISongFilter { ...@@ -32,8 +32,9 @@ class UriSongFilter final : public ISongFilter {
public: public:
template<typename V> template<typename V>
UriSongFilter(V &&_value, bool fold_case, bool _negated) UriSongFilter(V &&_value, bool fold_case, bool substring,
:filter(std::forward<V>(_value), fold_case), bool _negated)
:filter(std::forward<V>(_value), fold_case, substring),
negated(_negated) {} negated(_negated) {}
const auto &GetValue() const noexcept { const auto &GetValue() const noexcept {
......
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