From fcfb7bdb95baf7febc2adf437c3f2c94c5cb96c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6hler?= Date: Wed, 3 Oct 2007 01:18:13 +0000 Subject: [PATCH] #438360: Replace str{,n}casestr and strcasecmp by qof_utf8_{substr_nocase,strcasecmp}. The functions used did not work for non-ascii characters. The new implementations use g_utf8_casefold and g_utf8_normalize to improve case insensitive searches and comparisons. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@16547 57a11ea4-9604-0410-9ed3-97b8803252fd --- lib/libqof/qof/qofquerycore.c | 2 +- lib/libqof/qof/qofutil.c | 63 ++++++++++++++++++++++------------- lib/libqof/qof/qofutil.h | 17 ++++++---- 3 files changed, 50 insertions(+), 32 deletions(-) diff --git a/lib/libqof/qof/qofquerycore.c b/lib/libqof/qof/qofquerycore.c index d78ab7c5e5..f10ef5beb8 100644 --- a/lib/libqof/qof/qofquerycore.c +++ b/lib/libqof/qof/qofquerycore.c @@ -148,7 +148,7 @@ string_match_predicate (gpointer object, ret = 1; } else if (pdata->options == QOF_STRING_MATCH_CASEINSENSITIVE) { - if (strcasestr (s, pdata->matchstring)) + if (qof_utf8_substr_nocase (s, pdata->matchstring)) ret = 1; } else { diff --git a/lib/libqof/qof/qofutil.c b/lib/libqof/qof/qofutil.c index 51b8971e29..06f92958da 100644 --- a/lib/libqof/qof/qofutil.c +++ b/lib/libqof/qof/qofutil.c @@ -36,33 +36,48 @@ static QofLogModule log_module = QOF_MOD_UTIL; -/* Search for str2 in first nchar chars of str1, ignore case.. Return - * pointer to first match, or null. */ -gchar * -strncasestr(const guchar *str1, const guchar *str2, size_t len) +gboolean +qof_utf8_substr_nocase (const gchar *haystack, const gchar *needle) { - while (*str1 && len--) - { - if (toupper(*str1) == toupper(*str2)) - { - if (strncasecmp(str1,str2,strlen(str2)) == 0) - { - return (gchar *) str1; - } - } - str1++; - } - return NULL; + gchar *haystack_casefold, *haystack_normalized; + gchar *needle_casefold, *needle_normalized; + gchar *p; + gint offset; + + g_return_val_if_fail (haystack && needle, FALSE); + + haystack_casefold = g_utf8_casefold (haystack, -1); + haystack_normalized = g_utf8_normalize (haystack_casefold, -1, + G_NORMALIZE_ALL); + g_free (haystack_casefold); + + needle_casefold = g_utf8_casefold (needle, -1); + needle_normalized = g_utf8_normalize (needle_casefold, -1, G_NORMALIZE_ALL); + g_free (needle_casefold); + + p = strstr (haystack_normalized, needle_normalized); + g_free (haystack_normalized); + g_free (needle_normalized); + + return p != NULL; } -/* Search for str2 in str1, ignore case. Return pointer to first - * match, or null. */ -gchar * -strcasestr(const gchar *str1, const gchar *str2) +gint +qof_utf8_strcasecmp (const gchar *da, const gchar *db) { - size_t len = strlen (str1); - gchar * retval = strncasestr (str1, str2, len); - return retval; + gchar *da_casefold, *db_casefold; + gint retval; + + g_return_val_if_fail (da != NULL, 0); + g_return_val_if_fail (db != NULL, 0); + + da_casefold = g_utf8_casefold (da, -1); + db_casefold = g_utf8_casefold (db, -1); + retval = g_utf8_collate (da_casefold, db_casefold); + g_free (da_casefold); + g_free (db_casefold); + + return retval; } gint @@ -89,7 +104,7 @@ safe_strcasecmp (const gchar * da, const gchar * db) { if ((da) && (db)) { if ((da) != (db)) { - gint retval = strcasecmp ((da), (db)); + gint retval = qof_utf8_strcasecmp ((da), (db)); /* if strings differ, return */ if (retval) return retval; } diff --git a/lib/libqof/qof/qofutil.h b/lib/libqof/qof/qofutil.h index 5a63a76ce7..f1221399af 100644 --- a/lib/libqof/qof/qofutil.h +++ b/lib/libqof/qof/qofutil.h @@ -166,6 +166,16 @@ void qof_close (void); /* **** Prototypes *********************************************/ +/** Search for an occurence of the substring needle in the string + * haystack, ignoring case. Return TRUE if one is found or FALSE + * otherwise. */ +gboolean qof_utf8_substr_nocase (const gchar *haystack, const gchar *needle); + +/** Use g_utf8_casefold and g_utf8_collate to compare two utf8 strings, + * ignore case. Return < 0 if da compares before db, 0 if they compare + * equal, > 0 if da compares after db. */ +gint qof_utf8_strcasecmp (const gchar *da, const gchar *db); + /** The safe_strcmp compares strings da and db the same way that strcmp() does, except that either may be null. This routine assumes that a non-null string is always greater than a null string. @@ -201,13 +211,6 @@ gint safe_strcasecmp (const gchar * da, const gchar * db); */ gint null_strcmp (const gchar * da, const gchar * db); -/** Search for str2 in first nchar chars of str1, ignore case. Return - * pointer to first match, or null. These are just like that strnstr - * and the strstr functions, except that they ignore the case. */ -extern gchar *strncasestr(const guchar *str1, const guchar *str2, - size_t len); -extern gchar *strcasestr(const gchar *str1, const gchar *str2); - /** The ultostr() subroutine is the inverse of strtoul(). It accepts a * number and prints it in the indicated base. The returned string * should be g_freed when done. */