| 
							- #include <rtosc/rtosc.h>
 - #include <ctype.h>
 - #include <assert.h>
 - #include <string.h>
 - #include <strings.h>
 - #include <stdlib.h>
 - 
 - 
 - #include <stdio.h>
 - 
 - static bool rtosc_match_number(const char **pattern, const char **msg)
 - {
 -     //Verify both hold digits
 -     if(!isdigit(**pattern) || !isdigit(**msg))
 -         return false;
 - 
 -     //Read in both numeric values
 -     unsigned max = atoi(*pattern);
 -     unsigned val = atoi(*msg);
 - 
 -     ////Advance pointers
 -     while(isdigit(**pattern))++*pattern;
 -     while(isdigit(**msg))++*msg;
 - 
 -     //Match iff msg number is strictly less than pattern
 -     return val < max;
 - }
 - 
 - // pattern = /previous/{A,B,C,D,E}/after
 - //                     ^
 - // message = /previous/C/after
 - //                     ^
 - const char *rtosc_match_options(const char *pattern, const char **msg)
 - {
 -     const char *preserve = *msg;
 -     assert(*pattern == '{');
 -     pattern++;
 - 
 - retry:
 - 
 -     while(1) {
 -         //Check for special characters
 -         if(*pattern == ',' || *pattern == '}') {
 -             goto advance_until_end;
 -         } else if((*pattern == **msg)) { //verbatim compare
 -             if(**msg)
 -                 ++pattern, ++*msg;
 -             else
 -                 goto try_next;
 -         } else
 -             goto try_next;
 -     }
 - 
 - advance_until_end:
 -     while(*pattern && *pattern != '}') pattern++;
 -     if(*pattern == '}')
 -         pattern++;
 -     return pattern;
 - try_next:
 -     *msg = preserve;
 -     while(*pattern && *pattern != '}' && *pattern != ',') pattern++;
 -     if(*pattern == ',') {
 -         pattern++;
 -         goto retry;
 -     }
 - 
 -     return NULL;
 - }
 - 
 - const char *rtosc_match_path(const char *pattern,
 -                              const char *msg, const char** path_end)
 - {
 -     if(!path_end)
 -         path_end = &msg; // writing *path_end = msg later will have no effect
 -     while(1) {
 -         //Check for special characters
 -         if(*pattern == ':' && !*msg)
 -             return *path_end = msg, pattern;
 -         else if(*pattern == '{') {
 -             pattern = rtosc_match_options(pattern, &msg);
 -             if(!pattern)
 -                 return NULL;
 -         } else if(*pattern == '*') {
 -             //advance message and pattern to '/' or ':' and '\0'
 -             while(*pattern && *pattern != '/' && *pattern != ':')
 -                 pattern++;
 -             if(*pattern == '/' || *pattern == ':')
 -                 while(*msg && *msg != '/')
 -                     msg++;
 -         } else if(*pattern == '/' && *msg == '/') {
 -             ++pattern;
 -             ++msg;
 -             if(*pattern == '\0' || *pattern == ':')
 -                 return *path_end = msg, pattern;
 -         } else if(*pattern == '#') {
 -             ++pattern;
 -             if(!rtosc_match_number(&pattern, &msg))
 -                 return NULL;
 -         } else if((*pattern == *msg)) { //verbatim compare
 -             if(*msg)
 -                 ++pattern, ++msg;
 -             else
 -                 return *path_end = msg, pattern;
 -         } else
 -             return NULL;
 -     }
 - }
 - 
 - //Match the arg string or fail
 - static bool rtosc_match_args(const char *pattern, const char *msg)
 - {
 -     //match anything if now arg restriction is present (ie the ':')
 -     if(*pattern++ != ':')
 -         return true;
 - 
 -     const char *arg_str = rtosc_argument_string(msg);
 -     bool      arg_match = *pattern || *pattern == *arg_str;
 - 
 -     while(*pattern && *pattern != ':')
 -         arg_match &= (*pattern++==*arg_str++);
 - 
 -     if(*pattern==':') {
 -         if(arg_match && !*arg_str)
 -             return true;
 -         else
 -             return rtosc_match_args(pattern, msg); //retry
 -     }
 - 
 -     return arg_match;
 - }
 - 
 - bool rtosc_match(const char *pattern,
 -                  const char *msg, const char** path_end)
 - {
 -     const char *arg_pattern = rtosc_match_path(pattern, msg, path_end);
 -     if(!arg_pattern)
 -         return false;
 -     else if(*arg_pattern == ':')
 -         return rtosc_match_args(arg_pattern, msg);
 -     return true;
 - }
 - 
 - 
 - 
 - /*
 -  * Special characters from the specification:
 -  * ' '  space               32
 -  *  #   number sign         35
 -  *  *   asterisk            42
 -  *  ,   comma               44
 -  *  /   forward slash       47
 -  *  ?   question mark       63
 -  *  [   open bracket        91
 -  *  ]   close bracket       93
 -  *  {   open curly brace    123
 -  *  }   close curly brace   125
 -  */
 - 
 - #if 0
 - QUOTE FROM OSC 1.0 SPEC
 - 
 - '?' in the OSC Address Pattern matches any single character
 - '*' in the OSC Address Pattern matches any sequence of zero or more characters
 - A string of characters in square brackets (e.g., "[string]") in the OSC Address Pattern matches any character in the string.
 - Inside square brackets, the minus sign (-) and exclamation point (!) have special meanings:
 -     two characters separated by a minus sign indicate the range of characters between the given two
 - in ASCII collating sequence. (A minus sign at the end of the string has no special meaning.)
 -     An exclamation point at the beginning of a bracketed string negates the sense of the list,
 -     meaning that the list matches any character not in the list.
 - (An exclamation point anywhere besides the first character after the open bracket has no special meaning.)
 -     A comma-separated list of strings enclosed in curly braces (e.g., "{foo,bar}") in the OSC Address Pattern
 -     matches any of the strings in the list.
 - #endif
 - 
 - 
 - 
 - 
 - //for literal string X
 - //for X+?+[]         Y
 - //for Y+single{}     Z
 - //for numeric string N
 - //assume a is of the form X
 - //assume b is a pattern of the form:
 - //*   (1)
 - //Y   (2)
 - //Y*  (3)
 - //*X* (4)
 - //Z   (5)
 - //Z*  (6)
 - //Y#N (7)
 - #define RTOSC_MATCH_ALL             1
 - #define RTOSC_MATCH_CHAR            2
 - #define RTOSC_MATCH_PARTIAL_CHAR    3
 - #define RTOSC_MATCH_SUBSTRING       4
 - #define RTOSC_MATCH_OPTIONS         5
 - #define RTOSC_MATCH_PARTIAL_OPTIONS 6
 - #define RTOSC_MATCH_ENUMERATED      7
 - static bool is_charwise(uint8_t c)
 - {
 -     return c<=0x7f && c != ' ' && c != '#' &&
 -         c != '/' && c != '{' && c != '}';
 - }
 - 
 - int rtosc_subpath_pat_type(const char *pattern)
 - {
 -     int charwise_only = 1;
 -     const char *last_star = strrchr(pattern, '*');
 -     const char *pound = strchr(pattern, '#');
 -     if(!strcmp("*", pattern))
 -         return RTOSC_MATCH_ALL;
 - 
 -     for(const char *p = pattern;*p;++p)
 -         charwise_only &= is_charwise(*p);
 -     if(charwise_only && !last_star)
 -         return RTOSC_MATCH_CHAR;
 -     if(pound)
 -         return RTOSC_MATCH_ENUMERATED;
 - 
 - 
 -     return 2;
 - }
 - 
 - static bool rtosc_match_char(const char **path, const char **pattern)
 - {
 -     //printf("rtosc_match_char('%s','%s')\n", *path, *pattern);
 -     if(**path == **pattern && **path) {
 -         ++*path;
 -         ++*pattern;
 -         return true;
 -     } else if(**pattern == '?' && *path) {
 -         ++*path;
 -         ++*pattern;
 -         return true;
 -     } else if(**pattern == '[') {
 -         bool matched    = false;
 -         bool negation   = false;
 -         char last_range = '\0';
 -         char to_match   = **path;
 -         ++*pattern;
 -         if(**pattern == '!') {
 -             negation = true;
 -             ++*pattern;
 -         }
 -         while(**pattern && **pattern != ']') {
 -             last_range = **pattern;
 -             if(**pattern == to_match) {
 -                 matched = true;
 -             } else if(**pattern == '-') {//range
 -                 ++*pattern;
 -                 char range_high = **pattern;
 -                 if(range_high == ']' || !range_high)
 -                     break;
 -                 if(to_match <= range_high && to_match >= last_range)
 -                     matched = true;
 -             }
 -             ++*pattern;
 -         }
 -         if(**pattern == ']')
 -             ++*pattern;
 -         ++*path;
 -         return negation ^ matched;
 -     }
 -     return false;
 - }
 - 
 - bool rtosc_match_partial(const char *a, const char *b)
 - {
 -     //assume a is of the form X
 -     //assume b is a pattern of the form: (1..6)
 -     //This is done to avoid backtracking of any kind
 -     //This is an OSC serialization library, not a regex
 -     //implementation
 - 
 -     char patternbuf[256];
 -     (void) patternbuf;
 -     int type = rtosc_subpath_pat_type(b);
 - 
 -     if(type == RTOSC_MATCH_ALL)
 -         return true;
 -     else if(type == RTOSC_MATCH_CHAR || type == RTOSC_MATCH_PARTIAL_CHAR) {
 -         while(rtosc_match_char(&a,&b));
 -         if(!*a && !*b)
 -             return true;
 -         else if(*a && *b=='*' && b[1] == '\0')
 -             return true;
 -         else
 -             return false;
 -     } else if(type == 4) {
 -         //extract substring
 -         const char *sub=NULL;
 -         return strstr(a,sub);
 -     } else if(type == RTOSC_MATCH_OPTIONS || type == 6) {
 -         return false;
 -     } else if(type == RTOSC_MATCH_ENUMERATED) {
 -         while(rtosc_match_char(&a,&b));
 -         if(*a && *b=='#' && b[1] != '\0')
 -             return atoi(a) < atoi(b+1);
 -         return false;
 -     } else
 -         return 0;
 -     assert(false);
 - }
 - 
 - int rtosc_matchable_path(const char *pattern)
 - {
 -     (void) pattern;
 -     return 0;
 - 
 - }
 - 
 - int chunk_path(const char *a, int b, const char *c)
 - {
 -     (void) a;
 -     (void) b;
 -     (void) c;
 -     return 0;
 - }
 - void advance_path(const char **a)
 - {
 -     (void) a;
 - }
 - 
 - bool rtosc_match_full_path(const char *pattern, const char *message)
 - {
 -     assert(false && "This API is a WIP");
 -     char subpattern[256];
 -     char submessage[256];
 -     const char *p = pattern;
 -     const char *m = message;
 - 
 - step:
 -     if(*p != *m)
 -         return 0;
 -     if(chunk_path(subpattern, sizeof(subpattern), p))
 -         return 0;
 -     if(chunk_path(submessage, sizeof(submessage), m))
 -         return 0;
 - 
 -     advance_path(&p);
 -     advance_path(&m);
 - 
 -     if(*p == 0 && *m == 0)
 -         return 1;
 -     else
 -         goto step;
 - }
 
 
  |