601 lines
16 KiB
C
601 lines
16 KiB
C
|
/*
|
|||
|
Written by Adrian Freed, The Center for New Music and Audio Technologies,
|
|||
|
University of California, Berkeley. Copyright (c) 1992,93,94,95,96,97,98,99,2000,01,02,03,04
|
|||
|
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.
|
|||
|
|
|||
|
|
|||
|
The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
|
|||
|
*/
|
|||
|
|
|||
|
/* OSC-route.c
|
|||
|
Max object for OSC-style dispatching
|
|||
|
|
|||
|
To-do:
|
|||
|
|
|||
|
Match a pattern against a pattern?
|
|||
|
Declare outlet types / distinguish leaf nodes from other children
|
|||
|
More sophisticated (2-pass?) allmessages scheme
|
|||
|
set message?
|
|||
|
|
|||
|
|
|||
|
pd
|
|||
|
-------------
|
|||
|
-- tweaks for Win32 www.zeggz.com/raf 13-April-2002
|
|||
|
|
|||
|
|
|||
|
*/
|
|||
|
|
|||
|
#ifdef WIN32
|
|||
|
#include <stdlib.h>
|
|||
|
#include <string.h>
|
|||
|
#endif
|
|||
|
#ifdef __APPLE__
|
|||
|
#include <stdio.h>
|
|||
|
#endif
|
|||
|
#ifdef UNIX
|
|||
|
#include <stdio.h>
|
|||
|
#endif
|
|||
|
|
|||
|
/* structure definition of your object */
|
|||
|
|
|||
|
#define MAX_NUM 20
|
|||
|
#define OSC_ROUTE_VERSION "1.05"
|
|||
|
#define OSCWarning(x...) post(x)
|
|||
|
|
|||
|
/* the required include files */
|
|||
|
#include "m_pd.h"
|
|||
|
|
|||
|
|
|||
|
#ifndef TRUE
|
|||
|
typedef int Boolean;
|
|||
|
#define TRUE 1
|
|||
|
#define FALSE 0
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
/* Fixed byte width types */
|
|||
|
typedef int int4; /* 4 byte int */
|
|||
|
|
|||
|
Boolean PatternMatch (const char *pattern, const char *test);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* Version 1.04: Allows #1 thru #9 as typed-in arguments
|
|||
|
Version 1.05: Allows "list" messages as well as "message" messages.
|
|||
|
*/
|
|||
|
|
|||
|
static t_class *OSCroute_class;
|
|||
|
|
|||
|
typedef struct _OSCroute
|
|||
|
{
|
|||
|
t_object x_obj; // required header
|
|||
|
t_int x_num; // Number of address prefixes we store
|
|||
|
t_int x_complainmode; // Do we print a message if no match?
|
|||
|
t_int x_sendmode; // use pd internal sends instead of outlets
|
|||
|
char *x_prefixes[MAX_NUM];
|
|||
|
void *x_outlets[MAX_NUM+1];
|
|||
|
} t_OSCroute;
|
|||
|
|
|||
|
t_symbol *ps_list, *ps_complain, *ps_emptySymbol;
|
|||
|
|
|||
|
/* prototypes */
|
|||
|
|
|||
|
void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
|
|||
|
void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
|
|||
|
void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
|
|||
|
/* //void *OSCroute_new(t_symbol *s, int argc, atom *argv); */
|
|||
|
void *OSCroute_new(t_symbol *s, int argc, t_atom *argv);
|
|||
|
void OSCroute_version (t_OSCroute *x);
|
|||
|
/* void OSCroute_assist (OSCroute *x, void *box, long msg, long arg, */
|
|||
|
/* char *dstString); */
|
|||
|
void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
|
|||
|
|
|||
|
static char *NextSlashOrNull(char *p);
|
|||
|
static void StrCopyUntilSlash(char *target, const char *source);
|
|||
|
|
|||
|
|
|||
|
// free
|
|||
|
static void OSCroute_free(t_OSCroute *x)
|
|||
|
{
|
|||
|
// freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
|
|||
|
}
|
|||
|
|
|||
|
/* initialization routine */
|
|||
|
|
|||
|
// setup
|
|||
|
#ifdef WIN32
|
|||
|
OSC_API void OSCroute_setup(void) {
|
|||
|
#else
|
|||
|
void OSCroute_setup(void) {
|
|||
|
#endif
|
|||
|
OSCroute_class = class_new(gensym("OSCroute"), (t_newmethod)OSCroute_new,
|
|||
|
(t_method)OSCroute_free,sizeof(t_OSCroute), 0, A_GIMME, 0);
|
|||
|
class_addlist(OSCroute_class, OSCroute_list);
|
|||
|
class_addanything(OSCroute_class, OSCroute_anything);
|
|||
|
class_addmethod(OSCroute_class, (t_method)OSCroute_version, gensym("version"), A_NULL, 0, 0);
|
|||
|
class_sethelpsymbol(OSCroute_class, gensym("OSCroute-help.pd"));
|
|||
|
|
|||
|
/*
|
|||
|
class_addmethod(OSCroute_class, (t_method)OSCroute_connect,
|
|||
|
gensym("connect"), A_SYMBOL, A_FLOAT, 0);
|
|||
|
class_addmethod(OSCroute_class, (t_method)OSCroute_disconnect,
|
|||
|
gensym("disconnect"), 0);
|
|||
|
class_addmethod(OSCroute_class, (t_method)OSCroute_send, gensym("send"),
|
|||
|
A_GIMME, 0);
|
|||
|
*/
|
|||
|
/* ps_list = gensym("list"); */
|
|||
|
/* ps_complain = gensym("complain"); */
|
|||
|
ps_emptySymbol = gensym("");
|
|||
|
|
|||
|
post("OSCroute object version " OSC_ROUTE_VERSION " by Matt Wright. pd: jdl Win32 raf.");
|
|||
|
post("OSCroute Copyright <20> 1999 Regents of the University of California. All Rights Reserved.");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* instance creation routine */
|
|||
|
|
|||
|
void *OSCroute_new(t_symbol *s, int argc, t_atom *argv)
|
|||
|
{
|
|||
|
|
|||
|
t_OSCroute *x = (t_OSCroute *)pd_new(OSCroute_class); // get memory for a new object & initialize
|
|||
|
|
|||
|
int i; //{{raf}} n not used
|
|||
|
|
|||
|
// EnterCallback();
|
|||
|
|
|||
|
if (argc > MAX_NUM) {
|
|||
|
post("* OSC-route: too many arguments: %ld (max %ld)", argc, MAX_NUM);
|
|||
|
// ExitCallback();
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
x->x_complainmode = 0;
|
|||
|
x->x_num = 0;
|
|||
|
for (i = 0; i < argc; ++i) {
|
|||
|
if (argv[i].a_type == A_SYMBOL) {
|
|||
|
if (argv[i].a_w.w_symbol->s_name[0] == '/') {
|
|||
|
/* Now that's a nice prefix */
|
|||
|
x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name;
|
|||
|
++(x->x_num);
|
|||
|
} else if (argv[i].a_w.w_symbol->s_name[0] == '#' &&
|
|||
|
argv[i].a_w.w_symbol->s_name[1] >= '1' &&
|
|||
|
argv[i].a_w.w_symbol->s_name[1] <= '9') {
|
|||
|
/* The Max programmer is trying to make a patch that will be
|
|||
|
a subpatch with arguments. We have to make an outlet for this
|
|||
|
argument. */
|
|||
|
x->x_prefixes[i] = "dummy";
|
|||
|
++(x->x_num);
|
|||
|
} else {
|
|||
|
/* Maybe this is an option we support */
|
|||
|
|
|||
|
/* if (argv[i].a_w.w_sym == ps_complain) { */
|
|||
|
/* x->x_complainmode = 1; */
|
|||
|
/* } else { */
|
|||
|
/* post("* OSC-route: Unrecognized argument %s", argv[i].a_w.w_sym->s_name); */
|
|||
|
/* } */
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// no LONG
|
|||
|
|
|||
|
/* } else if (argv[i].a_type == A_FLOAD) { */
|
|||
|
/* // Convert to a numeral. Max ints are -2147483648 to 2147483647 */
|
|||
|
/* char *string = getbytes(12); */
|
|||
|
/* // I can't be bothered to plug this 12 byte memory leak */
|
|||
|
/* if (string == 0) { */
|
|||
|
/* post("* OSC-route: out of memory!"); */
|
|||
|
/* // ExitCallback(); */
|
|||
|
/* return 0; */
|
|||
|
/* } */
|
|||
|
/* sprintf(string, "%d", argv[i].a_w.w_long); */
|
|||
|
/* x->x_prefixes[i] = string; */
|
|||
|
/* ++(x->x_num); */
|
|||
|
|
|||
|
} else if (argv[i].a_type == A_FLOAT) {
|
|||
|
post("* OSC-route: float arguments are not OK.");
|
|||
|
// ExitCallback();
|
|||
|
return 0;
|
|||
|
} else {
|
|||
|
post("* OSC-route: unrecognized argument type!");
|
|||
|
// ExitCallback();
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Have to create the outlets in reverse order */
|
|||
|
/* well, not in pd ? */
|
|||
|
// for (i = x->x_num-1; i >= 0; --i) {
|
|||
|
// for (i = 0; i <= x->x_num-1; i++) {
|
|||
|
for (i = 0; i <= x->x_num; i++) {
|
|||
|
// x->x_outlets[i] = listout(x);
|
|||
|
x->x_outlets[i] = outlet_new(&x->x_obj, &s_list);
|
|||
|
}
|
|||
|
|
|||
|
// ExitCallback();
|
|||
|
return (x);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void OSCroute_version (t_OSCroute *x) {
|
|||
|
// EnterCallback();
|
|||
|
post("OSCroute Version " OSC_ROUTE_VERSION
|
|||
|
", by Matt Wright. pd jdl, win32: raf.\nOSCroute Compiled " __TIME__ " " __DATE__);
|
|||
|
// ExitCallback();
|
|||
|
}
|
|||
|
|
|||
|
/* I don't know why these aren't defined in some Max #include file. */
|
|||
|
#define ASSIST_INLET 1
|
|||
|
#define ASSIST_OUTLET 2
|
|||
|
|
|||
|
void OSCroute_assist (t_OSCroute *x, void *box, long msg, long arg,
|
|||
|
char *dstString) {
|
|||
|
// EnterCallback();
|
|||
|
|
|||
|
if (msg==ASSIST_INLET) {
|
|||
|
sprintf(dstString, "Incoming OSC messages");
|
|||
|
} else if (msg==ASSIST_OUTLET) {
|
|||
|
if (arg < 0 || arg >= x->x_num) {
|
|||
|
post("* OSCroute_assist: No outlet corresponds to arg %ld!", arg);
|
|||
|
} else {
|
|||
|
sprintf(dstString, "subaddress + args for prefix %s", x->x_prefixes[arg]);
|
|||
|
}
|
|||
|
} else {
|
|||
|
post("* OSCroute_assist: unrecognized message %ld", msg);
|
|||
|
}
|
|||
|
|
|||
|
// ExitCallback();
|
|||
|
}
|
|||
|
|
|||
|
void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
|
|||
|
// EnterCallback();
|
|||
|
if (argc > 0 && argv[0].a_type == A_SYMBOL) {
|
|||
|
/* Ignore the fact that this is a "list" */
|
|||
|
OSCroute_doanything(x, argv[0].a_w.w_symbol, argc-1, argv+1);
|
|||
|
} else {
|
|||
|
// post("* OSC-route: invalid list beginning with a number");
|
|||
|
// output on unmatched outlet jdl 20020908
|
|||
|
if (argv[0].a_type == A_FLOAT) {
|
|||
|
outlet_float(x->x_outlets[x->x_num], argv[0].a_w.w_float);
|
|||
|
} else {
|
|||
|
post("* OSC-route: unrecognized atom type!");
|
|||
|
}
|
|||
|
}
|
|||
|
// ExitCallback();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
|
|||
|
// EnterCallback();
|
|||
|
OSCroute_doanything(x, s, argc, argv);
|
|||
|
// ExitCallback();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
|
|||
|
char *pattern, *nextSlash;
|
|||
|
int i;
|
|||
|
int matchedAnything;
|
|||
|
// post("*** OSCroute_anything(s %s, argc %ld)", s->s_name, (long) argc);
|
|||
|
|
|||
|
pattern = s->s_name;
|
|||
|
if (pattern[0] != '/') {
|
|||
|
post("* OSC-route: invalid message pattern %s does not begin with /", s->s_name);
|
|||
|
outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
matchedAnything = 0;
|
|||
|
|
|||
|
nextSlash = NextSlashOrNull(pattern+1);
|
|||
|
if (*nextSlash == '\0') {
|
|||
|
/* last level of the address, so we'll output the argument list */
|
|||
|
|
|||
|
|
|||
|
#ifdef NULL_IS_DIFFERENT_FROM_BANG
|
|||
|
if (argc==0) {
|
|||
|
post("* OSC-route: why are you matching one level pattern %s with no args?",
|
|||
|
pattern);
|
|||
|
return;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
for (i = 0; i < x->x_num; ++i) {
|
|||
|
if (PatternMatch(pattern+1, x->x_prefixes[i]+1)) {
|
|||
|
++matchedAnything;
|
|||
|
|
|||
|
// I hate stupid Max lists with a special first element
|
|||
|
if (argc == 0) {
|
|||
|
outlet_bang(x->x_outlets[i]);
|
|||
|
} else if (argv[0].a_type == A_SYMBOL) {
|
|||
|
// Promote the symbol that was argv[0] to the special symbol
|
|||
|
outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1);
|
|||
|
} else if (argc > 1) {
|
|||
|
// Multiple arguments starting with a number, so naturally we have
|
|||
|
// to use a special function to output this "list", since it's what
|
|||
|
// Max originally meant by "list".
|
|||
|
outlet_list(x->x_outlets[i], 0L, argc, argv);
|
|||
|
} else {
|
|||
|
// There was only one argument, and it was a number, so we output it
|
|||
|
// not as a list
|
|||
|
/* if (argv[0].a_type == A_LONG) { */
|
|||
|
|
|||
|
/* outlet_int(x->x_outlets[i], argv[0].a_w.w_long); */
|
|||
|
// } else
|
|||
|
if (argv[0].a_type == A_FLOAT) {
|
|||
|
|
|||
|
outlet_float(x->x_outlets[i], argv[0].a_w.w_float);
|
|||
|
} else {
|
|||
|
post("* OSC-route: unrecognized atom type!");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
/* There's more address after this part, so our output list will begin with
|
|||
|
the next slash. */
|
|||
|
t_symbol *restOfPattern = 0; /* avoid the gensym unless we have to output */
|
|||
|
char patternBegin[1000];
|
|||
|
|
|||
|
|
|||
|
/* Get the first level of the incoming pattern to match against all our prefixes */
|
|||
|
StrCopyUntilSlash(patternBegin, pattern+1);
|
|||
|
|
|||
|
for (i = 0; i < x->x_num; ++i) {
|
|||
|
if (PatternMatch(patternBegin, x->x_prefixes[i]+1)) {
|
|||
|
++matchedAnything;
|
|||
|
if (restOfPattern == 0) {
|
|||
|
restOfPattern = gensym(nextSlash);
|
|||
|
}
|
|||
|
outlet_anything(x->x_outlets[i], restOfPattern, argc, argv);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (x->x_complainmode) {
|
|||
|
if (!matchedAnything) {
|
|||
|
post("* OSC-route: pattern %s did not match any prefixes", pattern);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// output unmatched data on rightmost outlet a la normal 'route' object, jdl 20020908
|
|||
|
if (!matchedAnything) {
|
|||
|
outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
static char *NextSlashOrNull(char *p) {
|
|||
|
while (*p != '/' && *p != '\0') {
|
|||
|
p++;
|
|||
|
}
|
|||
|
return p;
|
|||
|
}
|
|||
|
|
|||
|
static void StrCopyUntilSlash(char *target, const char *source) {
|
|||
|
while (*source != '/' && *source != '\0') {
|
|||
|
*target = *source;
|
|||
|
++target;
|
|||
|
++source;
|
|||
|
}
|
|||
|
*target = 0;
|
|||
|
}
|
|||
|
|
|||
|
static int MyStrCopy(char *target, const char *source) {
|
|||
|
int i = 0;
|
|||
|
while (*source != '\0') {
|
|||
|
*target = *source;
|
|||
|
++target;
|
|||
|
++source;
|
|||
|
++i;
|
|||
|
}
|
|||
|
*target = 0;
|
|||
|
return i;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
|
|||
|
int i;
|
|||
|
t_symbol *prefixSymbol = 0;
|
|||
|
char prefixBuf[1000];
|
|||
|
char *endOfPrefix;
|
|||
|
t_atom a[1];
|
|||
|
|
|||
|
if (argc >= 1 && argv[0].a_type == A_SYMBOL) {
|
|||
|
prefixSymbol = argv[0].a_w.w_symbol;
|
|||
|
endOfPrefix = prefixBuf + MyStrCopy(prefixBuf,
|
|||
|
prefixSymbol->s_name);
|
|||
|
} else {
|
|||
|
prefixSymbol = ps_emptySymbol;
|
|||
|
prefixBuf[0] = '\0';
|
|||
|
endOfPrefix = prefixBuf;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
for (i = 0; i < x->x_num; ++i) {
|
|||
|
post("OSC: %s%s", prefixSymbol->s_name, x->x_prefixes[i]);
|
|||
|
MyStrCopy(endOfPrefix, x->x_prefixes[i]);
|
|||
|
SETSYMBOL(a, gensym(prefixBuf));
|
|||
|
outlet_anything(x->x_outlets[i], s, 1, a);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* --------------------------------------------------- */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
static const char *theWholePattern; /* Just for warning messages */
|
|||
|
|
|||
|
static Boolean MatchBrackets (const char *pattern, const char *test);
|
|||
|
static Boolean MatchList (const char *pattern, const char *test);
|
|||
|
|
|||
|
Boolean PatternMatch (const char * pattern, const char * test) {
|
|||
|
theWholePattern = pattern;
|
|||
|
|
|||
|
if (pattern == 0 || pattern[0] == 0) {
|
|||
|
return test[0] == 0;
|
|||
|
}
|
|||
|
|
|||
|
if (test[0] == 0) {
|
|||
|
if (pattern[0] == '*')
|
|||
|
return PatternMatch (pattern+1,test);
|
|||
|
else
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
switch (pattern[0]) {
|
|||
|
case 0 : return test[0] == 0;
|
|||
|
case '?' : return PatternMatch (pattern + 1, test + 1);
|
|||
|
case '*' :
|
|||
|
if (PatternMatch (pattern+1, test)) {
|
|||
|
return TRUE;
|
|||
|
} else {
|
|||
|
return PatternMatch (pattern, test+1);
|
|||
|
}
|
|||
|
case ']' :
|
|||
|
case '}' :
|
|||
|
OSCWarning("Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern);
|
|||
|
return FALSE;
|
|||
|
case '[' :
|
|||
|
return MatchBrackets (pattern,test);
|
|||
|
case '{' :
|
|||
|
return MatchList (pattern,test);
|
|||
|
case '\\' :
|
|||
|
if (pattern[1] == 0) {
|
|||
|
return test[0] == 0;
|
|||
|
} else if (pattern[1] == test[0]) {
|
|||
|
return PatternMatch (pattern+2,test+1);
|
|||
|
} else {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
default :
|
|||
|
if (pattern[0] == test[0]) {
|
|||
|
return PatternMatch (pattern+1,test+1);
|
|||
|
} else {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* we know that pattern[0] == '[' and test[0] != 0 */
|
|||
|
|
|||
|
static Boolean MatchBrackets (const char *pattern, const char *test) {
|
|||
|
Boolean result;
|
|||
|
Boolean negated = FALSE;
|
|||
|
const char *p = pattern;
|
|||
|
|
|||
|
if (pattern[1] == 0) {
|
|||
|
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (pattern[1] == '!') {
|
|||
|
negated = TRUE;
|
|||
|
p++;
|
|||
|
}
|
|||
|
|
|||
|
while (*p != ']') {
|
|||
|
if (*p == 0) {
|
|||
|
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
if (p[1] == '-' && p[2] != 0) {
|
|||
|
if (test[0] >= p[0] && test[0] <= p[2]) {
|
|||
|
result = !negated;
|
|||
|
goto advance;
|
|||
|
}
|
|||
|
}
|
|||
|
if (p[0] == test[0]) {
|
|||
|
result = !negated;
|
|||
|
goto advance;
|
|||
|
}
|
|||
|
p++;
|
|||
|
}
|
|||
|
|
|||
|
result = negated;
|
|||
|
|
|||
|
advance:
|
|||
|
|
|||
|
if (!result)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
while (*p != ']') {
|
|||
|
if (*p == 0) {
|
|||
|
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
p++;
|
|||
|
}
|
|||
|
|
|||
|
return PatternMatch (p+1,test+1);
|
|||
|
}
|
|||
|
|
|||
|
static Boolean MatchList (const char *pattern, const char *test) {
|
|||
|
|
|||
|
const char *restOfPattern, *tp = test;
|
|||
|
|
|||
|
|
|||
|
for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) {
|
|||
|
if (*restOfPattern == 0) {
|
|||
|
OSCWarning("Unterminated { in pattern \".../%s/...\"", theWholePattern);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
restOfPattern++; /* skip close curly brace */
|
|||
|
|
|||
|
|
|||
|
pattern++; /* skip open curly brace */
|
|||
|
|
|||
|
while (1) {
|
|||
|
|
|||
|
if (*pattern == ',') {
|
|||
|
if (PatternMatch (restOfPattern, tp)) {
|
|||
|
return TRUE;
|
|||
|
} else {
|
|||
|
tp = test;
|
|||
|
++pattern;
|
|||
|
}
|
|||
|
} else if (*pattern == '}') {
|
|||
|
return PatternMatch (restOfPattern, tp);
|
|||
|
} else if (*pattern == *tp) {
|
|||
|
++pattern;
|
|||
|
++tp;
|
|||
|
} else {
|
|||
|
tp = test;
|
|||
|
while (*pattern != ',' && *pattern != '}') {
|
|||
|
pattern++;
|
|||
|
}
|
|||
|
if (*pattern == ',') {
|
|||
|
pattern++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|