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. */
20 static t_symbol
*class_loadsym
; /* name under which an extern is invoked */
21 static void pd_defaultfloat(t_pd
*x
, t_float f
);
22 static void pd_defaultlist(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
);
23 t_pd pd_objectmaker
; /* factory for creating "object" boxes */
24 t_pd pd_canvasmaker
; /* factory for creating canvases */
26 static t_symbol
*class_extern_dir
= &s_
;
28 static void pd_defaultanything(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
30 pd_error(x
, "%s: no method for '%s'", (*x
)->c_name
->s_name
, s
->s_name
);
33 static void pd_defaultbang(t_pd
*x
)
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);
40 static void pd_defaultpointer(t_pd
*x
, t_gpointer
*gp
)
42 if (*(*x
)->c_listmethod
!= pd_defaultlist
)
46 (*(*x
)->c_listmethod
)(x
, 0, 1, &at
);
52 (*(*x
)->c_anymethod
)(x
, &s_pointer
, 1, &at
);
56 static void pd_defaultfloat(t_pd
*x
, t_float f
)
58 if (*(*x
)->c_listmethod
!= pd_defaultlist
)
62 (*(*x
)->c_listmethod
)(x
, 0, 1, &at
);
68 (*(*x
)->c_anymethod
)(x
, &s_float
, 1, &at
);
72 static void pd_defaultsymbol(t_pd
*x
, t_symbol
*s
)
74 if (*(*x
)->c_listmethod
!= pd_defaultlist
)
78 (*(*x
)->c_listmethod
)(x
, 0, 1, &at
);
84 (*(*x
)->c_anymethod
)(x
, &s_symbol
, 1, &at
);
88 void obj_list(t_object
*x
, t_symbol
*s
, int argc
, t_atom
*argv
);
89 static void class_nosavefn(t_gobj
*z
, t_binbuf
*b
);
91 /* handle "list" messages to Pds without explicit list methods defined. */
92 static void pd_defaultlist(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
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". */
98 if (argv
->a_type
== A_FLOAT
&&
99 *(*x
)->c_floatmethod
!= pd_defaultfloat
)
101 (*(*x
)->c_floatmethod
)(x
, argv
->a_w
.w_float
);
104 else if (argv
->a_type
== A_SYMBOL
&&
105 *(*x
)->c_symbolmethod
!= pd_defaultsymbol
)
107 (*(*x
)->c_symbolmethod
)(x
, argv
->a_w
.w_symbol
);
110 else if (argv
->a_type
== A_POINTER
&&
111 *(*x
)->c_pointermethod
!= pd_defaultpointer
)
113 (*(*x
)->c_pointermethod
)(x
, argv
->a_w
.w_gpointer
);
117 /* Next try for an "anything" method */
118 if ((*x
)->c_anymethod
!= pd_defaultanything
)
119 (*(*x
)->c_anymethod
)(x
, &s_list
, argc
, argv
);
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
);
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. */
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. */
144 extern t_widgetbehavior text_widgetbehavior
;
145 extern void text_save(t_gobj
*z
, t_binbuf
*b
);
147 t_class
*class_new(t_symbol
*s
, t_newmethod newmethod
, t_method freemethod
,
148 size_t size
, int flags
, t_atomtype type1
, ...)
151 t_atomtype vec
[MAXPDARG
+1], *vp
= vec
;
154 int typeflag
= flags
& CLASS_TYPEMASK
;
155 if (!typeflag
) typeflag
= CLASS_PATCHABLE
;
161 if (count
== MAXPDARG
)
163 error("class %s: sorry: only %d creation args allowed",
164 s
->s_name
, MAXPDARG
);
169 *vp
= va_arg(ap
, t_atomtype
);
172 if (pd_objectmaker
&& newmethod
)
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]);
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
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
,
187 vec
[0], vec
[1], vec
[2], vec
[3], vec
[4], vec
[5]);
190 c
= (t_class
*)t_getbytes(sizeof(*c
));
191 c
->c_name
= c
->c_helpname
= s
;
193 c
->c_methods
= t_getbytes(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);
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
);
212 post("class: %s", c
->c_name
->s_name
);
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.) */
222 void class_addcreator(t_newmethod newmethod
, t_symbol
*s
,
223 t_atomtype type1
, ...)
226 t_atomtype vec
[MAXPDARG
+1], *vp
= vec
;
233 if (count
== MAXPDARG
)
235 error("class %s: sorry: only %d creation args allowed",
236 s
->s_name
, MAXPDARG
);
241 *vp
= va_arg(ap
, t_atomtype
);
244 class_addmethod(pd_objectmaker
, (t_method
)newmethod
, s
,
245 vec
[0], vec
[1], vec
[2], vec
[3], vec
[4], vec
[5]);
248 void class_addmethod(t_class
*c
, t_method fn
, t_symbol
*sel
,
249 t_atomtype arg1
, ...)
253 t_atomtype argtype
= 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
)
262 if (c
->c_floatsignalin
)
263 post("warning: signal method overrides class_mainsignalin");
264 c
->c_floatsignalin
= -1;
266 /* check for special cases. "Pointer" is missing here so that
267 pd_objectmaker's pointer method can be typechecked differently. */
270 if (argtype
) goto phooey
;
271 class_addbang(c
, fn
);
273 else if (sel
== &s_float
)
275 if (argtype
!= A_FLOAT
|| va_arg(ap
, t_atomtype
)) goto phooey
;
276 class_doaddfloat(c
, fn
);
278 else if (sel
== &s_symbol
)
280 if (argtype
!= A_SYMBOL
|| va_arg(ap
, t_atomtype
)) goto phooey
;
281 class_addsymbol(c
, fn
);
283 else if (sel
== &s_list
)
285 if (argtype
!= A_GIMME
) goto phooey
;
286 class_addlist(c
, fn
);
288 else if (sel
== &s_anything
)
290 if (argtype
!= A_GIMME
) goto phooey
;
291 class_addanything(c
, fn
);
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
;
301 m
->me_fun
= (t_gotfn
)fn
;
303 while (argtype
!= A_NULL
&& nargs
< MAXPDARG
)
305 m
->me_arg
[nargs
++] = argtype
;
306 argtype
= va_arg(ap
, t_atomtype
);
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
);
312 m
->me_arg
[nargs
] = A_NULL
;
316 bug("class_addmethod: %s_%s: bad argument types\n",
317 c
->c_name
->s_name
, sel
->s_name
);
320 /* Instead of these, see the "class_addfloat", etc., macros in m_pd.h */
321 void class_addbang(t_class
*c
, t_method fn
)
323 c
->c_bangmethod
= (t_bangmethod
)fn
;
326 void class_addpointer(t_class
*c
, t_method fn
)
328 c
->c_pointermethod
= (t_pointermethod
)fn
;
331 void class_doaddfloat(t_class
*c
, t_method fn
)
333 c
->c_floatmethod
= (t_floatmethod
)fn
;
336 void class_addsymbol(t_class
*c
, t_method fn
)
338 c
->c_symbolmethod
= (t_symbolmethod
)fn
;
341 void class_addlist(t_class
*c
, t_method fn
)
343 c
->c_listmethod
= (t_listmethod
)fn
;
346 void class_addanything(t_class
*c
, t_method fn
)
348 c
->c_anymethod
= (t_anymethod
)fn
;
351 void class_setwidget(t_class
*c
, t_widgetbehavior
*w
)
356 void class_setparentwidget(t_class
*c
, t_parentwidgetbehavior
*pw
)
361 char *class_getname(t_class
*c
)
363 return (c
->c_name
->s_name
);
366 char *class_gethelpname(t_class
*c
)
368 return (c
->c_helpname
->s_name
);
371 void class_sethelpsymbol(t_class
*c
, t_symbol
*s
)
376 t_parentwidgetbehavior
*pd_getparentwidget(t_pd
*x
)
378 return ((*x
)->c_pwb
);
381 void class_setdrawcommand(t_class
*c
)
383 c
->c_drawcommand
= 1;
386 int class_isdrawcommand(t_class
*c
)
388 return (c
->c_drawcommand
);
391 static void pd_floatforsignal(t_pd
*x
, t_float f
)
393 int offset
= (*x
)->c_floatsignalin
;
395 *(t_sample
*)(((char *)x
) + offset
) = ftofix(f
);
397 pd_error(x
, "%s: float unexpected for signal input",
398 (*x
)->c_name
->s_name
);
401 void class_domainsignalin(t_class
*c
, int onset
)
403 if (onset
<= 0) onset
= -1;
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
;
410 c
->c_floatsignalin
= onset
;
413 void class_set_extern_dir(t_symbol
*s
)
415 class_extern_dir
= s
;
418 char *class_gethelpdir(t_class
*c
)
420 return (c
->c_externdir
->s_name
);
423 static void class_nosavefn(t_gobj
*z
, t_binbuf
*b
)
425 bug("save function called but not defined");
428 void class_setsavefn(t_class
*c
, t_savefn f
)
433 t_savefn
class_getsavefn(t_class
*c
)
435 return (c
->c_savefn
);
438 void class_setpropertiesfn(t_class
*c
, t_propertiesfn f
)
440 c
->c_propertiesfn
= f
;
443 t_propertiesfn
class_getpropertiesfn(t_class
*c
)
445 return (c
->c_propertiesfn
);
448 /* ---------------- the symbol table ------------------------ */
450 #define HASHSIZE 1024
452 static t_symbol
*symhash
[HASHSIZE
];
454 t_symbol
*dogensym(char *s
, t_symbol
*oldsym
)
456 t_symbol
**sym1
, *sym2
;
457 unsigned int hash1
= 0, hash2
= 0;
467 sym1
= symhash
+ (hash2
& (HASHSIZE
-1));
470 if (!strcmp(sym2
->s_name
, s
)) return(sym2
);
471 sym1
= &sym2
->s_next
;
473 if (oldsym
) sym2
= oldsym
;
476 sym2
= (t_symbol
*)t_getbytes(sizeof(*sym2
));
477 sym2
->s_name
= t_getbytes(length
+1);
480 strcpy(sym2
->s_name
, s
);
486 t_symbol
*gensym(char *s
)
488 return(dogensym(s
, 0));
491 static t_symbol
*addfileextent(t_symbol
*s
)
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
));
501 static int tryingalready
;
503 void canvas_popabstraction(t_canvas
*x
);
506 t_symbol
* pathsearch(t_symbol
*s
,char* ext
);
507 int pd_setloadingabstraction(t_symbol
*sym
);
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. */
511 void new_anything(void *dummy
, t_symbol
*s
, int argc
, t_atom
*argv
)
514 t_symbol
*dir
= canvas_getcurrentdir();
516 char dirbuf
[MAXPDSTRING
], *nameptr
;
517 if (tryingalready
) return;
520 if (sys_load_lib(dir
->s_name
, s
->s_name
))
523 typedmess(dummy
, s
, argc
, argv
);
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)
535 if (!pd_setloadingabstraction(s
))
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);
543 else error("%s: can't load abstraction within itself\n", s
->s_name
);
548 t_symbol s_pointer
= {"pointer", 0, 0};
549 t_symbol s_float
= {"float", 0, 0};
550 t_symbol s_symbol
= {"symbol", 0, 0};
551 t_symbol s_bang
= {"bang", 0, 0};
552 t_symbol s_list
= {"list", 0, 0};
553 t_symbol s_anything
= {"anything", 0, 0};
554 t_symbol s_signal
= {"signal", 0, 0};
555 t_symbol s__N
= {"#N", 0, 0};
556 t_symbol s__X
= {"#X", 0, 0};
557 t_symbol s_x
= {"x", 0, 0};
558 t_symbol s_y
= {"y", 0, 0};
559 t_symbol s_
= {"", 0, 0};
561 static 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_
};
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
);
582 /* This is externally available, but note that it might later disappear; the
583 whole "newest" thing is a hack which needs to be redesigned. */
584 t_pd
*pd_newest(void)
589 /* horribly, we need prototypes for each of the artificial function
590 calls in typedmess(), to keep the compiler quiet. */
591 typedef t_pd
*(*t_newgimme
)(t_symbol
*s
, int argc
, t_atom
*argv
);
592 typedef void(*t_messgimme
)(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
);
594 typedef t_pd
*(*t_fun0
)(
595 t_floatarg d1
, t_floatarg d2
, t_floatarg d3
, t_floatarg d4
, t_floatarg d5
);
596 typedef t_pd
*(*t_fun1
)(t_int i1
,
597 t_floatarg d1
, t_floatarg d2
, t_floatarg d3
, t_floatarg d4
, t_floatarg d5
);
598 typedef 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
);
600 typedef 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
);
602 typedef 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
);
604 typedef 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
);
606 typedef 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
);
609 void pd_typedmess(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
614 t_atomtype
*wp
, wanttype
;
616 t_int ai
[MAXPDARG
+1], *ap
= ai
;
617 t_floatarg ad
[MAXPDARG
+1], *dp
= ad
;
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. */
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
);
634 (*c
->c_bangmethod
)(x
);
639 (*c
->c_listmethod
)(x
, s
, argc
, argv
);
644 if (argc
&& argv
->a_type
== A_SYMBOL
)
645 (*c
->c_symbolmethod
)(x
, argv
->a_w
.w_symbol
);
647 (*c
->c_symbolmethod
)(x
, &s_
);
650 for (i
= c
->c_nmethod
, m
= c
->c_methods
; i
--; m
++)
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
);
661 if (argc
> MAXPDARG
) argc
= MAXPDARG
;
662 if (x
!= &pd_objectmaker
) *(ap
++) = (t_int
)x
, narg
++;
663 while (wanttype
= *wp
++)
668 if (!argc
) goto badarg
;
671 if (argv
->a_type
== A_POINTER
)
672 *ap
= (t_int
)(argv
->a_w
.w_gpointer
);
681 if (!argc
) goto badarg
;
686 if (argv
->a_type
== A_FLOAT
)
687 *dp
= argv
->a_w
.w_float
;
695 if (!argc
) goto badarg
;
697 if (!argc
) *ap
= (t_int
)(&s_
);
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)
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;
738 if (x
== &pd_objectmaker
)
742 (*c
->c_anymethod
)(x
, s
, argc
, argv
);
745 pd_error(x
, "Bad arguments for message '%s' to object '%s'",
746 s
->s_name
, c
->c_name
->s_name
);
749 void pd_vmess(t_pd
*x
, t_symbol
*sel
, char *fmt
, ...)
752 t_atom arg
[MAXPDARG
], *at
=arg
;
759 if (nargs
> MAXPDARG
)
761 pd_error(x
, "pd_vmess: only %d allowed", MAXPDARG
);
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;
777 typedmess(x
, sel
, nargs
, arg
);
780 void pd_forwardmess(t_pd
*x
, int argc
, t_atom
*argv
)
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
)
788 if (argc
== 1) pd_pointer(x
, argv
->a_w
.w_gpointer
);
789 else pd_list(x
, &s_list
, argc
, argv
);
791 else if (t
== A_FLOAT
)
793 if (argc
== 1) pd_float(x
, argv
->a_w
.w_float
);
794 else pd_list(x
, &s_list
, argc
, argv
);
796 else bug("pd_forwardmess");
803 t_gotfn
getfn(t_pd
*x
, t_symbol
*s
)
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
);
815 t_gotfn
zgetfn(t_pd
*x
, t_symbol
*s
)
821 for (i
= c
->c_nmethod
, m
= c
->c_methods
; i
--; m
++)
822 if (m
->me_name
== s
) return(m
->me_fun
);
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. */
844 static t_symbol
*class_loadsym
; /* name under which an extern is invoked */
845 static void pd_defaultfloat(t_pd
*x
, t_float f
);
846 static void pd_defaultlist(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
);
847 t_pd pd_objectmaker
; /* factory for creating "object" boxes */
848 t_pd pd_canvasmaker
; /* factory for creating canvases */
850 static t_symbol
*class_extern_dir
= &s_
;
852 static void pd_defaultanything(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
854 pd_error(x
, "%s: no method for '%s'", (*x
)->c_name
->s_name
, s
->s_name
);
857 static void pd_defaultbang(t_pd
*x
)
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);
864 static void pd_defaultpointer(t_pd
*x
, t_gpointer
*gp
)
866 if (*(*x
)->c_listmethod
!= pd_defaultlist
)
870 (*(*x
)->c_listmethod
)(x
, 0, 1, &at
);
876 (*(*x
)->c_anymethod
)(x
, &s_pointer
, 1, &at
);
880 static void pd_defaultfloat(t_pd
*x
, t_float f
)
882 if (*(*x
)->c_listmethod
!= pd_defaultlist
)
886 (*(*x
)->c_listmethod
)(x
, 0, 1, &at
);
892 (*(*x
)->c_anymethod
)(x
, &s_float
, 1, &at
);
896 static void pd_defaultsymbol(t_pd
*x
, t_symbol
*s
)
898 if (*(*x
)->c_listmethod
!= pd_defaultlist
)
902 (*(*x
)->c_listmethod
)(x
, 0, 1, &at
);
908 (*(*x
)->c_anymethod
)(x
, &s_symbol
, 1, &at
);
912 void obj_list(t_object
*x
, t_symbol
*s
, int argc
, t_atom
*argv
);
913 static void class_nosavefn(t_gobj
*z
, t_binbuf
*b
);
915 /* handle "list" messages to Pds without explicit list methods defined. */
916 static void pd_defaultlist(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
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". */
922 if (argv
->a_type
== A_FLOAT
&&
923 *(*x
)->c_floatmethod
!= pd_defaultfloat
)
925 (*(*x
)->c_floatmethod
)(x
, argv
->a_w
.w_float
);
928 else if (argv
->a_type
== A_SYMBOL
&&
929 *(*x
)->c_symbolmethod
!= pd_defaultsymbol
)
931 (*(*x
)->c_symbolmethod
)(x
, argv
->a_w
.w_symbol
);
934 else if (argv
->a_type
== A_POINTER
&&
935 *(*x
)->c_pointermethod
!= pd_defaultpointer
)
937 (*(*x
)->c_pointermethod
)(x
, argv
->a_w
.w_gpointer
);
941 /* Next try for an "anything" method */
942 if ((*x
)->c_anymethod
!= pd_defaultanything
)
943 (*(*x
)->c_anymethod
)(x
, &s_list
, argc
, argv
);
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
);
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. */
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. */
968 extern t_widgetbehavior text_widgetbehavior
;
969 extern void text_save(t_gobj
*z
, t_binbuf
*b
);
971 t_class
*class_new(t_symbol
*s
, t_newmethod newmethod
, t_method freemethod
,
972 size_t size
, int flags
, t_atomtype type1
, ...)
975 t_atomtype vec
[MAXPDARG
+1], *vp
= vec
;
978 int typeflag
= flags
& CLASS_TYPEMASK
;
979 if (!typeflag
) typeflag
= CLASS_PATCHABLE
;
985 if (count
== MAXPDARG
)
987 error("class %s: sorry: only %d creation args allowed",
988 s
->s_name
, MAXPDARG
);
993 *vp
= va_arg(ap
, t_atomtype
);
996 if (pd_objectmaker
&& newmethod
)
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]);
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
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
,
1011 vec
[0], vec
[1], vec
[2], vec
[3], vec
[4], vec
[5]);
1014 c
= (t_class
*)t_getbytes(sizeof(*c
));
1015 c
->c_name
= c
->c_helpname
= s
;
1017 c
->c_methods
= t_getbytes(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);
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
);
1036 post("class: %s", c
->c_name
->s_name
);
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.) */
1046 void class_addcreator(t_newmethod newmethod
, t_symbol
*s
,
1047 t_atomtype type1
, ...)
1050 t_atomtype vec
[MAXPDARG
+1], *vp
= vec
;
1054 va_start(ap
, type1
);
1057 if (count
== MAXPDARG
)
1059 error("class %s: sorry: only %d creation args allowed",
1060 s
->s_name
, MAXPDARG
);
1065 *vp
= va_arg(ap
, t_atomtype
);
1068 class_addmethod(pd_objectmaker
, (t_method
)newmethod
, s
,
1069 vec
[0], vec
[1], vec
[2], vec
[3], vec
[4], vec
[5]);
1072 void class_addmethod(t_class
*c
, t_method fn
, t_symbol
*sel
,
1073 t_atomtype arg1
, ...)
1077 t_atomtype argtype
= 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
)
1086 if (c
->c_floatsignalin
)
1087 post("warning: signal method overrides class_mainsignalin");
1088 c
->c_floatsignalin
= -1;
1090 /* check for special cases. "Pointer" is missing here so that
1091 pd_objectmaker's pointer method can be typechecked differently. */
1094 if (argtype
) goto phooey
;
1095 class_addbang(c
, fn
);
1097 else if (sel
== &s_float
)
1099 if (argtype
!= A_FLOAT
|| va_arg(ap
, t_atomtype
)) goto phooey
;
1100 class_doaddfloat(c
, fn
);
1102 else if (sel
== &s_symbol
)
1104 if (argtype
!= A_SYMBOL
|| va_arg(ap
, t_atomtype
)) goto phooey
;
1105 class_addsymbol(c
, fn
);
1107 else if (sel
== &s_list
)
1109 if (argtype
!= A_GIMME
) goto phooey
;
1110 class_addlist(c
, fn
);
1112 else if (sel
== &s_anything
)
1114 if (argtype
!= A_GIMME
) goto phooey
;
1115 class_addanything(c
, fn
);
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
;
1125 m
->me_fun
= (t_gotfn
)fn
;
1127 while (argtype
!= A_NULL
&& nargs
< MAXPDARG
)
1129 m
->me_arg
[nargs
++] = argtype
;
1130 argtype
= va_arg(ap
, t_atomtype
);
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
);
1136 m
->me_arg
[nargs
] = A_NULL
;
1140 bug("class_addmethod: %s_%s: bad argument types\n",
1141 c
->c_name
->s_name
, sel
->s_name
);
1144 /* Instead of these, see the "class_addfloat", etc., macros in m_pd.h */
1145 void class_addbang(t_class
*c
, t_method fn
)
1147 c
->c_bangmethod
= (t_bangmethod
)fn
;
1150 void class_addpointer(t_class
*c
, t_method fn
)
1152 c
->c_pointermethod
= (t_pointermethod
)fn
;
1155 void class_doaddfloat(t_class
*c
, t_method fn
)
1157 c
->c_floatmethod
= (t_floatmethod
)fn
;
1160 void class_addsymbol(t_class
*c
, t_method fn
)
1162 c
->c_symbolmethod
= (t_symbolmethod
)fn
;
1165 void class_addlist(t_class
*c
, t_method fn
)
1167 c
->c_listmethod
= (t_listmethod
)fn
;
1170 void class_addanything(t_class
*c
, t_method fn
)
1172 c
->c_anymethod
= (t_anymethod
)fn
;
1175 void class_setwidget(t_class
*c
, t_widgetbehavior
*w
)
1180 void class_setparentwidget(t_class
*c
, t_parentwidgetbehavior
*pw
)
1185 char *class_getname(t_class
*c
)
1187 return (c
->c_name
->s_name
);
1190 char *class_gethelpname(t_class
*c
)
1192 return (c
->c_helpname
->s_name
);
1195 void class_sethelpsymbol(t_class
*c
, t_symbol
*s
)
1200 t_parentwidgetbehavior
*pd_getparentwidget(t_pd
*x
)
1202 return ((*x
)->c_pwb
);
1205 void class_setdrawcommand(t_class
*c
)
1207 c
->c_drawcommand
= 1;
1210 int class_isdrawcommand(t_class
*c
)
1212 return (c
->c_drawcommand
);
1215 static void pd_floatforsignal(t_pd
*x
, t_float f
)
1217 int offset
= (*x
)->c_floatsignalin
;
1219 *(t_sample
*)(((char *)x
) + offset
) = ftofix(f
);
1221 pd_error(x
, "%s: float unexpected for signal input",
1222 (*x
)->c_name
->s_name
);
1225 void class_domainsignalin(t_class
*c
, int onset
)
1227 if (onset
<= 0) onset
= -1;
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
;
1234 c
->c_floatsignalin
= onset
;
1237 void class_set_extern_dir(t_symbol
*s
)
1239 class_extern_dir
= s
;
1242 char *class_gethelpdir(t_class
*c
)
1244 return (c
->c_externdir
->s_name
);
1247 static void class_nosavefn(t_gobj
*z
, t_binbuf
*b
)
1249 bug("save function called but not defined");
1252 void class_setsavefn(t_class
*c
, t_savefn f
)
1257 t_savefn
class_getsavefn(t_class
*c
)
1259 return (c
->c_savefn
);
1262 void class_setpropertiesfn(t_class
*c
, t_propertiesfn f
)
1264 c
->c_propertiesfn
= f
;
1267 t_propertiesfn
class_getpropertiesfn(t_class
*c
)
1269 return (c
->c_propertiesfn
);
1272 /* ---------------- the symbol table ------------------------ */
1274 #define HASHSIZE 1024
1276 static t_symbol
*symhash
[HASHSIZE
];
1278 t_symbol
*dogensym(char *s
, t_symbol
*oldsym
)
1280 t_symbol
**sym1
, *sym2
;
1281 unsigned int hash1
= 0, hash2
= 0;
1291 sym1
= symhash
+ (hash2
& (HASHSIZE
-1));
1292 while (sym2
= *sym1
)
1294 if (!strcmp(sym2
->s_name
, s
)) return(sym2
);
1295 sym1
= &sym2
->s_next
;
1297 if (oldsym
) sym2
= oldsym
;
1300 sym2
= (t_symbol
*)t_getbytes(sizeof(*sym2
));
1301 sym2
->s_name
= t_getbytes(length
+1);
1304 strcpy(sym2
->s_name
, s
);
1310 t_symbol
*gensym(char *s
)
1312 return(dogensym(s
, 0));
1315 static t_symbol
*addfileextent(t_symbol
*s
)
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
));
1325 static int tryingalready
;
1327 void canvas_popabstraction(t_canvas
*x
);
1328 extern t_pd
*newest
;
1330 t_symbol
* pathsearch(t_symbol
*s
,char* ext
);
1331 int pd_setloadingabstraction(t_symbol
*sym
);
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. */
1335 void new_anything(void *dummy
, t_symbol
*s
, int argc
, t_atom
*argv
)
1338 t_symbol
*dir
= canvas_getcurrentdir();
1340 char dirbuf
[MAXPDSTRING
], *nameptr
;
1341 if (tryingalready
) return;
1344 if (sys_load_lib(dir
->s_name
, s
->s_name
))
1347 typedmess(dummy
, s
, argc
, argv
);
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)
1359 if (!pd_setloadingabstraction(s
))
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);
1367 else error("%s: can't load abstraction within itself\n", s
->s_name
);
1372 t_symbol s_pointer
= {"pointer", 0, 0};
1373 t_symbol s_float
= {"float", 0, 0};
1374 t_symbol s_symbol
= {"symbol", 0, 0};
1375 t_symbol s_bang
= {"bang", 0, 0};
1376 t_symbol s_list
= {"list", 0, 0};
1377 t_symbol s_anything
= {"anything", 0, 0};
1378 t_symbol s_signal
= {"signal", 0, 0};
1379 t_symbol s__N
= {"#N", 0, 0};
1380 t_symbol s__X
= {"#X", 0, 0};
1381 t_symbol s_x
= {"x", 0, 0};
1382 t_symbol s_y
= {"y", 0, 0};
1383 t_symbol s_
= {"", 0, 0};
1385 static 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_
};
1388 void mess_init(void)
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
);
1406 /* This is externally available, but note that it might later disappear; the
1407 whole "newest" thing is a hack which needs to be redesigned. */
1408 t_pd
*pd_newest(void)
1413 /* horribly, we need prototypes for each of the artificial function
1414 calls in typedmess(), to keep the compiler quiet. */
1415 typedef t_pd
*(*t_newgimme
)(t_symbol
*s
, int argc
, t_atom
*argv
);
1416 typedef void(*t_messgimme
)(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
);
1418 typedef t_pd
*(*t_fun0
)(
1419 t_floatarg d1
, t_floatarg d2
, t_floatarg d3
, t_floatarg d4
, t_floatarg d5
);
1420 typedef t_pd
*(*t_fun1
)(t_int i1
,
1421 t_floatarg d1
, t_floatarg d2
, t_floatarg d3
, t_floatarg d4
, t_floatarg d5
);
1422 typedef 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
);
1424 typedef 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
);
1426 typedef 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
);
1428 typedef 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
);
1430 typedef 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
);
1433 void pd_typedmess(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
1438 t_atomtype
*wp
, wanttype
;
1440 t_int ai
[MAXPDARG
+1], *ap
= ai
;
1441 t_floatarg ad
[MAXPDARG
+1], *dp
= ad
;
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. */
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
);
1458 (*c
->c_bangmethod
)(x
);
1463 (*c
->c_listmethod
)(x
, s
, argc
, argv
);
1468 if (argc
&& argv
->a_type
== A_SYMBOL
)
1469 (*c
->c_symbolmethod
)(x
, argv
->a_w
.w_symbol
);
1471 (*c
->c_symbolmethod
)(x
, &s_
);
1474 for (i
= c
->c_nmethod
, m
= c
->c_methods
; i
--; m
++)
1475 if (m
->me_name
== s
)
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
);
1485 if (argc
> MAXPDARG
) argc
= MAXPDARG
;
1486 if (x
!= &pd_objectmaker
) *(ap
++) = (t_int
)x
, narg
++;
1487 while (wanttype
= *wp
++)
1492 if (!argc
) goto badarg
;
1495 if (argv
->a_type
== A_POINTER
)
1496 *ap
= (t_int
)(argv
->a_w
.w_gpointer
);
1505 if (!argc
) goto badarg
;
1510 if (argv
->a_type
== A_FLOAT
)
1511 *dp
= argv
->a_w
.w_float
;
1519 if (!argc
) goto badarg
;
1521 if (!argc
) *ap
= (t_int
)(&s_
);
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)
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;
1562 if (x
== &pd_objectmaker
)
1566 (*c
->c_anymethod
)(x
, s
, argc
, argv
);
1569 pd_error(x
, "Bad arguments for message '%s' to object '%s'",
1570 s
->s_name
, c
->c_name
->s_name
);
1573 void pd_vmess(t_pd
*x
, t_symbol
*sel
, char *fmt
, ...)
1576 t_atom arg
[MAXPDARG
], *at
=arg
;
1583 if (nargs
> MAXPDARG
)
1585 pd_error(x
, "pd_vmess: only %d allowed", MAXPDARG
);
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;
1601 typedmess(x
, sel
, nargs
, arg
);
1604 void pd_forwardmess(t_pd
*x
, int argc
, t_atom
*argv
)
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
)
1612 if (argc
== 1) pd_pointer(x
, argv
->a_w
.w_gpointer
);
1613 else pd_list(x
, &s_list
, argc
, argv
);
1615 else if (t
== A_FLOAT
)
1617 if (argc
== 1) pd_float(x
, argv
->a_w
.w_float
);
1618 else pd_list(x
, &s_list
, argc
, argv
);
1620 else bug("pd_forwardmess");
1625 void nullfn(void) {}
1627 t_gotfn
getfn(t_pd
*x
, t_symbol
*s
)
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
);
1639 t_gotfn
zgetfn(t_pd
*x
, t_symbol
*s
)
1645 for (i
= c
->c_nmethod
, m
= c
->c_methods
; i
--; m
++)
1646 if (m
->me_name
== s
) return(m
->me_fun
);