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.
This commit is contained in:
parent
6fe43ed969
commit
ac0852b4e3
1
NEWS
1
NEWS
|
@ -1,6 +1,7 @@
|
||||||
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
|
||||||
|
|
||||||
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)
|
||||||
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,7 +330,10 @@ 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)
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
|
|
Loading…
Reference in New Issue