]> granicus.if.org Git - neomutt/commitdiff
Implement case-insensitive substring search
authorAustin Ray <austin@austinray.io>
Sat, 18 Aug 2018 21:21:14 +0000 (17:21 -0400)
committerRichard Russon <rich@flatcap.org>
Thu, 4 Oct 2018 14:48:45 +0000 (15:48 +0100)
Implemented a portable case-insensitive substring search since the C
standard does not provide one. A C implementation may include one as an
extension, but there is no way to ensure portability.

This implementation does a byte-by-byte in-place comparison so it will
return unspecified results for multibyte locales.

Included alongside this implementation are tests for NULL input, empty
string inputs, non-existent needles, and different size haystacks.

mutt/string.c
mutt/string2.h

index 3b3cd7d76c1b1532c5dc5b34ec11936bc91ced98..046483b34c7fe2f39925508e22935220848fb871 100644 (file)
@@ -1016,3 +1016,47 @@ bool mutt_str_inline_replace(char *buf, size_t buflen, size_t xlen, const char *
 
   return true;
 }
+
+/**
+ * mutt_str_strcasestr - Find a substring within a string without worrying about case
+ * @param haystack String that may or may not contain the substring
+ * @param needle   Substring we're looking for
+ * @retval ptr  Beginning of substring
+ * @retval NULL Substring is not in substring
+ *
+ * This performs a byte-to-byte check so it will return unspecified
+ * results for multibyte locales.
+ */
+const char *mutt_str_strcasestr(const char *haystack, const char *needle)
+{
+  if (!needle)
+    return NULL;
+
+  size_t haystack_len = mutt_str_strlen(haystack);
+  size_t needle_len = mutt_str_strlen(needle);
+
+  // Empty string exists at the front of a string. Check strstr if you don't believe me.
+  if (needle_len == 0)
+    return haystack;
+
+  // Check size conditions. No point wasting CPU cycles.
+  if ((haystack_len == 0) || (haystack_len < needle_len))
+    return NULL;
+
+  // Only check space that needle could fit in.
+  // Conditional has + 1 to handle when the haystack and needle are the same length.
+  for (size_t i = 0; i < (haystack_len - needle_len) + 1; i++)
+  {
+    for (size_t j = 0; j < needle_len; j++)
+    {
+      if (tolower((unsigned char) haystack[i + j]) != tolower((unsigned char) needle[j]))
+        break;
+
+      // If this statement is true, the needle has been found.
+      if (j == (needle_len - 1))
+        return haystack + i;
+    }
+  }
+
+  return NULL;
+}
index 25c19383e02e60664ca6ba74bf4b1c92e5649ee2..557c7673f1acc1f58306ec6a6b3b504c880a4f94 100644 (file)
@@ -85,6 +85,7 @@ const char *mutt_str_rstrnstr(const char *haystack, size_t haystack_length, cons
 char *      mutt_str_skip_email_wsp(const char *s);
 char *      mutt_str_skip_whitespace(char *p);
 int         mutt_str_strcasecmp(const char *a, const char *b);
+const char *mutt_str_strcasestr(const char *haystack, const char *needle);
 char *      mutt_str_strcat(char *buf, size_t buflen, const char *s);
 const char *mutt_str_strchrnul(const char *s, char c);
 int         mutt_str_strcmp(const char *a, const char *b);