Added utility function for wildcard matching.
authorDaniel Carl <danielcarl@gmx.de>
Sun, 31 Aug 2014 22:06:45 +0000 (00:06 +0200)
committerDaniel Carl <danielcarl@gmx.de>
Sun, 31 Aug 2014 22:41:52 +0000 (00:41 +0200)
src/autocmd.c
src/util.c
src/util.h
tests/test-util.c

index 9564a54..f08e2f9 100644 (file)
@@ -22,6 +22,7 @@
 #include "autocmd.h"
 #include "ascii.h"
 #include "ex.h"
+#include "util.h"
 
 typedef struct {
     guint bits;
@@ -166,8 +167,9 @@ gboolean autocmd_add(char *name, gboolean delete)
             if (!(cmd->bits & bits)) {
                 continue;
             }
-            /* skip it pattern does not match - '*' matches everithing */
-            if (strcmp(cmd->pattern, "*") && strcmp(cmd->pattern, pattern)) {
+            /* skip if pattern does not match - we check the pattern against
+             * another pattern */
+            if (!util_wildmatch(pattern, cmd->pattern)) {
                 continue;
             }
             /* remove the bits from the item */
@@ -217,9 +219,13 @@ gboolean autocmd_run(const char *group, AuEvent event, const char *uri)
             if (!(bits & cmd->bits)) {
                 continue;
             }
-            /* TODO skip if pattern does not match */
+            /* check pattern only if uri was given */
+            /* skip if pattern does not match */
+            if (uri && !util_wildmatch(cmd->pattern, uri)) {
+                continue;
+            }
             /* run the command */
-            /* TODO shoult hte result be tested for RESULT_COMPLETE? */
+            /* TODO shoult the result be tested for RESULT_COMPLETE? */
             ex_run_string(cmd->excmd);
         }
     }
index d07909b..6a7d3b4 100644 (file)
@@ -507,6 +507,78 @@ gboolean util_parse_expansion(const char **input, GString *str, int flags,
     return expanded;
 }
 
+/**
+ * Compares given string against also given pattern.
+ * *    matches any sequence of characters
+ * ?    matches any single character except of /
+ * \?   matches a ?
+ * .    matches a .
+ * ~    matches a ~
+ */
+gboolean util_wildmatch(const char *pattern, const char *string)
+{
+    int i;
+    char ul, pl;
+    const char *p, *s;
+
+    p = pattern;
+    s = string;
+
+    while (*p) {
+        switch (*p) {
+            case '?':
+                /* match single char except of / or end */
+                if (*s == '/' || !*s) {
+                    return false;
+                }
+                break;
+
+            case '\\':
+                /* \ escapes next * or ? char */
+                if (*(p + 1) == '*' || *(p + 1) == '?') {
+                    p++;
+                    if (*p != *s) {
+                        return false;
+                    }
+                }
+                break;
+
+            case '*':
+                /* Try to match as much as possible. Try to match the complete
+                 * uri, if that fails move forward in uri and chack for a
+                 * match. */
+                i = strlen(s);
+                while (i >= 0 && !util_wildmatch(p + 1, s + i)) {
+                    i--;
+                }
+                return i >= 0;
+
+            default:
+                ul = *s;
+                if (VB_IS_UPPER(ul)) {
+                    ul += 'a' - 'A';
+                }
+                pl = *p;
+                if (VB_IS_UPPER(pl)) {
+                    pl += 'a' - 'A';
+                }
+                if (ul != pl) {
+                    return false;
+                }
+                break;
+        }
+        p++;
+        s++;
+    }
+
+    /* if there is uri left on pattern end - this is no match */
+    if (!*p) {
+        return !*s;
+    }
+
+    return false;
+}
+
 /**
  * Fills the given list store by matching data of also given src list.
  */
index 5c7b4d4..ad6a770 100644 (file)
@@ -49,6 +49,7 @@ char *util_build_path(const char *path, const char *dir);
 char *util_expand(const char *src, int expflags);
 gboolean util_parse_expansion(const char **input, GString *str, int flags,
     const char *quoteable);
+gboolean util_wildmatch(const char *pattern, const char *string);
 gboolean util_fill_completion(GtkListStore *store, const char *input, GList *src);
 
 #endif /* end of include guard: _UTIL_H */
index 6dc26b4..cd80420 100644 (file)
@@ -137,6 +137,54 @@ static void test_str_replace(void)
     g_free(value);
 }
 
+static void test_wildmatch_simple(void)
+{
+    g_assert_true(util_wildmatch("", ""));
+    g_assert_true(util_wildmatch("w", "w"));
+    g_assert_true(util_wildmatch(".", "."));
+    g_assert_true(util_wildmatch("~", "~"));
+    g_assert_true(util_wildmatch("wildmatch", "WildMatch"));
+    g_assert_true(util_wildmatch("wild\\match", "wild\\match"));
+
+    /* no special meaning of . and ~ in pattern */
+    g_assert_false(util_wildmatch(".", "w"));
+    g_assert_false(util_wildmatch("~", "w"));
+    g_assert_false(util_wildmatch("wild", "wild "));
+    g_assert_false(util_wildmatch("wild", " wild"));
+    g_assert_false(util_wildmatch("wild", "\\ wild"));
+    g_assert_false(util_wildmatch("wild", "\\wild"));
+    g_assert_false(util_wildmatch("wild", "wild\\"));
+    g_assert_false(util_wildmatch("wild\\1", "wild\\2"));
+}
+
+static void test_wildmatch_questionmark(void)
+{
+    g_assert_true(util_wildmatch("wild?atch", "wildmatch"));
+    g_assert_true(util_wildmatch("wild?atch", "wildBatch"));
+    g_assert_true(util_wildmatch("wild?atch", "wild?atch"));
+    g_assert_true(util_wildmatch("?ild?atch", "MildBatch"));
+    g_assert_true(util_wildmatch("foo\\?bar", "foo?bar"));
+    g_assert_true(util_wildmatch("???", "foo"));
+    g_assert_true(util_wildmatch("???", "bar"));
+
+    g_assert_false(util_wildmatch("foo\\?bar", "foorbar"));
+    g_assert_false(util_wildmatch("?", ""));
+}
+
+static void test_wildmatch_wildcard(void)
+{
+    g_assert_true(util_wildmatch("*", ""));
+    g_assert_true(util_wildmatch("*", "Match as much as possible"));
+    g_assert_true(util_wildmatch("*match", "prefix match"));
+    g_assert_true(util_wildmatch("match*", "match suffix"));
+    g_assert_true(util_wildmatch("match*", "match*"));
+    g_assert_true(util_wildmatch("match\\*", "match*"));
+    g_assert_true(util_wildmatch("do * match", "do a infix match"));
+    g_assert_true(util_wildmatch("*://*.io/*", "http://fanglingsu.github.io/vimb/"));
+
+    g_assert_false(util_wildmatch("match\\*", "match fail"));
+}
+
 int main(int argc, char *argv[])
 {
     g_test_init(&argc, &argv, NULL);
@@ -148,6 +196,9 @@ int main(int argc, char *argv[])
     g_test_add_func("/test-util/expand-spacial", test_expand_speacial);
     g_test_add_func("/test-util/strcasestr", test_strcasestr);
     g_test_add_func("/test-util/str_replace", test_str_replace);
+    g_test_add_func("/test-util/wildmatch-simple", test_wildmatch_simple);
+    g_test_add_func("/test-util/wildmatch-questionmark", test_wildmatch_questionmark);
+    g_test_add_func("/test-util/wildmatch-wildcard", test_wildmatch_wildcard);
 
     return g_test_run();
 }