Fix pdbox makefile to actually take part in dependency generation
[kugel-rb.git] / apps / plugins / pdbox / PDa / extra / OSCroute.c
blob64edbc777fd8454111de1db6400c42cec21d5ada
1 /*
2 Written by Adrian Freed, The Center for New Music and Audio Technologies,
3 University of California, Berkeley. Copyright (c) 1992,93,94,95,96,97,98,99,2000,01,02,03,04
4 The Regents of the University of California (Regents).
6 Permission to use, copy, modify, distribute, and distribute modified versions
7 of this software and its documentation without fee and without a signed
8 licensing agreement, is hereby granted, provided that the above copyright
9 notice, this paragraph and the following two paragraphs appear in all copies,
10 modifications, and distributions.
12 IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
13 SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
14 OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
15 BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17 REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
20 HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
21 MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
27 /* OSC-route.c
28 Max object for OSC-style dispatching
30 To-do:
32 Match a pattern against a pattern?
33 Declare outlet types / distinguish leaf nodes from other children
34 More sophisticated (2-pass?) allmessages scheme
35 set message?
39 -------------
40 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
45 #ifdef ROCKBOX
46 #include "plugin.h"
47 #include "../../pdbox.h"
48 #else /* ROCKBOX */
49 #ifdef WIN32
50 #include <stdlib.h>
51 #include <string.h>
52 #endif
53 #ifdef __APPLE__
54 #include <stdio.h>
55 #endif
56 #ifdef UNIX
57 #include <stdio.h>
58 #endif
59 #endif /* ROCKBOX */
61 /* structure definition of your object */
63 #define MAX_NUM 20
64 #define OSC_ROUTE_VERSION "1.05"
65 #define OSCWarning(x...) post(x)
67 /* the required include files */
68 #include "../src/m_pd.h"
71 #ifndef TRUE
72 typedef int Boolean;
73 #define TRUE 1
74 #define FALSE 0
75 #endif
78 /* Fixed byte width types */
79 typedef int int4; /* 4 byte int */
81 Boolean PatternMatch (const char *pattern, const char *test);
85 /* Version 1.04: Allows #1 thru #9 as typed-in arguments
86 Version 1.05: Allows "list" messages as well as "message" messages.
89 static t_class *OSCroute_class;
91 typedef struct _OSCroute
93 t_object x_obj; // required header
94 t_int x_num; // Number of address prefixes we store
95 t_int x_complainmode; // Do we print a message if no match?
96 t_int x_sendmode; // use pd internal sends instead of outlets
97 char *x_prefixes[MAX_NUM];
98 void *x_outlets[MAX_NUM+1];
99 } t_OSCroute;
101 t_symbol *ps_list, *ps_complain, *ps_emptySymbol;
103 /* prototypes */
105 void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
106 void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
107 void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
108 /* //void *OSCroute_new(t_symbol *s, int argc, atom *argv); */
109 void *OSCroute_new(t_symbol *s, int argc, t_atom *argv);
110 void OSCroute_version (t_OSCroute *x);
111 /* void OSCroute_assist (OSCroute *x, void *box, long msg, long arg, */
112 /* char *dstString); */
113 void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
115 static char *NextSlashOrNull(char *p);
116 static void StrCopyUntilSlash(char *target, const char *source);
119 // free
120 static void OSCroute_free(t_OSCroute *x)
122 #ifdef ROCKBOX
123 (void) x;
124 #endif
125 // freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
128 /* initialization routine */
130 // setup
131 #ifdef WIN32
132 OSC_API void OSCroute_setup(void) {
133 #else
134 void OSCroute_setup(void) {
135 #endif
136 OSCroute_class = class_new(gensym("OSCroute"), (t_newmethod)OSCroute_new,
137 (t_method)OSCroute_free,sizeof(t_OSCroute), 0, A_GIMME, 0);
138 class_addlist(OSCroute_class, OSCroute_list);
139 class_addanything(OSCroute_class, OSCroute_anything);
140 class_addmethod(OSCroute_class, (t_method)OSCroute_version, gensym("version"), A_NULL, 0, 0);
141 class_sethelpsymbol(OSCroute_class, gensym("OSCroute-help.pd"));
144 class_addmethod(OSCroute_class, (t_method)OSCroute_connect,
145 gensym("connect"), A_SYMBOL, A_FLOAT, 0);
146 class_addmethod(OSCroute_class, (t_method)OSCroute_disconnect,
147 gensym("disconnect"), 0);
148 class_addmethod(OSCroute_class, (t_method)OSCroute_send, gensym("send"),
149 A_GIMME, 0);
151 /* ps_list = gensym("list"); */
152 /* ps_complain = gensym("complain"); */
153 ps_emptySymbol = gensym("");
155 post("OSCroute object version " OSC_ROUTE_VERSION " by Matt Wright. pd: jdl Win32 raf.");
156 post("OSCroute Copyright © 1999 Regents of the University of California. All Rights Reserved.");
161 /* instance creation routine */
163 void *OSCroute_new(t_symbol *s, int argc, t_atom *argv)
165 #ifdef ROCKBOX
166 (void) s;
167 #endif
168 t_OSCroute *x = (t_OSCroute *)pd_new(OSCroute_class); // get memory for a new object & initialize
170 int i; //{{raf}} n not used
172 // EnterCallback();
174 if (argc > MAX_NUM) {
175 post("* OSC-route: too many arguments: %ld (max %ld)", argc, MAX_NUM);
176 // ExitCallback();
177 return 0;
180 x->x_complainmode = 0;
181 x->x_num = 0;
182 for (i = 0; i < argc; ++i) {
183 if (argv[i].a_type == A_SYMBOL) {
184 if (argv[i].a_w.w_symbol->s_name[0] == '/') {
185 /* Now that's a nice prefix */
186 x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name;
187 ++(x->x_num);
188 } else if (argv[i].a_w.w_symbol->s_name[0] == '#' &&
189 argv[i].a_w.w_symbol->s_name[1] >= '1' &&
190 argv[i].a_w.w_symbol->s_name[1] <= '9') {
191 /* The Max programmer is trying to make a patch that will be
192 a subpatch with arguments. We have to make an outlet for this
193 argument. */
194 x->x_prefixes[i] = "dummy";
195 ++(x->x_num);
196 } else {
197 /* Maybe this is an option we support */
199 /* if (argv[i].a_w.w_sym == ps_complain) { */
200 /* x->x_complainmode = 1; */
201 /* } else { */
202 /* post("* OSC-route: Unrecognized argument %s", argv[i].a_w.w_sym->s_name); */
203 /* } */
207 // no LONG
209 /* } else if (argv[i].a_type == A_FLOAD) { */
210 /* // Convert to a numeral. Max ints are -2147483648 to 2147483647 */
211 /* char *string = getbytes(12); */
212 /* // I can't be bothered to plug this 12 byte memory leak */
213 /* if (string == 0) { */
214 /* post("* OSC-route: out of memory!"); */
215 /* // ExitCallback(); */
216 /* return 0; */
217 /* } */
218 /* sprintf(string, "%d", argv[i].a_w.w_long); */
219 /* x->x_prefixes[i] = string; */
220 /* ++(x->x_num); */
222 } else if (argv[i].a_type == A_FLOAT) {
223 post("* OSC-route: float arguments are not OK.");
224 // ExitCallback();
225 return 0;
226 } else {
227 post("* OSC-route: unrecognized argument type!");
228 // ExitCallback();
229 return 0;
234 /* Have to create the outlets in reverse order */
235 /* well, not in pd ? */
236 // for (i = x->x_num-1; i >= 0; --i) {
237 // for (i = 0; i <= x->x_num-1; i++) {
238 for (i = 0; i <= x->x_num; i++) {
239 // x->x_outlets[i] = listout(x);
240 x->x_outlets[i] = outlet_new(&x->x_obj, &s_list);
243 // ExitCallback();
244 return (x);
248 void OSCroute_version (t_OSCroute *x) {
249 #ifdef ROCKBOX
250 (void) x;
251 #endif
252 // EnterCallback();
253 post("OSCroute Version " OSC_ROUTE_VERSION
254 ", by Matt Wright. pd jdl, win32: raf.\nOSCroute Compiled " __TIME__ " " __DATE__);
255 // ExitCallback();
258 /* I don't know why these aren't defined in some Max #include file. */
259 #define ASSIST_INLET 1
260 #define ASSIST_OUTLET 2
262 void OSCroute_assist (t_OSCroute *x, void *box, long msg, long arg,
263 char *dstString) {
264 #ifdef ROCKBOX
265 (void) box;
266 #endif
267 // EnterCallback();
269 if (msg==ASSIST_INLET) {
270 #ifdef ROCKBOX
271 strcpy(dstString, "Incoming OSC messages");
272 #else
273 sprintf(dstString, "Incoming OSC messages");
274 #endif
275 } else if (msg==ASSIST_OUTLET) {
276 if (arg < 0 || arg >= x->x_num) {
277 post("* OSCroute_assist: No outlet corresponds to arg %ld!", arg);
278 } else {
279 #ifdef ROCKBOX
280 strcpy(dstString, "subaddress + args for prefix ");
281 strcat(dstString, x->x_prefixes[arg]);
282 #else
283 sprintf(dstString, "subaddress + args for prefix %s", x->x_prefixes[arg]);
284 #endif
286 } else {
287 post("* OSCroute_assist: unrecognized message %ld", msg);
290 // ExitCallback();
293 void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
294 #ifdef ROCKBOX
295 (void) s;
296 #endif
297 // EnterCallback();
298 if (argc > 0 && argv[0].a_type == A_SYMBOL) {
299 /* Ignore the fact that this is a "list" */
300 OSCroute_doanything(x, argv[0].a_w.w_symbol, argc-1, argv+1);
301 } else {
302 // post("* OSC-route: invalid list beginning with a number");
303 // output on unmatched outlet jdl 20020908
304 if (argv[0].a_type == A_FLOAT) {
305 outlet_float(x->x_outlets[x->x_num], argv[0].a_w.w_float);
306 } else {
307 post("* OSC-route: unrecognized atom type!");
310 // ExitCallback();
314 void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
315 // EnterCallback();
316 OSCroute_doanything(x, s, argc, argv);
317 // ExitCallback();
323 void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
324 char *pattern, *nextSlash;
325 int i;
326 int matchedAnything;
327 // post("*** OSCroute_anything(s %s, argc %ld)", s->s_name, (long) argc);
329 pattern = s->s_name;
330 if (pattern[0] != '/') {
331 post("* OSC-route: invalid message pattern %s does not begin with /", s->s_name);
332 outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
333 return;
336 matchedAnything = 0;
338 nextSlash = NextSlashOrNull(pattern+1);
339 if (*nextSlash == '\0') {
340 /* last level of the address, so we'll output the argument list */
343 #ifdef NULL_IS_DIFFERENT_FROM_BANG
344 if (argc==0) {
345 post("* OSC-route: why are you matching one level pattern %s with no args?",
346 pattern);
347 return;
349 #endif
351 for (i = 0; i < x->x_num; ++i) {
352 if (PatternMatch(pattern+1, x->x_prefixes[i]+1)) {
353 ++matchedAnything;
355 // I hate stupid Max lists with a special first element
356 if (argc == 0) {
357 outlet_bang(x->x_outlets[i]);
358 } else if (argv[0].a_type == A_SYMBOL) {
359 // Promote the symbol that was argv[0] to the special symbol
360 outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1);
361 } else if (argc > 1) {
362 // Multiple arguments starting with a number, so naturally we have
363 // to use a special function to output this "list", since it's what
364 // Max originally meant by "list".
365 outlet_list(x->x_outlets[i], 0L, argc, argv);
366 } else {
367 // There was only one argument, and it was a number, so we output it
368 // not as a list
369 /* if (argv[0].a_type == A_LONG) { */
371 /* outlet_int(x->x_outlets[i], argv[0].a_w.w_long); */
372 // } else
373 if (argv[0].a_type == A_FLOAT) {
375 outlet_float(x->x_outlets[i], argv[0].a_w.w_float);
376 } else {
377 post("* OSC-route: unrecognized atom type!");
382 } else {
383 /* There's more address after this part, so our output list will begin with
384 the next slash. */
385 t_symbol *restOfPattern = 0; /* avoid the gensym unless we have to output */
386 char patternBegin[1000];
389 /* Get the first level of the incoming pattern to match against all our prefixes */
390 StrCopyUntilSlash(patternBegin, pattern+1);
392 for (i = 0; i < x->x_num; ++i) {
393 if (PatternMatch(patternBegin, x->x_prefixes[i]+1)) {
394 ++matchedAnything;
395 if (restOfPattern == 0) {
396 restOfPattern = gensym(nextSlash);
398 outlet_anything(x->x_outlets[i], restOfPattern, argc, argv);
403 if (x->x_complainmode) {
404 if (!matchedAnything) {
405 post("* OSC-route: pattern %s did not match any prefixes", pattern);
409 // output unmatched data on rightmost outlet a la normal 'route' object, jdl 20020908
410 if (!matchedAnything) {
411 outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
417 static char *NextSlashOrNull(char *p) {
418 while (*p != '/' && *p != '\0') {
419 p++;
421 return p;
424 static void StrCopyUntilSlash(char *target, const char *source) {
425 while (*source != '/' && *source != '\0') {
426 *target = *source;
427 ++target;
428 ++source;
430 *target = 0;
433 static int MyStrCopy(char *target, const char *source) {
434 int i = 0;
435 while (*source != '\0') {
436 *target = *source;
437 ++target;
438 ++source;
439 ++i;
441 *target = 0;
442 return i;
447 void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
448 int i;
449 t_symbol *prefixSymbol = 0;
450 char prefixBuf[1000];
451 char *endOfPrefix;
452 t_atom a[1];
454 if (argc >= 1 && argv[0].a_type == A_SYMBOL) {
455 prefixSymbol = argv[0].a_w.w_symbol;
456 endOfPrefix = prefixBuf + MyStrCopy(prefixBuf,
457 prefixSymbol->s_name);
458 } else {
459 prefixSymbol = ps_emptySymbol;
460 prefixBuf[0] = '\0';
461 endOfPrefix = prefixBuf;
465 for (i = 0; i < x->x_num; ++i) {
466 post("OSC: %s%s", prefixSymbol->s_name, x->x_prefixes[i]);
467 MyStrCopy(endOfPrefix, x->x_prefixes[i]);
468 SETSYMBOL(a, gensym(prefixBuf));
469 outlet_anything(x->x_outlets[i], s, 1, a);
474 /* --------------------------------------------------- */
478 static const char *theWholePattern; /* Just for warning messages */
480 static Boolean MatchBrackets (const char *pattern, const char *test);
481 static Boolean MatchList (const char *pattern, const char *test);
483 Boolean PatternMatch (const char * pattern, const char * test) {
484 theWholePattern = pattern;
486 if (pattern == 0 || pattern[0] == 0) {
487 return test[0] == 0;
490 if (test[0] == 0) {
491 if (pattern[0] == '*')
492 return PatternMatch (pattern+1,test);
493 else
494 return FALSE;
497 switch (pattern[0]) {
498 case 0 : return test[0] == 0;
499 case '?' : return PatternMatch (pattern + 1, test + 1);
500 case '*' :
501 if (PatternMatch (pattern+1, test)) {
502 return TRUE;
503 } else {
504 return PatternMatch (pattern, test+1);
506 case ']' :
507 case '}' :
508 OSCWarning("Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern);
509 return FALSE;
510 case '[' :
511 return MatchBrackets (pattern,test);
512 case '{' :
513 return MatchList (pattern,test);
514 case '\\' :
515 if (pattern[1] == 0) {
516 return test[0] == 0;
517 } else if (pattern[1] == test[0]) {
518 return PatternMatch (pattern+2,test+1);
519 } else {
520 return FALSE;
522 default :
523 if (pattern[0] == test[0]) {
524 return PatternMatch (pattern+1,test+1);
525 } else {
526 return FALSE;
532 /* we know that pattern[0] == '[' and test[0] != 0 */
534 static Boolean MatchBrackets (const char *pattern, const char *test) {
535 Boolean result;
536 Boolean negated = FALSE;
537 const char *p = pattern;
539 if (pattern[1] == 0) {
540 OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
541 return FALSE;
544 if (pattern[1] == '!') {
545 negated = TRUE;
546 p++;
549 while (*p != ']') {
550 if (*p == 0) {
551 OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
552 return FALSE;
554 if (p[1] == '-' && p[2] != 0) {
555 if (test[0] >= p[0] && test[0] <= p[2]) {
556 result = !negated;
557 goto advance;
560 if (p[0] == test[0]) {
561 result = !negated;
562 goto advance;
564 p++;
567 result = negated;
569 advance:
571 if (!result)
572 return FALSE;
574 while (*p != ']') {
575 if (*p == 0) {
576 OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
577 return FALSE;
579 p++;
582 return PatternMatch (p+1,test+1);
585 static Boolean MatchList (const char *pattern, const char *test) {
587 const char *restOfPattern, *tp = test;
590 for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) {
591 if (*restOfPattern == 0) {
592 OSCWarning("Unterminated { in pattern \".../%s/...\"", theWholePattern);
593 return FALSE;
597 restOfPattern++; /* skip close curly brace */
600 pattern++; /* skip open curly brace */
602 while (1) {
604 if (*pattern == ',') {
605 if (PatternMatch (restOfPattern, tp)) {
606 return TRUE;
607 } else {
608 tp = test;
609 ++pattern;
611 } else if (*pattern == '}') {
612 return PatternMatch (restOfPattern, tp);
613 } else if (*pattern == *tp) {
614 ++pattern;
615 ++tp;
616 } else {
617 tp = test;
618 while (*pattern != ',' && *pattern != '}') {
619 pattern++;
621 if (*pattern == ',') {
622 pattern++;