aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2019-06-13 19:16:00 +0200
committerHanspeter Portner <dev@open-music-kontrollers.ch>2019-06-13 19:16:00 +0200
commitc9bb19d7bf4e5c6dbb81c9b564a331beb26c00f5 (patch)
treea2812e959fa2eb90d3fdfcf7ad64ec1f9d32d139
parentc471d9944c41d03eddc0428bef9eb6cbaa5b701a (diff)
downloadosc.lv2-c9bb19d7bf4e5c6dbb81c9b564a331beb26c00f5.tar.xz
util: implement pattern matching via fnmatch.
-rw-r--r--VERSION2
-rw-r--r--osc.lv2/util.h62
-rw-r--r--test/osc_test.c102
3 files changed, 154 insertions, 12 deletions
diff --git a/VERSION b/VERSION
index 8b06068..841597f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.117
+0.1.119
diff --git a/osc.lv2/util.h b/osc.lv2/util.h
index 36e25d9..0a0be1c 100644
--- a/osc.lv2/util.h
+++ b/osc.lv2/util.h
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
+#include <fnmatch.h>
#include <osc.lv2/osc.h>
@@ -72,16 +73,63 @@ static const char valid_format_chars [] = {
static bool
_lv2_osc_pattern_match(const char *from, const char *name, size_t len)
{
- const char *ast = strpbrk(from, "/*");
- if(ast && (*ast == '*') )
+ size_t nbrace = 0;
+
+ // count opening curly braces
+ for(size_t i = 0; i < len; i++)
+ {
+ if(from[i] == '{')
+ {
+ nbrace++;
+ }
+ }
+
+ // allocate temporary pattern buffer
+ char *pattern = alloca(len + nbrace + 1);
+
+ if(!pattern)
+ {
+ return false;
+ }
+
+ // convert {x,y} to @(x|y) for extended fnmatch
+ if(nbrace)
+ {
+ char *ptr = pattern;
+
+ for(size_t i = 0; i < len; i++)
+ {
+ switch(from[i])
+ {
+ case '{':
+ {
+ *ptr++ = '@';
+ *ptr++ = '(';
+ } break;
+ case ',':
+ {
+ *ptr++ = '|';
+ } break;
+ case '}':
+ {
+ *ptr++ = ')';
+ } break;
+ default:
+ {
+ *ptr++ = from[i];
+ } break;
+ }
+ }
+ }
+ else
{
- len = ast - from;
+ memcpy(pattern, from, len);
}
- //FIXME handle '?[]{}'
- return strncmp(from, name, len) == 0
- ? true
- : false;
+ // terminate pattern string with null terminator
+ pattern[len + nbrace] = '\0';
+
+ return fnmatch(pattern, name, FNM_NOESCAPE | FNM_EXTMATCH) == 0 ? true : false;
}
static void
diff --git a/test/osc_test.c b/test/osc_test.c
index bfa4e65..c58b2e7 100644
--- a/test/osc_test.c
+++ b/test/osc_test.c
@@ -943,7 +943,16 @@ _one(const char *path, const LV2_Atom_Tuple *arguments __attribute__((unused)),
|| !strcmp(path, "/s*/one")
|| !strcmp(path, "/su*/one")
|| !strcmp(path, "/sub*/one")
- || !strcmp(path, "/sub/*"));
+ || !strcmp(path, "/sub/*")
+ || !strcmp(path, "/*sub/one")
+ || !strcmp(path, "/*s*u*b*/one")
+ || !strcmp(path, "/su[ab]/one")
+ || !strcmp(path, "/su[a-b]/[!a-np-z]ne")
+ || !strcmp(path, "/su[a-b]/one")
+ || !strcmp(path, "/s?b/?ne")
+ || !strcmp(path, "/s?*/?ne")
+ || !strcmp(path, "/s?*/*?e")
+ || !strcmp(path, "/sub/{one,two}"));
}
static void
@@ -953,7 +962,9 @@ _two(const char *path, const LV2_Atom_Tuple *arguments __attribute__((unused)),
bool *flag = data;
*flag = true;
- assert(!strcmp(path, "/sub/two") || !strcmp(path, "/sub/*"));
+ assert(!strcmp(path, "/sub/two")
+ || !strcmp(path, "/sub/*")
+ || !strcmp(path, "/sub/{one,two}"));
}
static void
@@ -963,7 +974,8 @@ _foo(const char *path, const LV2_Atom_Tuple *arguments __attribute__((unused)),
bool *flag = data;
*flag = true;
- assert(!strcmp(path, "/foo"));
+ assert(!strcmp(path, "/foo")
+ || !strcmp(path, "/{foo,bar}"));
}
static void
@@ -973,7 +985,8 @@ _bar(const char *path, const LV2_Atom_Tuple *arguments __attribute__((unused)),
bool *flag = data;
*flag = true;
- assert(!strcmp(path, "/bar"));
+ assert(!strcmp(path, "/bar")
+ || !strcmp(path, "/{foo,bar}"));
}
static bool foo_sub_one = false;
@@ -1115,6 +1128,87 @@ _run_test_hooks()
assert(foo_sub_two[1] == false);
}
+ {
+ assert(_run_test_hooks_internal("/*sub/one") == true);
+ assert(foo == false);
+ assert(bar == false);
+ assert(foo_sub_one == true);
+ assert(foo_sub_two[0] == false);
+ assert(foo_sub_two[1] == false);
+ }
+
+ {
+ assert(_run_test_hooks_internal("/*s*u*b*/one") == true);
+ assert(foo == false);
+ assert(bar == false);
+ assert(foo_sub_one == true);
+ assert(foo_sub_two[0] == false);
+ assert(foo_sub_two[1] == false);
+ }
+
+ {
+ assert(_run_test_hooks_internal("/su[ab]/one") == true);
+ assert(foo == false);
+ assert(bar == false);
+ assert(foo_sub_one == true);
+ assert(foo_sub_two[0] == false);
+ assert(foo_sub_two[1] == false);
+ }
+
+ {
+ assert(_run_test_hooks_internal("/su[a-b]/[!a-np-z]ne") == true);
+ assert(foo == false);
+ assert(bar == false);
+ assert(foo_sub_one == true);
+ assert(foo_sub_two[0] == false);
+ assert(foo_sub_two[1] == false);
+ }
+
+ {
+ assert(_run_test_hooks_internal("/su[!a-b]/one") == true);
+ assert(foo == false);
+ assert(bar == false);
+ assert(foo_sub_one == false);
+ assert(foo_sub_two[0] == false);
+ assert(foo_sub_two[1] == false);
+ }
+
+ {
+ assert(_run_test_hooks_internal("/s?b/?ne") == true);
+ assert(foo == false);
+ assert(bar == false);
+ assert(foo_sub_one == true);
+ assert(foo_sub_two[0] == false);
+ assert(foo_sub_two[1] == false);
+ }
+
+ {
+ assert(_run_test_hooks_internal("/s?*/*?e") == true);
+ assert(foo == false);
+ assert(bar == false);
+ assert(foo_sub_one == true);
+ assert(foo_sub_two[0] == false);
+ assert(foo_sub_two[1] == false);
+ }
+
+ {
+ assert(_run_test_hooks_internal("/{foo,bar}") == true);
+ assert(foo == true);
+ assert(bar == true);
+ assert(foo_sub_one == false);
+ assert(foo_sub_two[0] == false);
+ assert(foo_sub_two[1] == false);
+ }
+
+ {
+ assert(_run_test_hooks_internal("/sub/{one,two}") == true);
+ assert(foo == false);
+ assert(bar == false);
+ assert(foo_sub_one == true);
+ assert(foo_sub_two[0] == true);
+ assert(foo_sub_two[1] == true);
+ }
+
return 0;
}