You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
307 lines
6.9 KiB
307 lines
6.9 KiB
#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; |
|
} |