diff options
author | Daniel Carl <danielcarl@gmx.de> | 2014-09-06 14:37:38 +0200 |
---|---|---|
committer | Daniel Carl <danielcarl@gmx.de> | 2014-09-06 22:14:20 +0200 |
commit | 9dd67ade189d799ead56857c01ede3798aa23215 (patch) | |
tree | aeece55af9cd11274bc71447707b4ad3c1d03dee /src/util.c | |
parent | 6e884f6a7b0c42027eb043e6a353ab8616f41cc6 (diff) |
Added curly brace pattern matching for auto commands (#100).
This allows to match pattern with {foo,bar} to match 'foo' or 'bar'. This is
really useful for protocol matching for examaple
http{s,}://{www,mail,maps}.ugly-domain.com/*.
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 147 |
1 files changed, 110 insertions, 37 deletions
@@ -28,6 +28,9 @@ extern VbCore vb; +static int match_list(const char *pattern, const char *subject); + + char *util_get_config_dir(void) { char *path = g_build_filename(g_get_user_config_dir(), PROJECT, NULL); @@ -509,79 +512,149 @@ gboolean util_parse_expansion(const char **input, GString *str, int flags, /** * Compares given string against also given pattern. - * * matches any sequence of characters - * ? matches any single character except of / - * \? matches a ? + * + * * Matches any sequence of characters. + * ? Matches any single character except of '/'. + * {foo,bar} Matches foo or bar - '{', ',' and '}' within this pattern must be + * escaped by '\'. '*' and '?' have no special meaning within the + * curly braces. + * *?{} these chars must always be escaped by '\' to match them literally */ -gboolean util_wildmatch(const char *pattern, const char *string) +gboolean util_wildmatch(const char *pattern, const char *subject) { int i; - char ul, pl; - const char *p, *s; + char sl, pl; - p = pattern; - s = string; - - while (*p) { - switch (*p) { + while (*pattern) { + switch (*pattern) { case '?': - /* match single char except of / or end */ - if (*s == '/' || !*s) { + /* '?' matches a single char except of / and subject end */ + if (*subject == '/' || !*subject) { return false; } break; - case '\\': - /* \ escapes next * or ? char */ - if (*(p + 1) == '*' || *(p + 1) == '?') { - p++; - if (*p != *s) { - return false; - } - } - break; - case '*': /* easiest case - the '*' ist the last char in pattern - this * will always match */ - if (*(p + 1) == '\0') { + if (!pattern[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(s); - while (i >= 0 && !util_wildmatch(p + 1, s + i)) { + i = strlen(subject); + while (i >= 0 && !util_wildmatch(pattern + 1, subject + i)) { i--; } return i >= 0; + case '}': + /* spurious '}' in pattern */ + return false; + + case '{': + /* possible {foo,bar} pattern */ + return match_list(pattern, subject); + + case '\\': + /* '\' escapes next special char */ + if (strchr("*?{}", pattern[1])) { + pattern++; + if (*pattern != *subject) { + return false; + } + } + break; + default: - ul = *s; - if (VB_IS_UPPER(ul)) { - ul += 'a' - 'A'; + /* compare case insensitive */ + sl = *subject; + if (VB_IS_UPPER(sl)) { + sl += 'a' - 'A'; } - pl = *p; + pl = *pattern; if (VB_IS_UPPER(pl)) { pl += 'a' - 'A'; } - if (ul != pl) { + if (sl != pl) { return false; } break; } - p++; - s++; + /* do another loop run with next pattern and subject char */ + pattern++; + subject++; + } + + /* on end of pattern only a also ended subject is a match */ + return !*subject; +} + +static int match_list(const char *pattern, const char *subject) +{ + const char *end, *s; + + /* finde the next none escaped '}' */ + for (end = pattern; *end && *end != '}'; end++) { + /* if escape char - move pointer one additional step */ + if (*end == '\\') { + end++; + } } - /* if there is uri left on pattern end - this is no match */ - if (!*p) { - return !*s; + if (!*end) { + /* unterminated '{' in pattern */ + return false; } - return false; + s = subject; + end++; /* skip over } */ + pattern++; /* skip over { */ + while (true) { + switch (*pattern) { + case ',': + if (util_wildmatch(end, s)) { + return true; + } + s = subject; + pattern++; + break; + + case '}': + return util_wildmatch(end, s); + + case '\\': + if (pattern[1] == ',' || pattern[1] == '}' || pattern[1] == '{') { + pattern += 1; + } + /* fall through */ + + default: + if (*pattern == *s) { + pattern++; + s++; + } else { + /* this item of the list does not match - move forward to + * the next none escaped ',' or '}' */ + s = subject; + while (*pattern != ',' && *pattern != '}') { + /* if escape char is found - skip next char */ + if (*pattern == '\\') { + pattern++; + } + pattern++; + } + /* found ',' skip over it to check the next list item */ + if (*pattern == ',') { + pattern++; + } + } + } + } } + /** * Fills the given list store by matching data of also given src list. */ |