Audio plugin host https://kx.studio/carla
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.

287 lines
7.5KB

  1. #include <rtosc/rtosc.h>
  2. #include <ctype.h>
  3. #include <assert.h>
  4. #include <string.h>
  5. #include <strings.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. static bool rtosc_match_number(const char **pattern, const char **msg)
  9. {
  10. //Verify both hold digits
  11. if(!isdigit(**pattern) || !isdigit(**msg))
  12. return false;
  13. //Read in both numeric values
  14. unsigned max = atoi(*pattern);
  15. unsigned val = atoi(*msg);
  16. ////Advance pointers
  17. while(isdigit(**pattern))++*pattern;
  18. while(isdigit(**msg))++*msg;
  19. //Match iff msg number is strictly less than pattern
  20. return val < max;
  21. }
  22. const char *rtosc_match_path(const char *pattern, const char *msg)
  23. {
  24. while(1) {
  25. //Check for special characters
  26. if(*pattern == ':' && !*msg)
  27. return pattern;
  28. else if(*pattern == '/' && *msg == '/')
  29. return ++pattern;
  30. else if(*pattern == '#') {
  31. ++pattern;
  32. if(!rtosc_match_number(&pattern, &msg))
  33. return NULL;
  34. } else if((*pattern == *msg)) { //verbatim compare
  35. if(*msg)
  36. ++pattern, ++msg;
  37. else
  38. return pattern;
  39. } else
  40. return NULL;
  41. }
  42. }
  43. //Match the arg string or fail
  44. static bool rtosc_match_args(const char *pattern, const char *msg)
  45. {
  46. //match anything if now arg restriction is present (ie the ':')
  47. if(*pattern++ != ':')
  48. return true;
  49. const char *arg_str = rtosc_argument_string(msg);
  50. bool arg_match = *pattern || *pattern == *arg_str;
  51. while(*pattern && *pattern != ':')
  52. arg_match &= (*pattern++==*arg_str++);
  53. if(*pattern==':') {
  54. if(arg_match && !*arg_str)
  55. return true;
  56. else
  57. return rtosc_match_args(pattern, msg); //retry
  58. }
  59. return arg_match;
  60. }
  61. bool rtosc_match(const char *pattern, const char *msg)
  62. {
  63. const char *arg_pattern = rtosc_match_path(pattern, msg);
  64. if(!arg_pattern)
  65. return false;
  66. else if(*arg_pattern == ':')
  67. return rtosc_match_args(arg_pattern, msg);
  68. return true;
  69. }
  70. /*
  71. * Special characters from the specification:
  72. * ' ' space 32
  73. * # number sign 35
  74. * * asterisk 42
  75. * , comma 44
  76. * / forward slash 47
  77. * ? question mark 63
  78. * [ open bracket 91
  79. * ] close bracket 93
  80. * { open curly brace 123
  81. * } close curly brace 125
  82. */
  83. #if 0
  84. QUOTE FROM OSC 1.0 SPEC
  85. '?' in the OSC Address Pattern matches any single character
  86. '*' in the OSC Address Pattern matches any sequence of zero or more characters
  87. A string of characters in square brackets (e.g., "[string]") in the OSC Address Pattern matches any character in the string.
  88. Inside square brackets, the minus sign (-) and exclamation point (!) have special meanings:
  89. two characters separated by a minus sign indicate the range of characters between the given two
  90. in ASCII collating sequence. (A minus sign at the end of the string has no special meaning.)
  91. An exclamation point at the beginning of a bracketed string negates the sense of the list,
  92. meaning that the list matches any character not in the list.
  93. (An exclamation point anywhere besides the first character after the open bracket has no special meaning.)
  94. A comma-separated list of strings enclosed in curly braces (e.g., "{foo,bar}") in the OSC Address Pattern
  95. matches any of the strings in the list.
  96. #endif
  97. //for literal string X
  98. //for X+?+[] Y
  99. //for Y+single{} Z
  100. //for numeric string N
  101. //assume a is of the form X
  102. //assume b is a pattern of the form:
  103. //* (1)
  104. //Y (2)
  105. //Y* (3)
  106. //*X* (4)
  107. //Z (5)
  108. //Z* (6)
  109. //Y#N (7)
  110. #define RTOSC_MATCH_ALL 1
  111. #define RTOSC_MATCH_CHAR 2
  112. #define RTOSC_MATCH_PARTIAL_CHAR 3
  113. #define RTOSC_MATCH_SUBSTRING 4
  114. #define RTOSC_MATCH_OPTIONS 5
  115. #define RTOSC_MATCH_PARTIAL_OPTIONS 6
  116. #define RTOSC_MATCH_ENUMERATED 7
  117. static bool is_charwise(char c)
  118. {
  119. return (c>=0 && c<=0x7f) && c != ' ' && c != '#' &&
  120. c != '/' && c != '{' && c != '}';
  121. }
  122. int rtosc_subpath_pat_type(const char *pattern)
  123. {
  124. int charwise_only = 1;
  125. const char *last_star = rindex(pattern, '*');
  126. const char *pound = index(pattern, '#');
  127. if(!strcmp("*", pattern))
  128. return RTOSC_MATCH_ALL;
  129. for(const char *p = pattern;*p;++p)
  130. charwise_only &= is_charwise(*p);
  131. if(charwise_only && !last_star)
  132. return RTOSC_MATCH_CHAR;
  133. if(pound)
  134. return RTOSC_MATCH_ENUMERATED;
  135. return 2;
  136. }
  137. static bool rtosc_match_char(const char **path, const char **pattern)
  138. {
  139. //printf("rtosc_match_char('%s','%s')\n", *path, *pattern);
  140. if(**path == **pattern && **path) {
  141. ++*path;
  142. ++*pattern;
  143. return true;
  144. } else if(**pattern == '?' && *path) {
  145. ++*path;
  146. ++*pattern;
  147. return true;
  148. } else if(**pattern == '[') {
  149. bool matched = false;
  150. bool negation = false;
  151. char last_range = '\0';
  152. char to_match = **path;
  153. ++*pattern;
  154. if(**pattern == '!') {
  155. negation = true;
  156. ++*pattern;
  157. }
  158. while(**pattern && **pattern != ']') {
  159. last_range = **pattern;
  160. if(**pattern == to_match) {
  161. matched = true;
  162. } else if(**pattern == '-') {//range
  163. ++*pattern;
  164. char range_high = **pattern;
  165. if(range_high == ']' || !range_high)
  166. break;
  167. if(to_match <= range_high && to_match >= last_range)
  168. matched = true;
  169. }
  170. ++*pattern;
  171. }
  172. if(**pattern == ']')
  173. ++*pattern;
  174. ++*path;
  175. return negation ^ matched;
  176. }
  177. return false;
  178. }
  179. bool rtosc_match_partial(const char *a, const char *b)
  180. {
  181. //assume a is of the form X
  182. //assume b is a pattern of the form: (1..6)
  183. //This is done to avoid backtracking of any kind
  184. //This is an OSC serialization library, not a regex
  185. //implementation
  186. char patternbuf[256];
  187. (void) patternbuf;
  188. int type = rtosc_subpath_pat_type(b);
  189. if(type == RTOSC_MATCH_ALL)
  190. return true;
  191. else if(type == RTOSC_MATCH_CHAR || type == RTOSC_MATCH_PARTIAL_CHAR) {
  192. while(rtosc_match_char(&a,&b));
  193. if(!*a && !*b)
  194. return true;
  195. else if(*a && *b=='*' && b[1] == '\0')
  196. return true;
  197. else
  198. return false;
  199. } else if(type == 4) {
  200. //extract substring
  201. const char *sub=NULL;
  202. return strstr(a,sub);
  203. } else if(type == RTOSC_MATCH_OPTIONS || type == 6) {
  204. } else if(type == RTOSC_MATCH_ENUMERATED) {
  205. while(rtosc_match_char(&a,&b));
  206. if(*a && *b=='#' && b[1] != '\0')
  207. return atoi(a) < atoi(b+1);
  208. return false;
  209. } else
  210. return 0;
  211. assert(false);
  212. }
  213. int rtosc_matchable_path(const char *pattern)
  214. {
  215. (void) pattern;
  216. return 0;
  217. }
  218. int chunk_path(const char *a, int b, const char *c)
  219. {
  220. (void) a;
  221. (void) b;
  222. (void) c;
  223. return 0;
  224. }
  225. void advance_path(const char **a)
  226. {
  227. (void) a;
  228. }
  229. bool rtosc_match_full_path(const char *pattern, const char *message)
  230. {
  231. assert(false && "This API is a WIP");
  232. char subpattern[256];
  233. char submessage[256];
  234. const char *p = pattern;
  235. const char *m = message;
  236. step:
  237. if(*p != *m)
  238. return 0;
  239. if(chunk_path(subpattern, sizeof(subpattern), p))
  240. return 0;
  241. if(chunk_path(submessage, sizeof(submessage), m))
  242. return 0;
  243. advance_path(&p);
  244. advance_path(&m);
  245. if(*p == 0 && *m == 0)
  246. return 1;
  247. else
  248. goto step;
  249. }