Ibiltari Nora / OSC
Revision:
14:2148b54dfdbf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OSCMatch.c	Mon Dec 10 16:51:59 2018 +0100
@@ -0,0 +1,307 @@
+#define OSC_MATCH_ENABLE_2STARS 1
+#define OSC_MATCH_ENABLE_NSTARS 1
+/*
+ Written by John MacCallum, The Center for New Music and Audio Technologies,
+ University of California, Berkeley.  Copyright (c) 2009, The Regents of
+ the University of California (Regents).
+ Permission to use, copy, modify, distribute, and distribute modified versions
+ of this software and its documentation without fee and without a signed
+ licensing agreement, is hereby granted, provided that the above copyright
+ notice, this paragraph and the following two paragraphs appear in all copies,
+ modifications, and distributions.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
+ OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
+ BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
+ HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
+ MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+#include <string.h>
+#include "OSCMatch.h"
+
+static int osc_match_star(const char *pattern, const char *address);
+static int osc_match_star_r(const char *pattern, const char *address);
+static int osc_match_single_char(const char *pattern, const char *address);
+static int osc_match_bracket(const char *pattern, const char *address);
+static int osc_match_curly_brace(const char *pattern, const char *address);
+
+int osc_match(const char *pattern, const char *address, int *pattern_offset, int *address_offset)
+{
+	if(!strcmp(pattern, address)){
+		*pattern_offset = strlen(pattern);
+		*address_offset = strlen(address);
+		return OSC_MATCH_ADDRESS_COMPLETE | OSC_MATCH_PATTERN_COMPLETE;
+	}
+
+	const char *pattern_start;
+	const char *address_start;
+
+	pattern_start = pattern;
+	address_start = address;
+
+	*pattern_offset = 0;
+	*address_offset = 0;
+
+	while(*address != '\0' && *pattern != '\0'){
+		if(*pattern == '*'){
+			if(!osc_match_star(pattern, address)){
+				return 0;
+			}
+			while(*pattern != '/' && *pattern != '\0'){
+				pattern++;
+			}
+			while(*address != '/' && *address != '\0'){
+				address++;
+			}
+		}else if(*address == '*'){
+			while(*pattern != '/' && *pattern != '\0'){
+				pattern++;
+			}
+			while(*address != '/' && *address != '\0'){
+				address++;
+			}
+		}else{
+			int n = 0;
+			if(!(n = osc_match_single_char(pattern, address))){
+				return 0;
+			}
+			if(*pattern == '['){
+				while(*pattern != ']'){
+					pattern++;
+				}
+				pattern++;
+				address++;
+			}else if(*pattern == '{'){
+				while(*pattern != '}'){
+					pattern++;
+				}
+				pattern++;
+				address += n;
+			}else{
+				pattern++;
+				address++;
+			}
+		}
+	}
+
+	*pattern_offset = pattern - pattern_start;
+	*address_offset = address - address_start;
+
+	int r = 0;
+
+	if(*address == '\0') {
+		r |= OSC_MATCH_ADDRESS_COMPLETE;
+	}
+
+	if(*pattern == '\0') {
+		r |= OSC_MATCH_PATTERN_COMPLETE;
+	}
+
+	return r;
+}
+
+static int osc_match_star(const char *pattern, const char *address)
+{
+	const char *address_start = address;
+	const char *pattern_start = pattern;
+	int num_stars = 0;
+	if(*address == '\0') { return 0; }
+	while(*address != '/' && *address != '\0'){
+		address++;
+	}
+	while(*pattern != '/' && *pattern != '\0'){
+		if(*pattern == '*'){
+			num_stars++;
+		}
+		pattern++;
+	}
+	pattern--;
+	address--;
+	switch(num_stars){
+		case 1:
+		{
+			const char *pp = pattern, *aa = address;
+			while(*pp != '*'){
+				if(!(osc_match_single_char(pp, aa))){
+					return 0;
+				}
+				if(*pp == ']' || *pp == '}'){
+					while(*pp != '[' && *pp != '{'){
+						pp--;
+					}
+				}
+				pp--;
+				aa--;
+			}
+		}
+			break;
+		case 2:
+#if (OSC_MATCH_ENABLE_2STARS == 1)
+		{
+			const char *pp = pattern, *aa = address;
+			while(*pp != '*'){
+				if(!(osc_match_single_char(pp, aa))){
+					return 0;
+				}
+				if(*pp == ']' || *pp == '}'){
+					while(*pp != '[' && *pp != '{'){
+						pp--;
+					}
+				}
+				pp--;
+				aa--;
+			}
+			aa++; // we want to start one character forward to allow the star to match nothing
+			const char *star2 = pp;
+			const char *test = aa;
+			int i = 0;
+			while(test > address_start){
+				pp = star2 - 1;
+				aa = test - 1;
+				i++;
+				while(*pp != '*'){
+					if(!osc_match_single_char(pp, aa)){
+						break;
+					}
+					if(*pp == ']' || *pp == '}'){
+						while(*pp != '[' && *pp != '{'){
+							pp--;
+						}
+					}
+					pp--;
+					aa--;
+				}
+				if(pp == pattern_start){
+					return 1;
+				}
+				test--;
+			}
+			return 0;
+		}
+			break;
+#else
+			return 0;
+#endif
+		default:
+#if (OSC_MATCH_ENABLE_NSTARS == 1)
+			return osc_match_star_r(pattern_start, address_start);
+			break;
+#else
+			return 0;
+#endif
+	}
+	return 1;
+}
+
+#if (OSC_MATCH_ENABLE_NSTARS == 1)
+static int osc_match_star_r(const char *pattern, const char *address)
+{
+	if(*address == '/' || *address == '\0'){
+		if(*pattern == '/' || *pattern == '\0' || (*pattern == '*' && ((*(pattern + 1) == '/') || *(pattern + 1) == '\0'))){
+			return 1;
+		}else{
+			return 0;
+		}
+	}
+	if(*pattern == '*'){
+		if(osc_match_star_r(pattern + 1, address)){
+			return 1;
+		}else{
+			return osc_match_star_r(pattern, address + 1);
+		}
+	}else{
+		if(!osc_match_single_char(pattern, address)){
+			return 0;
+		}
+		if(*pattern == '[' || *pattern == '{'){
+			while(*pattern != ']' && *pattern != '}'){
+				pattern++;
+			}
+		}
+		return osc_match_star_r(pattern + 1, address + 1);
+	}
+}
+#endif
+
+static int osc_match_single_char(const char *pattern, const char *address)
+{
+	switch(*pattern){
+		case '[':
+			return osc_match_bracket(pattern, address);
+		case ']':
+			while(*pattern != '['){
+				pattern--;
+			}
+			return osc_match_bracket(pattern, address);
+		case '{':
+			return osc_match_curly_brace(pattern, address);
+		case '}':
+			while(*pattern != '{'){
+				pattern--;
+			}
+			return osc_match_curly_brace(pattern, address);
+		case '?':
+			return 1;
+		default:
+			if(*pattern == *address){
+				return 1;
+			}else{
+				return 0;
+			}
+	}
+	return 0;
+}
+
+static int osc_match_bracket(const char *pattern, const char *address)
+{
+	pattern++;
+	int val = 1;
+	if(*pattern == '!'){
+		pattern++;
+		val = 0;
+	}
+	int matched = !val;
+	while(*pattern != ']' && *pattern != '\0'){
+		// the character we're on now is the beginning of a range
+		if(*(pattern + 1) == '-'){
+			if(*address >= *pattern && *address <= *(pattern + 2)){
+				matched = val;
+				break;
+			}else{
+				pattern += 3;
+			}
+		}else{
+			// just test the character
+			if(*pattern == *address){
+				matched = val;
+				break;
+			}
+			pattern++;
+		}
+	}
+	return matched;
+}
+
+static int osc_match_curly_brace(const char *pattern, const char *address)
+{
+	pattern++;
+	const char *ptr = pattern;
+	while(*ptr != '}' && *ptr != '\0' && *ptr != '/'){
+		while(*ptr != '}' && *ptr != '\0' && *ptr != '/' && *ptr != ','){
+			ptr++;
+		}
+		int n = ptr - pattern;
+		if(!strncmp(pattern, address, n)){
+			return n;
+		}else{
+			ptr++;
+			pattern = ptr;
+		}
+	}
+	return 0;
+}