summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/m_class.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/m_class.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/m_class.c1648
1 files changed, 1648 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/m_class.c b/apps/plugins/pdbox/PDa/src/m_class.c
new file mode 100644
index 0000000000..0b6d4df885
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_class.c
@@ -0,0 +1,1648 @@
1/* Copyright (c) 1997-1999 Miller Puckette.
2* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
4
5#define PD_CLASS_DEF
6#include "m_pd.h"
7#include "m_imp.h"
8#include "s_stuff.h"
9#include <stdlib.h>
10#ifdef UNIX
11#include <unistd.h>
12#endif
13#ifdef MSW
14#include <io.h>
15#endif
16
17#include <stdarg.h>
18#include <string.h>
19
20static t_symbol *class_loadsym; /* name under which an extern is invoked */
21static void pd_defaultfloat(t_pd *x, t_float f);
22static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv);
23t_pd pd_objectmaker; /* factory for creating "object" boxes */
24t_pd pd_canvasmaker; /* factory for creating canvases */
25
26static t_symbol *class_extern_dir = &s_;
27
28static void pd_defaultanything(t_pd *x, t_symbol *s, int argc, t_atom *argv)
29{
30 pd_error(x, "%s: no method for '%s'", (*x)->c_name->s_name, s->s_name);
31}
32
33static void pd_defaultbang(t_pd *x)
34{
35 if (*(*x)->c_listmethod != pd_defaultlist)
36 (*(*x)->c_listmethod)(x, 0, 0, 0);
37 else (*(*x)->c_anymethod)(x, &s_bang, 0, 0);
38}
39
40static void pd_defaultpointer(t_pd *x, t_gpointer *gp)
41{
42 if (*(*x)->c_listmethod != pd_defaultlist)
43 {
44 t_atom at;
45 SETPOINTER(&at, gp);
46 (*(*x)->c_listmethod)(x, 0, 1, &at);
47 }
48 else
49 {
50 t_atom at;
51 SETPOINTER(&at, gp);
52 (*(*x)->c_anymethod)(x, &s_pointer, 1, &at);
53 }
54}
55
56static void pd_defaultfloat(t_pd *x, t_float f)
57{
58 if (*(*x)->c_listmethod != pd_defaultlist)
59 {
60 t_atom at;
61 SETFLOAT(&at, f);
62 (*(*x)->c_listmethod)(x, 0, 1, &at);
63 }
64 else
65 {
66 t_atom at;
67 SETFLOAT(&at, f);
68 (*(*x)->c_anymethod)(x, &s_float, 1, &at);
69 }
70}
71
72static void pd_defaultsymbol(t_pd *x, t_symbol *s)
73{
74 if (*(*x)->c_listmethod != pd_defaultlist)
75 {
76 t_atom at;
77 SETSYMBOL(&at, s);
78 (*(*x)->c_listmethod)(x, 0, 1, &at);
79 }
80 else
81 {
82 t_atom at;
83 SETSYMBOL(&at, s);
84 (*(*x)->c_anymethod)(x, &s_symbol, 1, &at);
85 }
86}
87
88void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
89static void class_nosavefn(t_gobj *z, t_binbuf *b);
90
91 /* handle "list" messages to Pds without explicit list methods defined. */
92static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv)
93{
94 /* a list with one element which is a number can be handled by a
95 "float" method if any is defined; same for "symbol", "pointer". */
96 if (argc == 1)
97 {
98 if (argv->a_type == A_FLOAT &&
99 *(*x)->c_floatmethod != pd_defaultfloat)
100 {
101 (*(*x)->c_floatmethod)(x, argv->a_w.w_float);
102 return;
103 }
104 else if (argv->a_type == A_SYMBOL &&
105 *(*x)->c_symbolmethod != pd_defaultsymbol)
106 {
107 (*(*x)->c_symbolmethod)(x, argv->a_w.w_symbol);
108 return;
109 }
110 else if (argv->a_type == A_POINTER &&
111 *(*x)->c_pointermethod != pd_defaultpointer)
112 {
113 (*(*x)->c_pointermethod)(x, argv->a_w.w_gpointer);
114 return;
115 }
116 }
117 /* Next try for an "anything" method */
118 if ((*x)->c_anymethod != pd_defaultanything)
119 (*(*x)->c_anymethod)(x, &s_list, argc, argv);
120
121 /* if the object is patchable (i.e., can have proper inlets)
122 send it on to obj_list which will unpack the list into the inlets */
123 else if ((*x)->c_patchable)
124 obj_list((t_object *)x, s, argc, argv);
125 /* otherwise gove up and complain. */
126 else pd_defaultanything(x, &s_list, argc, argv);
127}
128
129 /* for now we assume that all "gobjs" are text unless explicitly
130 overridden later by calling class_setbehavior(). I'm not sure
131 how to deal with Pds that aren't gobjs; shouldn't there be a
132 way to check that at run time? Perhaps the presence of a "newmethod"
133 should be our cue, or perhaps the "tiny" flag. */
134
135 /* another matter. This routine does two unrelated things: it creates
136 a Pd class, but also adds a "new" method to create an instance of it.
137 These are combined for historical reasons and for brevity in writing
138 objects. To avoid adding a "new" method send a null function pointer.
139 To add additional ones, use class_addcreator below. Some "classes", like
140 "select", are actually two classes of the same name, one for the single-
141 argument form, one for the multiple one; see select_setup() to find out
142 how this is handled. */
143
144extern t_widgetbehavior text_widgetbehavior;
145extern void text_save(t_gobj *z, t_binbuf *b);
146
147t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod,
148 size_t size, int flags, t_atomtype type1, ...)
149{
150 va_list ap;
151 t_atomtype vec[MAXPDARG+1], *vp = vec;
152 int count = 0;
153 t_class *c;
154 int typeflag = flags & CLASS_TYPEMASK;
155 if (!typeflag) typeflag = CLASS_PATCHABLE;
156 *vp = type1;
157
158 va_start(ap, type1);
159 while (*vp)
160 {
161 if (count == MAXPDARG)
162 {
163 error("class %s: sorry: only %d creation args allowed",
164 s->s_name, MAXPDARG);
165 break;
166 }
167 vp++;
168 count++;
169 *vp = va_arg(ap, t_atomtype);
170 }
171 va_end(ap);
172 if (pd_objectmaker && newmethod)
173 {
174 /* add a "new" method by the name specified by the object */
175 class_addmethod(pd_objectmaker, (t_method)newmethod, s,
176 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
177 if (class_loadsym)
178 {
179 /* if we're loading an extern it might have been invoked by a
180 longer file name; in this case, make this an admissible name
181 too. */
182 char *loadstring = class_loadsym->s_name,
183 l1 = strlen(s->s_name), l2 = strlen(loadstring);
184 if (l2 > l1 && !strcmp(s->s_name, loadstring + (l2 - l1)))
185 class_addmethod(pd_objectmaker, (t_method)newmethod,
186 class_loadsym,
187 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
188 }
189 }
190 c = (t_class *)t_getbytes(sizeof(*c));
191 c->c_name = c->c_helpname = s;
192 c->c_size = size;
193 c->c_methods = t_getbytes(0);
194 c->c_nmethod = 0;
195 c->c_freemethod = (t_method)freemethod;
196 c->c_bangmethod = pd_defaultbang;
197 c->c_pointermethod = pd_defaultpointer;
198 c->c_floatmethod = pd_defaultfloat;
199 c->c_symbolmethod = pd_defaultsymbol;
200 c->c_listmethod = pd_defaultlist;
201 c->c_anymethod = pd_defaultanything;
202 c->c_wb = (typeflag == CLASS_PATCHABLE ? &text_widgetbehavior : 0);
203 c->c_pwb = 0;
204 c->c_firstin = ((flags & CLASS_NOINLET) == 0);
205 c->c_patchable = (typeflag == CLASS_PATCHABLE);
206 c->c_gobj = (typeflag >= CLASS_GOBJ);
207 c->c_drawcommand = 0;
208 c->c_floatsignalin = 0;
209 c->c_externdir = class_extern_dir;
210 c->c_savefn = (typeflag == CLASS_PATCHABLE ? text_save : class_nosavefn);
211#if 0
212 post("class: %s", c->c_name->s_name);
213#endif
214 return (c);
215}
216
217 /* add a creation method, which is a function that returns a Pd object
218 suitable for putting in an object box. We presume you've got a class it
219 can belong to, but this won't be used until the newmethod is actually
220 called back (and the new method explicitly takes care of this.) */
221
222void class_addcreator(t_newmethod newmethod, t_symbol *s,
223 t_atomtype type1, ...)
224{
225 va_list ap;
226 t_atomtype vec[MAXPDARG+1], *vp = vec;
227 int count = 0;
228 *vp = type1;
229
230 va_start(ap, type1);
231 while (*vp)
232 {
233 if (count == MAXPDARG)
234 {
235 error("class %s: sorry: only %d creation args allowed",
236 s->s_name, MAXPDARG);
237 break;
238 }
239 vp++;
240 count++;
241 *vp = va_arg(ap, t_atomtype);
242 }
243 va_end(ap);
244 class_addmethod(pd_objectmaker, (t_method)newmethod, s,
245 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
246}
247
248void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
249 t_atomtype arg1, ...)
250{
251 va_list ap;
252 t_methodentry *m;
253 t_atomtype argtype = arg1;
254 int nargs;
255
256 va_start(ap, arg1);
257 /* "signal" method specifies that we take audio signals but
258 that we don't want automatic float to signal conversion. This
259 is obsolete; you should now use the CLASS_MAINSIGNALIN macro. */
260 if (sel == &s_signal)
261 {
262 if (c->c_floatsignalin)
263 post("warning: signal method overrides class_mainsignalin");
264 c->c_floatsignalin = -1;
265 }
266 /* check for special cases. "Pointer" is missing here so that
267 pd_objectmaker's pointer method can be typechecked differently. */
268 if (sel == &s_bang)
269 {
270 if (argtype) goto phooey;
271 class_addbang(c, fn);
272 }
273 else if (sel == &s_float)
274 {
275 if (argtype != A_FLOAT || va_arg(ap, t_atomtype)) goto phooey;
276 class_doaddfloat(c, fn);
277 }
278 else if (sel == &s_symbol)
279 {
280 if (argtype != A_SYMBOL || va_arg(ap, t_atomtype)) goto phooey;
281 class_addsymbol(c, fn);
282 }
283 else if (sel == &s_list)
284 {
285 if (argtype != A_GIMME) goto phooey;
286 class_addlist(c, fn);
287 }
288 else if (sel == &s_anything)
289 {
290 if (argtype != A_GIMME) goto phooey;
291 class_addanything(c, fn);
292 }
293 else
294 {
295 c->c_methods = t_resizebytes(c->c_methods,
296 c->c_nmethod * sizeof(*c->c_methods),
297 (c->c_nmethod + 1) * sizeof(*c->c_methods));
298 m = c->c_methods + c->c_nmethod;
299 c->c_nmethod++;
300 m->me_name = sel;
301 m->me_fun = (t_gotfn)fn;
302 nargs = 0;
303 while (argtype != A_NULL && nargs < MAXPDARG)
304 {
305 m->me_arg[nargs++] = argtype;
306 argtype = va_arg(ap, t_atomtype);
307 }
308 if (argtype != A_NULL)
309 error("%s_%s: only 5 arguments are typecheckable; use A_GIMME",
310 c->c_name->s_name, sel->s_name);
311 va_end(ap);
312 m->me_arg[nargs] = A_NULL;
313 }
314 return;
315phooey:
316 bug("class_addmethod: %s_%s: bad argument types\n",
317 c->c_name->s_name, sel->s_name);
318}
319
320 /* Instead of these, see the "class_addfloat", etc., macros in m_pd.h */
321void class_addbang(t_class *c, t_method fn)
322{
323 c->c_bangmethod = (t_bangmethod)fn;
324}
325
326void class_addpointer(t_class *c, t_method fn)
327{
328 c->c_pointermethod = (t_pointermethod)fn;
329}
330
331void class_doaddfloat(t_class *c, t_method fn)
332{
333 c->c_floatmethod = (t_floatmethod)fn;
334}
335
336void class_addsymbol(t_class *c, t_method fn)
337{
338 c->c_symbolmethod = (t_symbolmethod)fn;
339}
340
341void class_addlist(t_class *c, t_method fn)
342{
343 c->c_listmethod = (t_listmethod)fn;
344}
345
346void class_addanything(t_class *c, t_method fn)
347{
348 c->c_anymethod = (t_anymethod)fn;
349}
350
351void class_setwidget(t_class *c, t_widgetbehavior *w)
352{
353 c->c_wb = w;
354}
355
356void class_setparentwidget(t_class *c, t_parentwidgetbehavior *pw)
357{
358 c->c_pwb = pw;
359}
360
361char *class_getname(t_class *c)
362{
363 return (c->c_name->s_name);
364}
365
366char *class_gethelpname(t_class *c)
367{
368 return (c->c_helpname->s_name);
369}
370
371void class_sethelpsymbol(t_class *c, t_symbol *s)
372{
373 c->c_helpname = s;
374}
375
376t_parentwidgetbehavior *pd_getparentwidget(t_pd *x)
377{
378 return ((*x)->c_pwb);
379}
380
381void class_setdrawcommand(t_class *c)
382{
383 c->c_drawcommand = 1;
384}
385
386int class_isdrawcommand(t_class *c)
387{
388 return (c->c_drawcommand);
389}
390
391static void pd_floatforsignal(t_pd *x, t_float f)
392{
393 int offset = (*x)->c_floatsignalin;
394 if (offset > 0)
395 *(t_sample *)(((char *)x) + offset) = ftofix(f);
396 else
397 pd_error(x, "%s: float unexpected for signal input",
398 (*x)->c_name->s_name);
399}
400
401void class_domainsignalin(t_class *c, int onset)
402{
403 if (onset <= 0) onset = -1;
404 else
405 {
406 if (c->c_floatmethod != pd_defaultfloat)
407 post("warning: %s: float method overwritten", c->c_name->s_name);
408 c->c_floatmethod = (t_floatmethod)pd_floatforsignal;
409 }
410 c->c_floatsignalin = onset;
411}
412
413void class_set_extern_dir(t_symbol *s)
414{
415 class_extern_dir = s;
416}
417
418char *class_gethelpdir(t_class *c)
419{
420 return (c->c_externdir->s_name);
421}
422
423static void class_nosavefn(t_gobj *z, t_binbuf *b)
424{
425 bug("save function called but not defined");
426}
427
428void class_setsavefn(t_class *c, t_savefn f)
429{
430 c->c_savefn = f;
431}
432
433t_savefn class_getsavefn(t_class *c)
434{
435 return (c->c_savefn);
436}
437
438void class_setpropertiesfn(t_class *c, t_propertiesfn f)
439{
440 c->c_propertiesfn = f;
441}
442
443t_propertiesfn class_getpropertiesfn(t_class *c)
444{
445 return (c->c_propertiesfn);
446}
447
448/* ---------------- the symbol table ------------------------ */
449
450#define HASHSIZE 1024
451
452static t_symbol *symhash[HASHSIZE];
453
454t_symbol *dogensym(char *s, t_symbol *oldsym)
455{
456 t_symbol **sym1, *sym2;
457 unsigned int hash1 = 0, hash2 = 0;
458 int length = 0;
459 char *s2 = s;
460 while (*s2)
461 {
462 hash1 += *s2;
463 hash2 += hash1;
464 length++;
465 s2++;
466 }
467 sym1 = symhash + (hash2 & (HASHSIZE-1));
468 while (sym2 = *sym1)
469 {
470 if (!strcmp(sym2->s_name, s)) return(sym2);
471 sym1 = &sym2->s_next;
472 }
473 if (oldsym) sym2 = oldsym;
474 else
475 {
476 sym2 = (t_symbol *)t_getbytes(sizeof(*sym2));
477 sym2->s_name = t_getbytes(length+1);
478 sym2->s_next = 0;
479 sym2->s_thing = 0;
480 strcpy(sym2->s_name, s);
481 }
482 *sym1 = sym2;
483 return (sym2);
484}
485
486t_symbol *gensym(char *s)
487{
488 return(dogensym(s, 0));
489}
490
491static t_symbol *addfileextent(t_symbol *s)
492{
493 char namebuf[MAXPDSTRING], *str = s->s_name;
494 int ln = strlen(str);
495 if (!strcmp(str + ln - 3, ".pd")) return (s);
496 strcpy(namebuf, str);
497 strcpy(namebuf+ln, ".pd");
498 return (gensym(namebuf));
499}
500
501static int tryingalready;
502
503void canvas_popabstraction(t_canvas *x);
504extern t_pd *newest;
505
506t_symbol* pathsearch(t_symbol *s,char* ext);
507int pd_setloadingabstraction(t_symbol *sym);
508
509 /* this routine is called when a new "object" is requested whose class Pd
510 doesn't know. Pd tries to load it as an extern, then as an abstraction. */
511void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv)
512{
513 t_pd *current;
514 t_symbol *dir = canvas_getcurrentdir();
515 int fd;
516 char dirbuf[MAXPDSTRING], *nameptr;
517 if (tryingalready) return;
518 newest = 0;
519 class_loadsym = s;
520 if (sys_load_lib(dir->s_name, s->s_name))
521 {
522 tryingalready = 1;
523 typedmess(dummy, s, argc, argv);
524 tryingalready = 0;
525 return;
526 }
527 class_loadsym = 0;
528 current = s__X.s_thing;
529 if ((fd = open_via_path(dir->s_name, s->s_name, ".pd",
530 dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0 ||
531 (fd = open_via_path(dir->s_name, s->s_name, ".pat",
532 dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0)
533 {
534 close (fd);
535 if (!pd_setloadingabstraction(s))
536 {
537 canvas_setargs(argc, argv); /* bug fix by Krzysztof Czaja */
538 binbuf_evalfile(gensym(nameptr), gensym(dirbuf));
539 if (s__X.s_thing != current)
540 canvas_popabstraction((t_canvas *)(s__X.s_thing));
541 canvas_setargs(0, 0);
542 }
543 else error("%s: can't load abstraction within itself\n", s->s_name);
544 }
545 else newest = 0;
546}
547
548t_symbol s_pointer = {"pointer", 0, 0};
549t_symbol s_float = {"float", 0, 0};
550t_symbol s_symbol = {"symbol", 0, 0};
551t_symbol s_bang = {"bang", 0, 0};
552t_symbol s_list = {"list", 0, 0};
553t_symbol s_anything = {"anything", 0, 0};
554t_symbol s_signal = {"signal", 0, 0};
555t_symbol s__N = {"#N", 0, 0};
556t_symbol s__X = {"#X", 0, 0};
557t_symbol s_x = {"x", 0, 0};
558t_symbol s_y = {"y", 0, 0};
559t_symbol s_ = {"", 0, 0};
560
561static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang,
562 &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_};
563
564void mess_init(void)
565{
566 t_symbol **sp;
567 int i;
568
569 if (pd_objectmaker) return;
570 for (i = sizeof(symlist)/sizeof(*symlist), sp = symlist; i--; sp++)
571 (void) dogensym((*sp)->s_name, *sp);
572 pd_objectmaker = class_new(gensym("objectmaker"), 0, 0, sizeof(t_pd),
573 CLASS_DEFAULT, A_NULL);
574 pd_canvasmaker = class_new(gensym("classmaker"), 0, 0, sizeof(t_pd),
575 CLASS_DEFAULT, A_NULL);
576 pd_bind(&pd_canvasmaker, &s__N);
577 class_addanything(pd_objectmaker, (t_method)new_anything);
578}
579
580t_pd *newest;
581
582/* This is externally available, but note that it might later disappear; the
583whole "newest" thing is a hack which needs to be redesigned. */
584t_pd *pd_newest(void)
585{
586 return (newest);
587}
588
589 /* horribly, we need prototypes for each of the artificial function
590 calls in typedmess(), to keep the compiler quiet. */
591typedef t_pd *(*t_newgimme)(t_symbol *s, int argc, t_atom *argv);
592typedef void(*t_messgimme)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
593
594typedef t_pd *(*t_fun0)(
595 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
596typedef t_pd *(*t_fun1)(t_int i1,
597 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
598typedef t_pd *(*t_fun2)(t_int i1, t_int i2,
599 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
600typedef t_pd *(*t_fun3)(t_int i1, t_int i2, t_int i3,
601 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
602typedef t_pd *(*t_fun4)(t_int i1, t_int i2, t_int i3, t_int i4,
603 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
604typedef t_pd *(*t_fun5)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5,
605 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
606typedef t_pd *(*t_fun6)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, t_int i6,
607 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
608
609void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv)
610{
611 t_method *f;
612 t_class *c = *x;
613 t_methodentry *m;
614 t_atomtype *wp, wanttype;
615 int i;
616 t_int ai[MAXPDARG+1], *ap = ai;
617 t_floatarg ad[MAXPDARG+1], *dp = ad;
618 int narg = 0;
619 t_pd *bonzo;
620
621 /* check for messages that are handled by fixed slots in the class
622 structure. We don't catch "pointer" though so that sending "pointer"
623 to pd_objectmaker doesn't require that we supply a pointer value. */
624 if (s == &s_float)
625 {
626 if (!argc) (*c->c_floatmethod)(x, 0.);
627 else if (argv->a_type == A_FLOAT)
628 (*c->c_floatmethod)(x, argv->a_w.w_float);
629 else goto badarg;
630 return;
631 }
632 if (s == &s_bang)
633 {
634 (*c->c_bangmethod)(x);
635 return;
636 }
637 if (s == &s_list)
638 {
639 (*c->c_listmethod)(x, s, argc, argv);
640 return;
641 }
642 if (s == &s_symbol)
643 {
644 if (argc && argv->a_type == A_SYMBOL)
645 (*c->c_symbolmethod)(x, argv->a_w.w_symbol);
646 else
647 (*c->c_symbolmethod)(x, &s_);
648 return;
649 }
650 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
651 if (m->me_name == s)
652 {
653 wp = m->me_arg;
654 if (*wp == A_GIMME)
655 {
656 if (x == &pd_objectmaker)
657 newest = (*((t_newgimme)(m->me_fun)))(s, argc, argv);
658 else (*((t_messgimme)(m->me_fun)))(x, s, argc, argv);
659 return;
660 }
661 if (argc > MAXPDARG) argc = MAXPDARG;
662 if (x != &pd_objectmaker) *(ap++) = (t_int)x, narg++;
663 while (wanttype = *wp++)
664 {
665 switch (wanttype)
666 {
667 case A_POINTER:
668 if (!argc) goto badarg;
669 else
670 {
671 if (argv->a_type == A_POINTER)
672 *ap = (t_int)(argv->a_w.w_gpointer);
673 else goto badarg;
674 argc--;
675 argv++;
676 }
677 narg++;
678 ap++;
679 break;
680 case A_FLOAT:
681 if (!argc) goto badarg;
682 case A_DEFFLOAT:
683 if (!argc) *dp = 0;
684 else
685 {
686 if (argv->a_type == A_FLOAT)
687 *dp = argv->a_w.w_float;
688 else goto badarg;
689 argc--;
690 argv++;
691 }
692 dp++;
693 break;
694 case A_SYMBOL:
695 if (!argc) goto badarg;
696 case A_DEFSYM:
697 if (!argc) *ap = (t_int)(&s_);
698 else
699 {
700 if (argv->a_type == A_SYMBOL)
701 *ap = (t_int)(argv->a_w.w_symbol);
702 /* if it's an unfilled "dollar" argument it appears
703 as zero here; cheat and bash it to the null
704 symbol. Unfortunately, this lets real zeros
705 pass as symbols too, which seems wrong... */
706 else if (x == &pd_objectmaker && argv->a_type == A_FLOAT
707 && argv->a_w.w_float == 0)
708 *ap = (t_int)(&s_);
709 else goto badarg;
710 argc--;
711 argv++;
712 }
713 narg++;
714 ap++;
715 }
716 }
717 switch (narg)
718 {
719 case 0 : bonzo = (*(t_fun0)(m->me_fun))
720 (ad[0], ad[1], ad[2], ad[3], ad[4]); break;
721 case 1 : bonzo = (*(t_fun1)(m->me_fun))
722 (ai[0], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
723 case 2 : bonzo = (*(t_fun2)(m->me_fun))
724 (ai[0], ai[1], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
725 case 3 : bonzo = (*(t_fun3)(m->me_fun))
726 (ai[0], ai[1], ai[2], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
727 case 4 : bonzo = (*(t_fun4)(m->me_fun))
728 (ai[0], ai[1], ai[2], ai[3],
729 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
730 case 5 : bonzo = (*(t_fun5)(m->me_fun))
731 (ai[0], ai[1], ai[2], ai[3], ai[4],
732 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
733 case 6 : bonzo = (*(t_fun6)(m->me_fun))
734 (ai[0], ai[1], ai[2], ai[3], ai[4], ai[5],
735 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
736 default: bonzo = 0;
737 }
738 if (x == &pd_objectmaker)
739 newest = bonzo;
740 return;
741 }
742 (*c->c_anymethod)(x, s, argc, argv);
743 return;
744badarg:
745 pd_error(x, "Bad arguments for message '%s' to object '%s'",
746 s->s_name, c->c_name->s_name);
747}
748
749void pd_vmess(t_pd *x, t_symbol *sel, char *fmt, ...)
750{
751 va_list ap;
752 t_atom arg[MAXPDARG], *at =arg;
753 int nargs = 0;
754 char *fp = fmt;
755
756 va_start(ap, fmt);
757 while (1)
758 {
759 if (nargs > MAXPDARG)
760 {
761 pd_error(x, "pd_vmess: only %d allowed", MAXPDARG);
762 break;
763 }
764 switch(*fp++)
765 {
766 case 'f': SETFLOAT(at, va_arg(ap, double)); break;
767 case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
768 case 'i': SETFLOAT(at, va_arg(ap, t_int)); break;
769 case 'p': SETPOINTER(at, va_arg(ap, t_gpointer *)); break;
770 default: goto done;
771 }
772 at++;
773 nargs++;
774 }
775done:
776 va_end(ap);
777 typedmess(x, sel, nargs, arg);
778}
779
780void pd_forwardmess(t_pd *x, int argc, t_atom *argv)
781{
782 if (argc)
783 {
784 t_atomtype t = argv->a_type;
785 if (t == A_SYMBOL) pd_typedmess(x, argv->a_w.w_symbol, argc-1, argv+1);
786 else if (t == A_POINTER)
787 {
788 if (argc == 1) pd_pointer(x, argv->a_w.w_gpointer);
789 else pd_list(x, &s_list, argc, argv);
790 }
791 else if (t == A_FLOAT)
792 {
793 if (argc == 1) pd_float(x, argv->a_w.w_float);
794 else pd_list(x, &s_list, argc, argv);
795 }
796 else bug("pd_forwardmess");
797 }
798
799}
800
801void nullfn(void) {}
802
803t_gotfn getfn(t_pd *x, t_symbol *s)
804{
805 t_class *c = *x;
806 t_methodentry *m;
807 int i;
808
809 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
810 if (m->me_name == s) return(m->me_fun);
811 pd_error(x, "%s: no method for message '%s'", c->c_name->s_name, s->s_name);
812 return((t_gotfn)nullfn);
813}
814
815t_gotfn zgetfn(t_pd *x, t_symbol *s)
816{
817 t_class *c = *x;
818 t_methodentry *m;
819 int i;
820
821 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
822 if (m->me_name == s) return(m->me_fun);
823 return(0);
824}
825/* Copyright (c) 1997-1999 Miller Puckette.
826* For information on usage and redistribution, and for a DISCLAIMER OF ALL
827* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
828
829#define PD_CLASS_DEF
830#include "m_pd.h"
831#include "m_imp.h"
832#include "s_stuff.h"
833#include <stdlib.h>
834#ifdef UNIX
835#include <unistd.h>
836#endif
837#ifdef MSW
838#include <io.h>
839#endif
840
841#include <stdarg.h>
842#include <string.h>
843
844static t_symbol *class_loadsym; /* name under which an extern is invoked */
845static void pd_defaultfloat(t_pd *x, t_float f);
846static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv);
847t_pd pd_objectmaker; /* factory for creating "object" boxes */
848t_pd pd_canvasmaker; /* factory for creating canvases */
849
850static t_symbol *class_extern_dir = &s_;
851
852static void pd_defaultanything(t_pd *x, t_symbol *s, int argc, t_atom *argv)
853{
854 pd_error(x, "%s: no method for '%s'", (*x)->c_name->s_name, s->s_name);
855}
856
857static void pd_defaultbang(t_pd *x)
858{
859 if (*(*x)->c_listmethod != pd_defaultlist)
860 (*(*x)->c_listmethod)(x, 0, 0, 0);
861 else (*(*x)->c_anymethod)(x, &s_bang, 0, 0);
862}
863
864static void pd_defaultpointer(t_pd *x, t_gpointer *gp)
865{
866 if (*(*x)->c_listmethod != pd_defaultlist)
867 {
868 t_atom at;
869 SETPOINTER(&at, gp);
870 (*(*x)->c_listmethod)(x, 0, 1, &at);
871 }
872 else
873 {
874 t_atom at;
875 SETPOINTER(&at, gp);
876 (*(*x)->c_anymethod)(x, &s_pointer, 1, &at);
877 }
878}
879
880static void pd_defaultfloat(t_pd *x, t_float f)
881{
882 if (*(*x)->c_listmethod != pd_defaultlist)
883 {
884 t_atom at;
885 SETFLOAT(&at, f);
886 (*(*x)->c_listmethod)(x, 0, 1, &at);
887 }
888 else
889 {
890 t_atom at;
891 SETFLOAT(&at, f);
892 (*(*x)->c_anymethod)(x, &s_float, 1, &at);
893 }
894}
895
896static void pd_defaultsymbol(t_pd *x, t_symbol *s)
897{
898 if (*(*x)->c_listmethod != pd_defaultlist)
899 {
900 t_atom at;
901 SETSYMBOL(&at, s);
902 (*(*x)->c_listmethod)(x, 0, 1, &at);
903 }
904 else
905 {
906 t_atom at;
907 SETSYMBOL(&at, s);
908 (*(*x)->c_anymethod)(x, &s_symbol, 1, &at);
909 }
910}
911
912void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
913static void class_nosavefn(t_gobj *z, t_binbuf *b);
914
915 /* handle "list" messages to Pds without explicit list methods defined. */
916static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv)
917{
918 /* a list with one element which is a number can be handled by a
919 "float" method if any is defined; same for "symbol", "pointer". */
920 if (argc == 1)
921 {
922 if (argv->a_type == A_FLOAT &&
923 *(*x)->c_floatmethod != pd_defaultfloat)
924 {
925 (*(*x)->c_floatmethod)(x, argv->a_w.w_float);
926 return;
927 }
928 else if (argv->a_type == A_SYMBOL &&
929 *(*x)->c_symbolmethod != pd_defaultsymbol)
930 {
931 (*(*x)->c_symbolmethod)(x, argv->a_w.w_symbol);
932 return;
933 }
934 else if (argv->a_type == A_POINTER &&
935 *(*x)->c_pointermethod != pd_defaultpointer)
936 {
937 (*(*x)->c_pointermethod)(x, argv->a_w.w_gpointer);
938 return;
939 }
940 }
941 /* Next try for an "anything" method */
942 if ((*x)->c_anymethod != pd_defaultanything)
943 (*(*x)->c_anymethod)(x, &s_list, argc, argv);
944
945 /* if the object is patchable (i.e., can have proper inlets)
946 send it on to obj_list which will unpack the list into the inlets */
947 else if ((*x)->c_patchable)
948 obj_list((t_object *)x, s, argc, argv);
949 /* otherwise gove up and complain. */
950 else pd_defaultanything(x, &s_list, argc, argv);
951}
952
953 /* for now we assume that all "gobjs" are text unless explicitly
954 overridden later by calling class_setbehavior(). I'm not sure
955 how to deal with Pds that aren't gobjs; shouldn't there be a
956 way to check that at run time? Perhaps the presence of a "newmethod"
957 should be our cue, or perhaps the "tiny" flag. */
958
959 /* another matter. This routine does two unrelated things: it creates
960 a Pd class, but also adds a "new" method to create an instance of it.
961 These are combined for historical reasons and for brevity in writing
962 objects. To avoid adding a "new" method send a null function pointer.
963 To add additional ones, use class_addcreator below. Some "classes", like
964 "select", are actually two classes of the same name, one for the single-
965 argument form, one for the multiple one; see select_setup() to find out
966 how this is handled. */
967
968extern t_widgetbehavior text_widgetbehavior;
969extern void text_save(t_gobj *z, t_binbuf *b);
970
971t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod,
972 size_t size, int flags, t_atomtype type1, ...)
973{
974 va_list ap;
975 t_atomtype vec[MAXPDARG+1], *vp = vec;
976 int count = 0;
977 t_class *c;
978 int typeflag = flags & CLASS_TYPEMASK;
979 if (!typeflag) typeflag = CLASS_PATCHABLE;
980 *vp = type1;
981
982 va_start(ap, type1);
983 while (*vp)
984 {
985 if (count == MAXPDARG)
986 {
987 error("class %s: sorry: only %d creation args allowed",
988 s->s_name, MAXPDARG);
989 break;
990 }
991 vp++;
992 count++;
993 *vp = va_arg(ap, t_atomtype);
994 }
995 va_end(ap);
996 if (pd_objectmaker && newmethod)
997 {
998 /* add a "new" method by the name specified by the object */
999 class_addmethod(pd_objectmaker, (t_method)newmethod, s,
1000 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
1001 if (class_loadsym)
1002 {
1003 /* if we're loading an extern it might have been invoked by a
1004 longer file name; in this case, make this an admissible name
1005 too. */
1006 char *loadstring = class_loadsym->s_name,
1007 l1 = strlen(s->s_name), l2 = strlen(loadstring);
1008 if (l2 > l1 && !strcmp(s->s_name, loadstring + (l2 - l1)))
1009 class_addmethod(pd_objectmaker, (t_method)newmethod,
1010 class_loadsym,
1011 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
1012 }
1013 }
1014 c = (t_class *)t_getbytes(sizeof(*c));
1015 c->c_name = c->c_helpname = s;
1016 c->c_size = size;
1017 c->c_methods = t_getbytes(0);
1018 c->c_nmethod = 0;
1019 c->c_freemethod = (t_method)freemethod;
1020 c->c_bangmethod = pd_defaultbang;
1021 c->c_pointermethod = pd_defaultpointer;
1022 c->c_floatmethod = pd_defaultfloat;
1023 c->c_symbolmethod = pd_defaultsymbol;
1024 c->c_listmethod = pd_defaultlist;
1025 c->c_anymethod = pd_defaultanything;
1026 c->c_wb = (typeflag == CLASS_PATCHABLE ? &text_widgetbehavior : 0);
1027 c->c_pwb = 0;
1028 c->c_firstin = ((flags & CLASS_NOINLET) == 0);
1029 c->c_patchable = (typeflag == CLASS_PATCHABLE);
1030 c->c_gobj = (typeflag >= CLASS_GOBJ);
1031 c->c_drawcommand = 0;
1032 c->c_floatsignalin = 0;
1033 c->c_externdir = class_extern_dir;
1034 c->c_savefn = (typeflag == CLASS_PATCHABLE ? text_save : class_nosavefn);
1035#if 0
1036 post("class: %s", c->c_name->s_name);
1037#endif
1038 return (c);
1039}
1040
1041 /* add a creation method, which is a function that returns a Pd object
1042 suitable for putting in an object box. We presume you've got a class it
1043 can belong to, but this won't be used until the newmethod is actually
1044 called back (and the new method explicitly takes care of this.) */
1045
1046void class_addcreator(t_newmethod newmethod, t_symbol *s,
1047 t_atomtype type1, ...)
1048{
1049 va_list ap;
1050 t_atomtype vec[MAXPDARG+1], *vp = vec;
1051 int count = 0;
1052 *vp = type1;
1053
1054 va_start(ap, type1);
1055 while (*vp)
1056 {
1057 if (count == MAXPDARG)
1058 {
1059 error("class %s: sorry: only %d creation args allowed",
1060 s->s_name, MAXPDARG);
1061 break;
1062 }
1063 vp++;
1064 count++;
1065 *vp = va_arg(ap, t_atomtype);
1066 }
1067 va_end(ap);
1068 class_addmethod(pd_objectmaker, (t_method)newmethod, s,
1069 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
1070}
1071
1072void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
1073 t_atomtype arg1, ...)
1074{
1075 va_list ap;
1076 t_methodentry *m;
1077 t_atomtype argtype = arg1;
1078 int nargs;
1079
1080 va_start(ap, arg1);
1081 /* "signal" method specifies that we take audio signals but
1082 that we don't want automatic float to signal conversion. This
1083 is obsolete; you should now use the CLASS_MAINSIGNALIN macro. */
1084 if (sel == &s_signal)
1085 {
1086 if (c->c_floatsignalin)
1087 post("warning: signal method overrides class_mainsignalin");
1088 c->c_floatsignalin = -1;
1089 }
1090 /* check for special cases. "Pointer" is missing here so that
1091 pd_objectmaker's pointer method can be typechecked differently. */
1092 if (sel == &s_bang)
1093 {
1094 if (argtype) goto phooey;
1095 class_addbang(c, fn);
1096 }
1097 else if (sel == &s_float)
1098 {
1099 if (argtype != A_FLOAT || va_arg(ap, t_atomtype)) goto phooey;
1100 class_doaddfloat(c, fn);
1101 }
1102 else if (sel == &s_symbol)
1103 {
1104 if (argtype != A_SYMBOL || va_arg(ap, t_atomtype)) goto phooey;
1105 class_addsymbol(c, fn);
1106 }
1107 else if (sel == &s_list)
1108 {
1109 if (argtype != A_GIMME) goto phooey;
1110 class_addlist(c, fn);
1111 }
1112 else if (sel == &s_anything)
1113 {
1114 if (argtype != A_GIMME) goto phooey;
1115 class_addanything(c, fn);
1116 }
1117 else
1118 {
1119 c->c_methods = t_resizebytes(c->c_methods,
1120 c->c_nmethod * sizeof(*c->c_methods),
1121 (c->c_nmethod + 1) * sizeof(*c->c_methods));
1122 m = c->c_methods + c->c_nmethod;
1123 c->c_nmethod++;
1124 m->me_name = sel;
1125 m->me_fun = (t_gotfn)fn;
1126 nargs = 0;
1127 while (argtype != A_NULL && nargs < MAXPDARG)
1128 {
1129 m->me_arg[nargs++] = argtype;
1130 argtype = va_arg(ap, t_atomtype);
1131 }
1132 if (argtype != A_NULL)
1133 error("%s_%s: only 5 arguments are typecheckable; use A_GIMME",
1134 c->c_name->s_name, sel->s_name);
1135 va_end(ap);
1136 m->me_arg[nargs] = A_NULL;
1137 }
1138 return;
1139phooey:
1140 bug("class_addmethod: %s_%s: bad argument types\n",
1141 c->c_name->s_name, sel->s_name);
1142}
1143
1144 /* Instead of these, see the "class_addfloat", etc., macros in m_pd.h */
1145void class_addbang(t_class *c, t_method fn)
1146{
1147 c->c_bangmethod = (t_bangmethod)fn;
1148}
1149
1150void class_addpointer(t_class *c, t_method fn)
1151{
1152 c->c_pointermethod = (t_pointermethod)fn;
1153}
1154
1155void class_doaddfloat(t_class *c, t_method fn)
1156{
1157 c->c_floatmethod = (t_floatmethod)fn;
1158}
1159
1160void class_addsymbol(t_class *c, t_method fn)
1161{
1162 c->c_symbolmethod = (t_symbolmethod)fn;
1163}
1164
1165void class_addlist(t_class *c, t_method fn)
1166{
1167 c->c_listmethod = (t_listmethod)fn;
1168}
1169
1170void class_addanything(t_class *c, t_method fn)
1171{
1172 c->c_anymethod = (t_anymethod)fn;
1173}
1174
1175void class_setwidget(t_class *c, t_widgetbehavior *w)
1176{
1177 c->c_wb = w;
1178}
1179
1180void class_setparentwidget(t_class *c, t_parentwidgetbehavior *pw)
1181{
1182 c->c_pwb = pw;
1183}
1184
1185char *class_getname(t_class *c)
1186{
1187 return (c->c_name->s_name);
1188}
1189
1190char *class_gethelpname(t_class *c)
1191{
1192 return (c->c_helpname->s_name);
1193}
1194
1195void class_sethelpsymbol(t_class *c, t_symbol *s)
1196{
1197 c->c_helpname = s;
1198}
1199
1200t_parentwidgetbehavior *pd_getparentwidget(t_pd *x)
1201{
1202 return ((*x)->c_pwb);
1203}
1204
1205void class_setdrawcommand(t_class *c)
1206{
1207 c->c_drawcommand = 1;
1208}
1209
1210int class_isdrawcommand(t_class *c)
1211{
1212 return (c->c_drawcommand);
1213}
1214
1215static void pd_floatforsignal(t_pd *x, t_float f)
1216{
1217 int offset = (*x)->c_floatsignalin;
1218 if (offset > 0)
1219 *(t_sample *)(((char *)x) + offset) = ftofix(f);
1220 else
1221 pd_error(x, "%s: float unexpected for signal input",
1222 (*x)->c_name->s_name);
1223}
1224
1225void class_domainsignalin(t_class *c, int onset)
1226{
1227 if (onset <= 0) onset = -1;
1228 else
1229 {
1230 if (c->c_floatmethod != pd_defaultfloat)
1231 post("warning: %s: float method overwritten", c->c_name->s_name);
1232 c->c_floatmethod = (t_floatmethod)pd_floatforsignal;
1233 }
1234 c->c_floatsignalin = onset;
1235}
1236
1237void class_set_extern_dir(t_symbol *s)
1238{
1239 class_extern_dir = s;
1240}
1241
1242char *class_gethelpdir(t_class *c)
1243{
1244 return (c->c_externdir->s_name);
1245}
1246
1247static void class_nosavefn(t_gobj *z, t_binbuf *b)
1248{
1249 bug("save function called but not defined");
1250}
1251
1252void class_setsavefn(t_class *c, t_savefn f)
1253{
1254 c->c_savefn = f;
1255}
1256
1257t_savefn class_getsavefn(t_class *c)
1258{
1259 return (c->c_savefn);
1260}
1261
1262void class_setpropertiesfn(t_class *c, t_propertiesfn f)
1263{
1264 c->c_propertiesfn = f;
1265}
1266
1267t_propertiesfn class_getpropertiesfn(t_class *c)
1268{
1269 return (c->c_propertiesfn);
1270}
1271
1272/* ---------------- the symbol table ------------------------ */
1273
1274#define HASHSIZE 1024
1275
1276static t_symbol *symhash[HASHSIZE];
1277
1278t_symbol *dogensym(char *s, t_symbol *oldsym)
1279{
1280 t_symbol **sym1, *sym2;
1281 unsigned int hash1 = 0, hash2 = 0;
1282 int length = 0;
1283 char *s2 = s;
1284 while (*s2)
1285 {
1286 hash1 += *s2;
1287 hash2 += hash1;
1288 length++;
1289 s2++;
1290 }
1291 sym1 = symhash + (hash2 & (HASHSIZE-1));
1292 while (sym2 = *sym1)
1293 {
1294 if (!strcmp(sym2->s_name, s)) return(sym2);
1295 sym1 = &sym2->s_next;
1296 }
1297 if (oldsym) sym2 = oldsym;
1298 else
1299 {
1300 sym2 = (t_symbol *)t_getbytes(sizeof(*sym2));
1301 sym2->s_name = t_getbytes(length+1);
1302 sym2->s_next = 0;
1303 sym2->s_thing = 0;
1304 strcpy(sym2->s_name, s);
1305 }
1306 *sym1 = sym2;
1307 return (sym2);
1308}
1309
1310t_symbol *gensym(char *s)
1311{
1312 return(dogensym(s, 0));
1313}
1314
1315static t_symbol *addfileextent(t_symbol *s)
1316{
1317 char namebuf[MAXPDSTRING], *str = s->s_name;
1318 int ln = strlen(str);
1319 if (!strcmp(str + ln - 3, ".pd")) return (s);
1320 strcpy(namebuf, str);
1321 strcpy(namebuf+ln, ".pd");
1322 return (gensym(namebuf));
1323}
1324
1325static int tryingalready;
1326
1327void canvas_popabstraction(t_canvas *x);
1328extern t_pd *newest;
1329
1330t_symbol* pathsearch(t_symbol *s,char* ext);
1331int pd_setloadingabstraction(t_symbol *sym);
1332
1333 /* this routine is called when a new "object" is requested whose class Pd
1334 doesn't know. Pd tries to load it as an extern, then as an abstraction. */
1335void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv)
1336{
1337 t_pd *current;
1338 t_symbol *dir = canvas_getcurrentdir();
1339 int fd;
1340 char dirbuf[MAXPDSTRING], *nameptr;
1341 if (tryingalready) return;
1342 newest = 0;
1343 class_loadsym = s;
1344 if (sys_load_lib(dir->s_name, s->s_name))
1345 {
1346 tryingalready = 1;
1347 typedmess(dummy, s, argc, argv);
1348 tryingalready = 0;
1349 return;
1350 }
1351 class_loadsym = 0;
1352 current = s__X.s_thing;
1353 if ((fd = open_via_path(dir->s_name, s->s_name, ".pd",
1354 dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0 ||
1355 (fd = open_via_path(dir->s_name, s->s_name, ".pat",
1356 dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0)
1357 {
1358 close (fd);
1359 if (!pd_setloadingabstraction(s))
1360 {
1361 canvas_setargs(argc, argv); /* bug fix by Krzysztof Czaja */
1362 binbuf_evalfile(gensym(nameptr), gensym(dirbuf));
1363 if (s__X.s_thing != current)
1364 canvas_popabstraction((t_canvas *)(s__X.s_thing));
1365 canvas_setargs(0, 0);
1366 }
1367 else error("%s: can't load abstraction within itself\n", s->s_name);
1368 }
1369 else newest = 0;
1370}
1371
1372t_symbol s_pointer = {"pointer", 0, 0};
1373t_symbol s_float = {"float", 0, 0};
1374t_symbol s_symbol = {"symbol", 0, 0};
1375t_symbol s_bang = {"bang", 0, 0};
1376t_symbol s_list = {"list", 0, 0};
1377t_symbol s_anything = {"anything", 0, 0};
1378t_symbol s_signal = {"signal", 0, 0};
1379t_symbol s__N = {"#N", 0, 0};
1380t_symbol s__X = {"#X", 0, 0};
1381t_symbol s_x = {"x", 0, 0};
1382t_symbol s_y = {"y", 0, 0};
1383t_symbol s_ = {"", 0, 0};
1384
1385static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang,
1386 &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_};
1387
1388void mess_init(void)
1389{
1390 t_symbol **sp;
1391 int i;
1392
1393 if (pd_objectmaker) return;
1394 for (i = sizeof(symlist)/sizeof(*symlist), sp = symlist; i--; sp++)
1395 (void) dogensym((*sp)->s_name, *sp);
1396 pd_objectmaker = class_new(gensym("objectmaker"), 0, 0, sizeof(t_pd),
1397 CLASS_DEFAULT, A_NULL);
1398 pd_canvasmaker = class_new(gensym("classmaker"), 0, 0, sizeof(t_pd),
1399 CLASS_DEFAULT, A_NULL);
1400 pd_bind(&pd_canvasmaker, &s__N);
1401 class_addanything(pd_objectmaker, (t_method)new_anything);
1402}
1403
1404t_pd *newest;
1405
1406/* This is externally available, but note that it might later disappear; the
1407whole "newest" thing is a hack which needs to be redesigned. */
1408t_pd *pd_newest(void)
1409{
1410 return (newest);
1411}
1412
1413 /* horribly, we need prototypes for each of the artificial function
1414 calls in typedmess(), to keep the compiler quiet. */
1415typedef t_pd *(*t_newgimme)(t_symbol *s, int argc, t_atom *argv);
1416typedef void(*t_messgimme)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
1417
1418typedef t_pd *(*t_fun0)(
1419 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1420typedef t_pd *(*t_fun1)(t_int i1,
1421 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1422typedef t_pd *(*t_fun2)(t_int i1, t_int i2,
1423 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1424typedef t_pd *(*t_fun3)(t_int i1, t_int i2, t_int i3,
1425 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1426typedef t_pd *(*t_fun4)(t_int i1, t_int i2, t_int i3, t_int i4,
1427 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1428typedef t_pd *(*t_fun5)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5,
1429 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1430typedef t_pd *(*t_fun6)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, t_int i6,
1431 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
1432
1433void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv)
1434{
1435 t_method *f;
1436 t_class *c = *x;
1437 t_methodentry *m;
1438 t_atomtype *wp, wanttype;
1439 int i;
1440 t_int ai[MAXPDARG+1], *ap = ai;
1441 t_floatarg ad[MAXPDARG+1], *dp = ad;
1442 int narg = 0;
1443 t_pd *bonzo;
1444
1445 /* check for messages that are handled by fixed slots in the class
1446 structure. We don't catch "pointer" though so that sending "pointer"
1447 to pd_objectmaker doesn't require that we supply a pointer value. */
1448 if (s == &s_float)
1449 {
1450 if (!argc) (*c->c_floatmethod)(x, 0.);
1451 else if (argv->a_type == A_FLOAT)
1452 (*c->c_floatmethod)(x, argv->a_w.w_float);
1453 else goto badarg;
1454 return;
1455 }
1456 if (s == &s_bang)
1457 {
1458 (*c->c_bangmethod)(x);
1459 return;
1460 }
1461 if (s == &s_list)
1462 {
1463 (*c->c_listmethod)(x, s, argc, argv);
1464 return;
1465 }
1466 if (s == &s_symbol)
1467 {
1468 if (argc && argv->a_type == A_SYMBOL)
1469 (*c->c_symbolmethod)(x, argv->a_w.w_symbol);
1470 else
1471 (*c->c_symbolmethod)(x, &s_);
1472 return;
1473 }
1474 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
1475 if (m->me_name == s)
1476 {
1477 wp = m->me_arg;
1478 if (*wp == A_GIMME)
1479 {
1480 if (x == &pd_objectmaker)
1481 newest = (*((t_newgimme)(m->me_fun)))(s, argc, argv);
1482 else (*((t_messgimme)(m->me_fun)))(x, s, argc, argv);
1483 return;
1484 }
1485 if (argc > MAXPDARG) argc = MAXPDARG;
1486 if (x != &pd_objectmaker) *(ap++) = (t_int)x, narg++;
1487 while (wanttype = *wp++)
1488 {
1489 switch (wanttype)
1490 {
1491 case A_POINTER:
1492 if (!argc) goto badarg;
1493 else
1494 {
1495 if (argv->a_type == A_POINTER)
1496 *ap = (t_int)(argv->a_w.w_gpointer);
1497 else goto badarg;
1498 argc--;
1499 argv++;
1500 }
1501 narg++;
1502 ap++;
1503 break;
1504 case A_FLOAT:
1505 if (!argc) goto badarg;
1506 case A_DEFFLOAT:
1507 if (!argc) *dp = 0;
1508 else
1509 {
1510 if (argv->a_type == A_FLOAT)
1511 *dp = argv->a_w.w_float;
1512 else goto badarg;
1513 argc--;
1514 argv++;
1515 }
1516 dp++;
1517 break;
1518 case A_SYMBOL:
1519 if (!argc) goto badarg;
1520 case A_DEFSYM:
1521 if (!argc) *ap = (t_int)(&s_);
1522 else
1523 {
1524 if (argv->a_type == A_SYMBOL)
1525 *ap = (t_int)(argv->a_w.w_symbol);
1526 /* if it's an unfilled "dollar" argument it appears
1527 as zero here; cheat and bash it to the null
1528 symbol. Unfortunately, this lets real zeros
1529 pass as symbols too, which seems wrong... */
1530 else if (x == &pd_objectmaker && argv->a_type == A_FLOAT
1531 && argv->a_w.w_float == 0)
1532 *ap = (t_int)(&s_);
1533 else goto badarg;
1534 argc--;
1535 argv++;
1536 }
1537 narg++;
1538 ap++;
1539 }
1540 }
1541 switch (narg)
1542 {
1543 case 0 : bonzo = (*(t_fun0)(m->me_fun))
1544 (ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1545 case 1 : bonzo = (*(t_fun1)(m->me_fun))
1546 (ai[0], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1547 case 2 : bonzo = (*(t_fun2)(m->me_fun))
1548 (ai[0], ai[1], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1549 case 3 : bonzo = (*(t_fun3)(m->me_fun))
1550 (ai[0], ai[1], ai[2], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1551 case 4 : bonzo = (*(t_fun4)(m->me_fun))
1552 (ai[0], ai[1], ai[2], ai[3],
1553 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1554 case 5 : bonzo = (*(t_fun5)(m->me_fun))
1555 (ai[0], ai[1], ai[2], ai[3], ai[4],
1556 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1557 case 6 : bonzo = (*(t_fun6)(m->me_fun))
1558 (ai[0], ai[1], ai[2], ai[3], ai[4], ai[5],
1559 ad[0], ad[1], ad[2], ad[3], ad[4]); break;
1560 default: bonzo = 0;
1561 }
1562 if (x == &pd_objectmaker)
1563 newest = bonzo;
1564 return;
1565 }
1566 (*c->c_anymethod)(x, s, argc, argv);
1567 return;
1568badarg:
1569 pd_error(x, "Bad arguments for message '%s' to object '%s'",
1570 s->s_name, c->c_name->s_name);
1571}
1572
1573void pd_vmess(t_pd *x, t_symbol *sel, char *fmt, ...)
1574{
1575 va_list ap;
1576 t_atom arg[MAXPDARG], *at =arg;
1577 int nargs = 0;
1578 char *fp = fmt;
1579
1580 va_start(ap, fmt);
1581 while (1)
1582 {
1583 if (nargs > MAXPDARG)
1584 {
1585 pd_error(x, "pd_vmess: only %d allowed", MAXPDARG);
1586 break;
1587 }
1588 switch(*fp++)
1589 {
1590 case 'f': SETFLOAT(at, va_arg(ap, double)); break;
1591 case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
1592 case 'i': SETFLOAT(at, va_arg(ap, t_int)); break;
1593 case 'p': SETPOINTER(at, va_arg(ap, t_gpointer *)); break;
1594 default: goto done;
1595 }
1596 at++;
1597 nargs++;
1598 }
1599done:
1600 va_end(ap);
1601 typedmess(x, sel, nargs, arg);
1602}
1603
1604void pd_forwardmess(t_pd *x, int argc, t_atom *argv)
1605{
1606 if (argc)
1607 {
1608 t_atomtype t = argv->a_type;
1609 if (t == A_SYMBOL) pd_typedmess(x, argv->a_w.w_symbol, argc-1, argv+1);
1610 else if (t == A_POINTER)
1611 {
1612 if (argc == 1) pd_pointer(x, argv->a_w.w_gpointer);
1613 else pd_list(x, &s_list, argc, argv);
1614 }
1615 else if (t == A_FLOAT)
1616 {
1617 if (argc == 1) pd_float(x, argv->a_w.w_float);
1618 else pd_list(x, &s_list, argc, argv);
1619 }
1620 else bug("pd_forwardmess");
1621 }
1622
1623}
1624
1625void nullfn(void) {}
1626
1627t_gotfn getfn(t_pd *x, t_symbol *s)
1628{
1629 t_class *c = *x;
1630 t_methodentry *m;
1631 int i;
1632
1633 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
1634 if (m->me_name == s) return(m->me_fun);
1635 pd_error(x, "%s: no method for message '%s'", c->c_name->s_name, s->s_name);
1636 return((t_gotfn)nullfn);
1637}
1638
1639t_gotfn zgetfn(t_pd *x, t_symbol *s)
1640{
1641 t_class *c = *x;
1642 t_methodentry *m;
1643 int i;
1644
1645 for (i = c->c_nmethod, m = c->c_methods; i--; m++)
1646 if (m->me_name == s) return(m->me_fun);
1647 return(0);
1648}