static guint get_event_bits(const char *name);
static void rebuild_used_bits(void);
static char *get_next_word(char **line);
-static gboolean wildmatch(char *patterns, const char *uri);
static AuGroup *new_group(const char *name);
static void free_group(AuGroup *group);
static AutoCmd *new_autocmd(const char *excmd, const char *pattern);
}
/* skip if pattern does not match - we check the pattern against
* another pattern */
- if (!wildmatch(pattern, cmd->pattern)) {
+ if (!util_wildmatch_multi(pattern, cmd->pattern)) {
continue;
}
/* remove the bits from the item */
}
/* check pattern only if uri was given */
/* skip if pattern does not match */
- if (uri && !wildmatch(cmd->pattern, uri)) {
+ if (uri && !util_wildmatch_multi(cmd->pattern, uri)) {
continue;
}
/* run the command */
return word;
}
-/**
- * Check if given uri matches one of the patterns given as comma separated
- * string.
- */
-static gboolean wildmatch(char *patterns, const char *uri)
-{
- char *cur, *start;
- gboolean matched;
-
- for (cur = start = patterns; *cur; cur++) {
- /* iterate through the patterns until the next ',' */
- if (*cur == ',') {
- *cur = '\0';
- matched = util_wildmatch(start, uri);
- *cur = ',';
-
- /* return if the first match is found */
- if (matched) {
- return true;
- }
-
- /* set the start right after the ',' */
- start = cur + 1;
- }
- }
-
- /* still no match found - check the last pattern */
- return util_wildmatch(start, uri);
-}
-
static AuGroup *new_group(const char *name)
{
AuGroup *new = g_slice_new(AuGroup);
extern VbCore vb;
-static int match_list(const char *pattern, const char *subject);
+static gboolean match(const char *pattern, int patlen, const char *subject);
+static gboolean match_list(const char *pattern, int patlen, const char *subject);
char *util_get_config_dir(void)
return expanded;
}
+/**
+ * Like util_wildmatch, but allow to use a list of patterns,
+ */
+gboolean util_wildmatch_multi(const char *pattern, const char *subject)
+{
+ const char *end;
+ int braces, patlen;
+
+ /* loop through all pattens */
+ for (; *pattern; pattern = (*end == ',' ? end + 1 : end)) {
+ /* find end of the pattern - but be careful with comma in curly braces */
+ braces = 0;
+ for (end = pattern; *end && (*end != ',' || braces || *(end - 1) == '\\'); ++end) {
+ if (*end == '{') {
+ braces++;
+ } else if (*end == '}') {
+ braces--;
+ }
+ }
+ /* ignore single comma */
+ if (*pattern == *end) {
+ continue;
+ }
+ /* calculate the length of the pattern */
+ patlen = end - pattern;
+
+ /* if this pattern matches - return */
+ if (match(pattern, patlen, subject)) {
+ return true;
+ }
+ }
+
+ /* empty pattern matches only on empty subject */
+ return !*subject;
+}
+
/**
* Compares given string against also given pattern.
*
* *?{} these chars must always be escaped by '\' to match them literally
*/
gboolean util_wildmatch(const char *pattern, const char *subject)
+{
+ return match(pattern, strlen(pattern), subject);
+}
+
+/**
+ * Compares given subject string against the given pattern.
+ * The pattern needs not to bee NUL terminated.
+ */
+static gboolean match(const char *pattern, int patlen, const char *subject)
{
int i;
char sl, pl;
- while (*pattern) {
+ while (patlen > 0) {
switch (*pattern) {
case '?':
/* '?' matches a single char except of / and subject end */
case '*':
/* easiest case - the '*' ist the last char in pattern - this
* will always match */
- if (!pattern[1]) {
+ if (patlen == 1) {
return true;
}
/* Try to match as much as possible. Try to match the complete
* uri, if that fails move forward in uri and check for a
* match. */
i = strlen(subject);
- while (i >= 0 && !util_wildmatch(pattern + 1, subject + i)) {
+ while (i >= 0 && !match(pattern + 1, patlen - 1, subject + i)) {
i--;
}
return i >= 0;
case '{':
/* possible {foo,bar} pattern */
- return match_list(pattern, subject);
+ return match_list(pattern, patlen, subject);
case '\\':
/* '\' escapes next special char */
if (strchr("*?{}", pattern[1])) {
pattern++;
+ patlen--;
if (*pattern != *subject) {
return false;
}
}
/* do another loop run with next pattern and subject char */
pattern++;
+ patlen--;
subject++;
}
return !*subject;
}
-static int match_list(const char *pattern, const char *subject)
+/**
+ * Matches pattern starting with '{'.
+ * This function can process also on none null terminated pattern.
+ */
+static gboolean match_list(const char *pattern, int patlen, const char *subject)
{
+ int endlen;
const char *end, *s;
+ end = pattern;
+ endlen = patlen;
/* finde the next none escaped '}' */
- for (end = pattern; *end && *end != '}'; end++) {
+ while (endlen > 0 && *end != '}') {
/* if escape char - move pointer one additional step */
if (*end == '\\') {
end++;
+ endlen--;
}
+ end++;
+ endlen--;
}
if (!*end) {
s = subject;
end++; /* skip over } */
+ endlen--;
pattern++; /* skip over { */
+ patlen--;
while (true) {
switch (*pattern) {
case ',':
- if (util_wildmatch(end, s)) {
+ if (match(end, endlen, s)) {
return true;
}
s = subject;
pattern++;
+ patlen--;
break;
case '}':
- return util_wildmatch(end, s);
+ return match(end, endlen, s);
case '\\':
if (pattern[1] == ',' || pattern[1] == '}' || pattern[1] == '{') {
- pattern += 1;
+ pattern++;
+ patlen--;
}
/* fall through */
default:
if (*pattern == *s) {
pattern++;
+ patlen--;
s++;
} else {
/* this item of the list does not match - move forward to
/* if escape char is found - skip next char */
if (*pattern == '\\') {
pattern++;
+ patlen--;
}
pattern++;
+ patlen--;
}
/* found ',' skip over it to check the next list item */
if (*pattern == ',') {
pattern++;
+ patlen--;
}
}
}
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_multi(const char *pattern, const char *subject);
gboolean util_wildmatch(const char *pattern, const char *string);
gboolean util_fill_completion(GtkListStore *store, const char *input, GList *src);
g_assert_true(util_wildmatch("http{s,}://{fanglingsu.,}github.{io,com}/*vimb/", "https://github.com/fanglingsu/vimb/"));
}
+static void test_wildmatch_multi(void)
+{
+ /* check if sinlge pattern matching works */
+ g_assert_true(util_wildmatch_multi("", ""));
+ g_assert_true(util_wildmatch_multi("single", "single"));
+ g_assert_true(util_wildmatch_multi("s*e", "single"));
+
+ g_assert_true(util_wildmatch_multi("foo,b{a,o,}r,ba?", "foo"));
+ g_assert_true(util_wildmatch_multi("foo,b{a,o,}r,ba?", "bar"));
+ g_assert_true(util_wildmatch_multi("foo,b{a,o,}r,ba?", "bor"));
+ g_assert_true(util_wildmatch_multi("foo,b{a,o,}r,ba?", "br"));
+ g_assert_true(util_wildmatch_multi("foo,b{a,o,}r,ba?", "baz"));
+ g_assert_true(util_wildmatch_multi("foo,b{a,o,}r,ba?", "bat"));
+
+ g_assert_false(util_wildmatch_multi("foo,b{a,o,}r,ba?", "foo,"));
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/test-util/wildmatch-wildcard", test_wildmatch_wildcard);
g_test_add_func("/test-util/wildmatch-curlybraces", test_wildmatch_curlybraces);
g_test_add_func("/test-util/wildmatch-complete", test_wildmatch_complete);
+ g_test_add_func("/test-util/wildmatch-multi", test_wildmatch_multi);
return g_test_run();
}