summaryrefslogtreecommitdiff
path: root/src/util.c
diff options
context:
space:
mode:
authorDaniel Carl <danielcarl@gmx.de>2014-09-06 14:37:38 +0200
committerDaniel Carl <danielcarl@gmx.de>2014-09-06 22:14:20 +0200
commit9dd67ade189d799ead56857c01ede3798aa23215 (patch)
treeaeece55af9cd11274bc71447707b4ad3c1d03dee /src/util.c
parent6e884f6a7b0c42027eb043e6a353ab8616f41cc6 (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.c147
1 files changed, 110 insertions, 37 deletions
diff --git a/src/util.c b/src/util.c
index 1084482..7101bca 100644
--- a/src/util.c
+++ b/src/util.c
@@ -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.
*/