lib/icu/Compare: add fallback using strcasecmp() and strcasestr()

Our IcuCaseFold() fallback using strxfrm() is not actually case
insensitive.  This commit fixes the problem by switching to
strcasecmp().  That function is not guaranteed to support UTF-8, but
it's the best we can do in this sparse situation.

Closes #111
This commit is contained in:
Max Kellermann 2017-09-20 23:43:06 +02:00
parent 66646d9276
commit 1295a1272a
4 changed files with 31 additions and 0 deletions

1
NEWS
View File

@ -3,6 +3,7 @@ ver 0.20.11 (not yet released)
- curl: support Content-Type application/xml - curl: support Content-Type application/xml
* decoder * decoder
- ffmpeg: more reliable song duration - ffmpeg: more reliable song duration
* fix case insensitive search without libicu
ver 0.20.10 (2017/08/24) ver 0.20.10 (2017/08/24)
* decoder * decoder

View File

@ -241,6 +241,7 @@ AC_CHECK_FUNCS(getpwnam_r getpwuid_r)
AC_CHECK_FUNCS(initgroups) AC_CHECK_FUNCS(initgroups)
AC_CHECK_FUNCS(fnmatch) AC_CHECK_FUNCS(fnmatch)
AC_CHECK_FUNCS(strndup) AC_CHECK_FUNCS(strndup)
AC_CHECK_FUNCS(strcasestr)
if test x$host_is_linux = xyes; then if test x$host_is_linux = xyes; then
MPD_OPTIONAL_FUNC(eventfd, eventfd, USE_EVENTFD) MPD_OPTIONAL_FUNC(eventfd, eventfd, USE_EVENTFD)

View File

@ -23,6 +23,10 @@
#include "check.h" #include "check.h"
#include "Compiler.h" #include "Compiler.h"
#if defined(HAVE_ICU) || defined(_WIN32)
#define HAVE_ICU_CASE_FOLD
#endif
template<typename T> class AllocatedString; template<typename T> class AllocatedString;
gcc_nonnull_all gcc_nonnull_all

View File

@ -24,18 +24,43 @@
#include <string.h> #include <string.h>
#ifdef HAVE_ICU_CASE_FOLD
IcuCompare::IcuCompare(const char *_needle) noexcept IcuCompare::IcuCompare(const char *_needle) noexcept
:needle(IcuCaseFold(_needle)) {} :needle(IcuCaseFold(_needle)) {}
#else
IcuCompare::IcuCompare(const char *_needle) noexcept
:needle(AllocatedString<>::Duplicate(_needle)) {}
#endif
bool bool
IcuCompare::operator==(const char *haystack) const noexcept IcuCompare::operator==(const char *haystack) const noexcept
{ {
#ifdef HAVE_ICU_CASE_FOLD
return StringIsEqual(IcuCaseFold(haystack).c_str(), needle.c_str()); return StringIsEqual(IcuCaseFold(haystack).c_str(), needle.c_str());
#else
return strcasecmp(haystack, needle.c_str());
#endif
} }
bool bool
IcuCompare::IsIn(const char *haystack) const noexcept IcuCompare::IsIn(const char *haystack) const noexcept
{ {
#ifdef HAVE_ICU_CASE_FOLD
return StringFind(IcuCaseFold(haystack).c_str(), return StringFind(IcuCaseFold(haystack).c_str(),
needle.c_str()) != nullptr; needle.c_str()) != nullptr;
#elif defined(HAVE_STRCASESTR)
return strcasestr(haystack, needle.c_str()) != nullptr;
#else
/* poor man's strcasestr() */
for (const size_t length = strlen(needle.c_str());
*haystack != 0; ++haystack)
if (strncasecmp(haystack, needle.c_str(), length) == 0)
return true;
return false;
#endif
} }