From ef4c14cc9b1121d591e3c88cfb57a1e7b1688900 Mon Sep 17 00:00:00 2001 From: Daniel Carl Date: Mon, 1 Sep 2014 00:06:45 +0200 Subject: [PATCH] Added utility function for wildcard matching. --- src/autocmd.c | 14 ++++++--- src/util.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++ src/util.h | 1 + tests/test-util.c | 51 +++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 4 deletions(-) diff --git a/src/autocmd.c b/src/autocmd.c index 9564a54..f08e2f9 100644 --- a/src/autocmd.c +++ b/src/autocmd.c @@ -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); } } diff --git a/src/util.c b/src/util.c index d07909b..6a7d3b4 100644 --- a/src/util.c +++ b/src/util.c @@ -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. */ diff --git a/src/util.h b/src/util.h index 5c7b4d4..ad6a770 100644 --- a/src/util.h +++ b/src/util.h @@ -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 */ diff --git a/tests/test-util.c b/tests/test-util.c index 6dc26b4..cd80420 100644 --- a/tests/test-util.c +++ b/tests/test-util.c @@ -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(); } -- 2.20.1