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. */
34 static t_symbol
*class_loadsym
; /* name under which an extern is invoked */
35 static void pd_defaultfloat(t_pd
*x
, t_float f
);
36 static void pd_defaultlist(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
);
37 t_pd pd_objectmaker
; /* factory for creating "object" boxes */
38 t_pd pd_canvasmaker
; /* factory for creating canvases */
40 static t_symbol
*class_extern_dir
= &s_
;
42 static void pd_defaultanything(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
48 pd_error(x
, "%s: no method for '%s'", (*x
)->c_name
->s_name
, s
->s_name
);
51 static void pd_defaultbang(t_pd
*x
)
53 if (*(*x
)->c_listmethod
!= pd_defaultlist
)
54 (*(*x
)->c_listmethod
)(x
, 0, 0, 0);
55 else (*(*x
)->c_anymethod
)(x
, &s_bang
, 0, 0);
58 static void pd_defaultpointer(t_pd
*x
, t_gpointer
*gp
)
60 if (*(*x
)->c_listmethod
!= pd_defaultlist
)
64 (*(*x
)->c_listmethod
)(x
, 0, 1, &at
);
70 (*(*x
)->c_anymethod
)(x
, &s_pointer
, 1, &at
);
74 static void pd_defaultfloat(t_pd
*x
, t_float f
)
76 if (*(*x
)->c_listmethod
!= pd_defaultlist
)
80 (*(*x
)->c_listmethod
)(x
, 0, 1, &at
);
86 (*(*x
)->c_anymethod
)(x
, &s_float
, 1, &at
);
90 static void pd_defaultsymbol(t_pd
*x
, t_symbol
*s
)
92 if (*(*x
)->c_listmethod
!= pd_defaultlist
)
96 (*(*x
)->c_listmethod
)(x
, 0, 1, &at
);
102 (*(*x
)->c_anymethod
)(x
, &s_symbol
, 1, &at
);
106 void obj_list(t_object
*x
, t_symbol
*s
, int argc
, t_atom
*argv
);
107 static void class_nosavefn(t_gobj
*z
, t_binbuf
*b
);
109 /* handle "list" messages to Pds without explicit list methods defined. */
110 static void pd_defaultlist(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
112 /* a list with one element which is a number can be handled by a
113 "float" method if any is defined; same for "symbol", "pointer". */
116 if (argv
->a_type
== A_FLOAT
&&
117 *(*x
)->c_floatmethod
!= pd_defaultfloat
)
119 (*(*x
)->c_floatmethod
)(x
, argv
->a_w
.w_float
);
122 else if (argv
->a_type
== A_SYMBOL
&&
123 *(*x
)->c_symbolmethod
!= pd_defaultsymbol
)
125 (*(*x
)->c_symbolmethod
)(x
, argv
->a_w
.w_symbol
);
128 else if (argv
->a_type
== A_POINTER
&&
129 *(*x
)->c_pointermethod
!= pd_defaultpointer
)
131 (*(*x
)->c_pointermethod
)(x
, argv
->a_w
.w_gpointer
);
135 /* Next try for an "anything" method */
136 if ((*x
)->c_anymethod
!= pd_defaultanything
)
137 (*(*x
)->c_anymethod
)(x
, &s_list
, argc
, argv
);
139 /* if the object is patchable (i.e., can have proper inlets)
140 send it on to obj_list which will unpack the list into the inlets */
141 else if ((*x
)->c_patchable
)
142 obj_list((t_object
*)x
, s
, argc
, argv
);
143 /* otherwise gove up and complain. */
144 else pd_defaultanything(x
, &s_list
, argc
, argv
);
147 /* for now we assume that all "gobjs" are text unless explicitly
148 overridden later by calling class_setbehavior(). I'm not sure
149 how to deal with Pds that aren't gobjs; shouldn't there be a
150 way to check that at run time? Perhaps the presence of a "newmethod"
151 should be our cue, or perhaps the "tiny" flag. */
153 /* another matter. This routine does two unrelated things: it creates
154 a Pd class, but also adds a "new" method to create an instance of it.
155 These are combined for historical reasons and for brevity in writing
156 objects. To avoid adding a "new" method send a null function pointer.
157 To add additional ones, use class_addcreator below. Some "classes", like
158 "select", are actually two classes of the same name, one for the single-
159 argument form, one for the multiple one; see select_setup() to find out
160 how this is handled. */
162 extern t_widgetbehavior text_widgetbehavior
;
163 extern void text_save(t_gobj
*z
, t_binbuf
*b
);
165 t_class
*class_new(t_symbol
*s
, t_newmethod newmethod
, t_method freemethod
,
166 size_t size
, int flags
, t_atomtype type1
, ...)
169 t_atomtype vec
[MAXPDARG
+1], *vp
= vec
;
172 int typeflag
= flags
& CLASS_TYPEMASK
;
173 if (!typeflag
) typeflag
= CLASS_PATCHABLE
;
179 if (count
== MAXPDARG
)
181 error("class %s: sorry: only %d creation args allowed",
182 s
->s_name
, MAXPDARG
);
187 *vp
= va_arg(ap
, t_atomtype
);
190 if (pd_objectmaker
&& newmethod
)
192 /* add a "new" method by the name specified by the object */
193 class_addmethod(pd_objectmaker
, (t_method
)newmethod
, s
,
194 vec
[0], vec
[1], vec
[2], vec
[3], vec
[4], vec
[5]);
197 /* if we're loading an extern it might have been invoked by a
198 longer file name; in this case, make this an admissible name
200 char *loadstring
= class_loadsym
->s_name
,
201 l1
= strlen(s
->s_name
), l2
= strlen(loadstring
);
202 if (l2
> l1
&& !strcmp(s
->s_name
, loadstring
+ (l2
- l1
)))
203 class_addmethod(pd_objectmaker
, (t_method
)newmethod
,
205 vec
[0], vec
[1], vec
[2], vec
[3], vec
[4], vec
[5]);
208 c
= (t_class
*)t_getbytes(sizeof(*c
));
209 c
->c_name
= c
->c_helpname
= s
;
211 c
->c_methods
= t_getbytes(0);
213 c
->c_freemethod
= (t_method
)freemethod
;
214 c
->c_bangmethod
= pd_defaultbang
;
215 c
->c_pointermethod
= pd_defaultpointer
;
216 c
->c_floatmethod
= pd_defaultfloat
;
217 c
->c_symbolmethod
= pd_defaultsymbol
;
218 c
->c_listmethod
= pd_defaultlist
;
219 c
->c_anymethod
= pd_defaultanything
;
220 c
->c_wb
= (typeflag
== CLASS_PATCHABLE
? &text_widgetbehavior
: 0);
222 c
->c_firstin
= ((flags
& CLASS_NOINLET
) == 0);
223 c
->c_patchable
= (typeflag
== CLASS_PATCHABLE
);
224 c
->c_gobj
= (typeflag
>= CLASS_GOBJ
);
225 c
->c_drawcommand
= 0;
226 c
->c_floatsignalin
= 0;
227 c
->c_externdir
= class_extern_dir
;
228 c
->c_savefn
= (typeflag
== CLASS_PATCHABLE
? text_save
: class_nosavefn
);
230 post("class: %s", c
->c_name
->s_name
);
235 /* add a creation method, which is a function that returns a Pd object
236 suitable for putting in an object box. We presume you've got a class it
237 can belong to, but this won't be used until the newmethod is actually
238 called back (and the new method explicitly takes care of this.) */
240 void class_addcreator(t_newmethod newmethod
, t_symbol
*s
,
241 t_atomtype type1
, ...)
244 t_atomtype vec
[MAXPDARG
+1], *vp
= vec
;
251 if (count
== MAXPDARG
)
253 error("class %s: sorry: only %d creation args allowed",
254 s
->s_name
, MAXPDARG
);
259 *vp
= va_arg(ap
, t_atomtype
);
262 class_addmethod(pd_objectmaker
, (t_method
)newmethod
, s
,
263 vec
[0], vec
[1], vec
[2], vec
[3], vec
[4], vec
[5]);
266 void class_addmethod(t_class
*c
, t_method fn
, t_symbol
*sel
,
267 t_atomtype arg1
, ...)
271 t_atomtype argtype
= arg1
;
275 /* "signal" method specifies that we take audio signals but
276 that we don't want automatic float to signal conversion. This
277 is obsolete; you should now use the CLASS_MAINSIGNALIN macro. */
278 if (sel
== &s_signal
)
280 if (c
->c_floatsignalin
)
281 post("warning: signal method overrides class_mainsignalin");
282 c
->c_floatsignalin
= -1;
284 /* check for special cases. "Pointer" is missing here so that
285 pd_objectmaker's pointer method can be typechecked differently. */
288 if (argtype
) goto phooey
;
289 class_addbang(c
, fn
);
291 else if (sel
== &s_float
)
293 if (argtype
!= A_FLOAT
|| va_arg(ap
, t_atomtype
)) goto phooey
;
294 class_doaddfloat(c
, fn
);
296 else if (sel
== &s_symbol
)
298 if (argtype
!= A_SYMBOL
|| va_arg(ap
, t_atomtype
)) goto phooey
;
299 class_addsymbol(c
, fn
);
301 else if (sel
== &s_list
)
303 if (argtype
!= A_GIMME
) goto phooey
;
304 class_addlist(c
, fn
);
306 else if (sel
== &s_anything
)
308 if (argtype
!= A_GIMME
) goto phooey
;
309 class_addanything(c
, fn
);
313 c
->c_methods
= t_resizebytes(c
->c_methods
,
314 c
->c_nmethod
* sizeof(*c
->c_methods
),
315 (c
->c_nmethod
+ 1) * sizeof(*c
->c_methods
));
316 m
= c
->c_methods
+ c
->c_nmethod
;
319 m
->me_fun
= (t_gotfn
)fn
;
321 while (argtype
!= A_NULL
&& nargs
< MAXPDARG
)
323 m
->me_arg
[nargs
++] = argtype
;
324 argtype
= va_arg(ap
, t_atomtype
);
326 if (argtype
!= A_NULL
)
327 error("%s_%s: only 5 arguments are typecheckable; use A_GIMME",
328 c
->c_name
->s_name
, sel
->s_name
);
330 m
->me_arg
[nargs
] = A_NULL
;
334 bug("class_addmethod: %s_%s: bad argument types\n",
335 c
->c_name
->s_name
, sel
->s_name
);
338 /* Instead of these, see the "class_addfloat", etc., macros in m_pd.h */
339 void class_addbang(t_class
*c
, t_method fn
)
341 c
->c_bangmethod
= (t_bangmethod
)fn
;
344 void class_addpointer(t_class
*c
, t_method fn
)
346 c
->c_pointermethod
= (t_pointermethod
)fn
;
349 void class_doaddfloat(t_class
*c
, t_method fn
)
351 c
->c_floatmethod
= (t_floatmethod
)fn
;
354 void class_addsymbol(t_class
*c
, t_method fn
)
356 c
->c_symbolmethod
= (t_symbolmethod
)fn
;
359 void class_addlist(t_class
*c
, t_method fn
)
361 c
->c_listmethod
= (t_listmethod
)fn
;
364 void class_addanything(t_class
*c
, t_method fn
)
366 c
->c_anymethod
= (t_anymethod
)fn
;
369 void class_setwidget(t_class
*c
, t_widgetbehavior
*w
)
374 void class_setparentwidget(t_class
*c
, t_parentwidgetbehavior
*pw
)
379 char *class_getname(t_class
*c
)
381 return (c
->c_name
->s_name
);
384 char *class_gethelpname(t_class
*c
)
386 return (c
->c_helpname
->s_name
);
389 void class_sethelpsymbol(t_class
*c
, t_symbol
*s
)
394 t_parentwidgetbehavior
*pd_getparentwidget(t_pd
*x
)
396 return ((*x
)->c_pwb
);
399 void class_setdrawcommand(t_class
*c
)
401 c
->c_drawcommand
= 1;
404 int class_isdrawcommand(t_class
*c
)
406 return (c
->c_drawcommand
);
409 static void pd_floatforsignal(t_pd
*x
, t_float f
)
411 int offset
= (*x
)->c_floatsignalin
;
413 *(t_sample
*)(((char *)x
) + offset
) = ftofix(f
);
415 pd_error(x
, "%s: float unexpected for signal input",
416 (*x
)->c_name
->s_name
);
419 void class_domainsignalin(t_class
*c
, int onset
)
421 if (onset
<= 0) onset
= -1;
424 if (c
->c_floatmethod
!= pd_defaultfloat
)
425 post("warning: %s: float method overwritten", c
->c_name
->s_name
);
426 c
->c_floatmethod
= (t_floatmethod
)pd_floatforsignal
;
428 c
->c_floatsignalin
= onset
;
431 void class_set_extern_dir(t_symbol
*s
)
433 class_extern_dir
= s
;
436 char *class_gethelpdir(t_class
*c
)
438 return (c
->c_externdir
->s_name
);
441 static void class_nosavefn(t_gobj
*z
, t_binbuf
*b
)
447 bug("save function called but not defined");
450 void class_setsavefn(t_class
*c
, t_savefn f
)
455 t_savefn
class_getsavefn(t_class
*c
)
457 return (c
->c_savefn
);
460 void class_setpropertiesfn(t_class
*c
, t_propertiesfn f
)
462 c
->c_propertiesfn
= f
;
465 t_propertiesfn
class_getpropertiesfn(t_class
*c
)
467 return (c
->c_propertiesfn
);
470 /* ---------------- the symbol table ------------------------ */
472 #define HASHSIZE 1024
474 static t_symbol
*symhash
[HASHSIZE
];
476 t_symbol
*dogensym(char *s
, t_symbol
*oldsym
)
478 t_symbol
**sym1
, *sym2
;
479 unsigned int hash1
= 0, hash2
= 0;
489 sym1
= symhash
+ (hash2
& (HASHSIZE
-1));
490 while ((sym2
= *sym1
))
492 if (!strcmp(sym2
->s_name
, s
)) return(sym2
);
493 sym1
= &sym2
->s_next
;
495 if (oldsym
) sym2
= oldsym
;
498 sym2
= (t_symbol
*)t_getbytes(sizeof(*sym2
));
499 sym2
->s_name
= t_getbytes(length
+1);
502 strcpy(sym2
->s_name
, s
);
508 t_symbol
*gensym(char *s
)
510 // printf("gensym: %s\n", s);
513 return dogensym("/", 0);
516 return(dogensym(s
, 0));
522 t_symbol
*addfileextent(t_symbol
*s
)
524 char namebuf
[MAXPDSTRING
], *str
= s
->s_name
;
525 int ln
= strlen(str
);
526 if (!strcmp(str
+ ln
- 3, ".pd")) return (s
);
527 strcpy(namebuf
, str
);
528 strcpy(namebuf
+ln
, ".pd");
529 return (gensym(namebuf
));
532 static int tryingalready
;
534 void canvas_popabstraction(t_canvas
*x
);
537 t_symbol
* pathsearch(t_symbol
*s
,char* ext
);
538 int pd_setloadingabstraction(t_symbol
*sym
);
540 /* this routine is called when a new "object" is requested whose class Pd
541 doesn't know. Pd tries to load it as an extern, then as an abstraction. */
542 void new_anything(void *dummy
, t_symbol
*s
, int argc
, t_atom
*argv
)
545 t_symbol
*dir
= canvas_getcurrentdir();
547 char dirbuf
[MAXPDSTRING
], *nameptr
;
548 if (tryingalready
) return;
551 if (sys_load_lib(dir
->s_name
, s
->s_name
))
554 typedmess(dummy
, s
, argc
, argv
);
559 current
= s__X
.s_thing
;
560 if ((fd
= open_via_path(dir
->s_name
, s
->s_name
, ".pd",
561 dirbuf
, &nameptr
, MAXPDSTRING
, 0)) >= 0 ||
562 (fd
= open_via_path(dir
->s_name
, s
->s_name
, ".pat",
563 dirbuf
, &nameptr
, MAXPDSTRING
, 0)) >= 0)
566 if (!pd_setloadingabstraction(s
))
568 canvas_setargs(argc
, argv
); /* bug fix by Krzysztof Czaja */
569 binbuf_evalfile(gensym(nameptr
), gensym(dirbuf
));
570 if (s__X
.s_thing
!= current
)
571 canvas_popabstraction((t_canvas
*)(s__X
.s_thing
));
572 canvas_setargs(0, 0);
574 else error("%s: can't load abstraction within itself\n", s
->s_name
);
579 t_symbol s_pointer
= {"pointer", 0, 0};
580 t_symbol s_float
= {"float", 0, 0};
581 t_symbol s_symbol
= {"symbol", 0, 0};
582 t_symbol s_bang
= {"bang", 0, 0};
583 t_symbol s_list
= {"list", 0, 0};
584 t_symbol s_anything
= {"anything", 0, 0};
585 t_symbol s_signal
= {"signal", 0, 0};
586 t_symbol s__N
= {"#N", 0, 0};
587 t_symbol s__X
= {"#X", 0, 0};
588 t_symbol s_x
= {"x", 0, 0};
589 t_symbol s_y
= {"y", 0, 0};
590 t_symbol s_
= {"", 0, 0};
592 static t_symbol
*symlist
[] = { &s_pointer
, &s_float
, &s_symbol
, &s_bang
,
593 &s_list
, &s_anything
, &s_signal
, &s__N
, &s__X
, &s_x
, &s_y
, &s_
};
600 if (pd_objectmaker
) return;
601 for (i
= sizeof(symlist
)/sizeof(*symlist
), sp
= symlist
; i
--; sp
++)
602 (void) dogensym((*sp
)->s_name
, *sp
);
603 pd_objectmaker
= class_new(gensym("objectmaker"), 0, 0, sizeof(t_pd
),
604 CLASS_DEFAULT
, A_NULL
);
605 pd_canvasmaker
= class_new(gensym("classmaker"), 0, 0, sizeof(t_pd
),
606 CLASS_DEFAULT
, A_NULL
);
607 pd_bind(&pd_canvasmaker
, &s__N
);
608 class_addanything(pd_objectmaker
, (t_method
)new_anything
);
613 /* This is externally available, but note that it might later disappear; the
614 whole "newest" thing is a hack which needs to be redesigned. */
615 t_pd
*pd_newest(void)
620 /* horribly, we need prototypes for each of the artificial function
621 calls in typedmess(), to keep the compiler quiet. */
622 typedef t_pd
*(*t_newgimme
)(t_symbol
*s
, int argc
, t_atom
*argv
);
623 typedef void(*t_messgimme
)(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
);
625 typedef t_pd
*(*t_fun0
)(
626 t_floatarg d1
, t_floatarg d2
, t_floatarg d3
, t_floatarg d4
, t_floatarg d5
);
627 typedef t_pd
*(*t_fun1
)(t_int i1
,
628 t_floatarg d1
, t_floatarg d2
, t_floatarg d3
, t_floatarg d4
, t_floatarg d5
);
629 typedef t_pd
*(*t_fun2
)(t_int i1
, t_int i2
,
630 t_floatarg d1
, t_floatarg d2
, t_floatarg d3
, t_floatarg d4
, t_floatarg d5
);
631 typedef t_pd
*(*t_fun3
)(t_int i1
, t_int i2
, t_int i3
,
632 t_floatarg d1
, t_floatarg d2
, t_floatarg d3
, t_floatarg d4
, t_floatarg d5
);
633 typedef t_pd
*(*t_fun4
)(t_int i1
, t_int i2
, t_int i3
, t_int i4
,
634 t_floatarg d1
, t_floatarg d2
, t_floatarg d3
, t_floatarg d4
, t_floatarg d5
);
635 typedef t_pd
*(*t_fun5
)(t_int i1
, t_int i2
, t_int i3
, t_int i4
, t_int i5
,
636 t_floatarg d1
, t_floatarg d2
, t_floatarg d3
, t_floatarg d4
, t_floatarg d5
);
637 typedef t_pd
*(*t_fun6
)(t_int i1
, t_int i2
, t_int i3
, t_int i4
, t_int i5
, t_int i6
,
638 t_floatarg d1
, t_floatarg d2
, t_floatarg d3
, t_floatarg d4
, t_floatarg d5
);
640 void pd_typedmess(t_pd
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
647 t_atomtype
*wp
, wanttype
;
649 t_int ai
[MAXPDARG
+1], *ap
= ai
;
650 t_floatarg ad
[MAXPDARG
+1], *dp
= ad
;
654 /* check for messages that are handled by fixed slots in the class
655 structure. We don't catch "pointer" though so that sending "pointer"
656 to pd_objectmaker doesn't require that we supply a pointer value. */
659 if (!argc
) (*c
->c_floatmethod
)(x
, 0.);
660 else if (argv
->a_type
== A_FLOAT
)
661 (*c
->c_floatmethod
)(x
, argv
->a_w
.w_float
);
667 (*c
->c_bangmethod
)(x
);
672 (*c
->c_listmethod
)(x
, s
, argc
, argv
);
677 if (argc
&& argv
->a_type
== A_SYMBOL
)
678 (*c
->c_symbolmethod
)(x
, argv
->a_w
.w_symbol
);
680 (*c
->c_symbolmethod
)(x
, &s_
);
683 for (i
= c
->c_nmethod
, m
= c
->c_methods
; i
--; m
++)
689 if (x
== &pd_objectmaker
)
690 newest
= (*((t_newgimme
)(m
->me_fun
)))(s
, argc
, argv
);
691 else (*((t_messgimme
)(m
->me_fun
)))(x
, s
, argc
, argv
);
695 if (argc
> MAXPDARG
) argc
= MAXPDARG
;
696 if (x
!= &pd_objectmaker
) *(ap
++) = (t_int
)x
, narg
++;
697 while((wanttype
= *wp
++))
702 if (!argc
) goto badarg
;
705 if (argv
->a_type
== A_POINTER
)
706 *ap
= (t_int
)(argv
->a_w
.w_gpointer
);
715 if (!argc
) goto badarg
;
720 if (argv
->a_type
== A_FLOAT
)
721 *dp
= argv
->a_w
.w_float
;
729 if (!argc
) goto badarg
;
731 if (!argc
) *ap
= (t_int
)(&s_
);
734 if (argv
->a_type
== A_SYMBOL
)
735 *ap
= (t_int
)(argv
->a_w
.w_symbol
);
736 /* if it's an unfilled "dollar" argument it appears
737 as zero here; cheat and bash it to the null
738 symbol. Unfortunately, this lets real zeros
739 pass as symbols too, which seems wrong... */
740 else if (x
== &pd_objectmaker
&& argv
->a_type
== A_FLOAT
741 && argv
->a_w
.w_float
== 0)
758 case 0 : bonzo
= (*(t_fun0
)(m
->me_fun
))
759 (ad
[0], ad
[1], ad
[2], ad
[3], ad
[4]); break;
760 case 1 : bonzo
= (*(t_fun1
)(m
->me_fun
))
761 (ai
[0], ad
[0], ad
[1], ad
[2], ad
[3], ad
[4]); break;
762 case 2 : bonzo
= (*(t_fun2
)(m
->me_fun
))
763 (ai
[0], ai
[1], ad
[0], ad
[1], ad
[2], ad
[3], ad
[4]); break;
764 case 3 : bonzo
= (*(t_fun3
)(m
->me_fun
))
765 (ai
[0], ai
[1], ai
[2], ad
[0], ad
[1], ad
[2], ad
[3], ad
[4]); break;
766 case 4 : bonzo
= (*(t_fun4
)(m
->me_fun
))
767 (ai
[0], ai
[1], ai
[2], ai
[3],
768 ad
[0], ad
[1], ad
[2], ad
[3], ad
[4]); break;
769 case 5 : bonzo
= (*(t_fun5
)(m
->me_fun
))
770 (ai
[0], ai
[1], ai
[2], ai
[3], ai
[4],
771 ad
[0], ad
[1], ad
[2], ad
[3], ad
[4]); break;
772 case 6 : bonzo
= (*(t_fun6
)(m
->me_fun
))
773 (ai
[0], ai
[1], ai
[2], ai
[3], ai
[4], ai
[5],
774 ad
[0], ad
[1], ad
[2], ad
[3], ad
[4]); break;
777 if (x
== &pd_objectmaker
)
781 (*c
->c_anymethod
)(x
, s
, argc
, argv
);
784 pd_error(x
, "Bad arguments for message '%s' to object '%s'",
785 s
->s_name
, c
->c_name
->s_name
);
788 void pd_vmess(t_pd
*x
, t_symbol
*sel
, char *fmt
, ...)
791 t_atom arg
[MAXPDARG
], *at
=arg
;
798 if (nargs
> MAXPDARG
)
800 pd_error(x
, "pd_vmess: only %d allowed", MAXPDARG
);
805 case 'f': SETFLOAT(at
, va_arg(ap
, double)); break;
806 case 's': SETSYMBOL(at
, va_arg(ap
, t_symbol
*)); break;
807 case 'i': SETFLOAT(at
, va_arg(ap
, t_int
)); break;
808 case 'p': SETPOINTER(at
, va_arg(ap
, t_gpointer
*)); break;
816 typedmess(x
, sel
, nargs
, arg
);
819 void pd_forwardmess(t_pd
*x
, int argc
, t_atom
*argv
)
823 t_atomtype t
= argv
->a_type
;
824 if (t
== A_SYMBOL
) pd_typedmess(x
, argv
->a_w
.w_symbol
, argc
-1, argv
+1);
825 else if (t
== A_POINTER
)
827 if (argc
== 1) pd_pointer(x
, argv
->a_w
.w_gpointer
);
828 else pd_list(x
, &s_list
, argc
, argv
);
830 else if (t
== A_FLOAT
)
832 if (argc
== 1) pd_float(x
, argv
->a_w
.w_float
);
833 else pd_list(x
, &s_list
, argc
, argv
);
835 else bug("pd_forwardmess");
842 t_gotfn
getfn(t_pd
*x
, t_symbol
*s
)
848 for (i
= c
->c_nmethod
, m
= c
->c_methods
; i
--; m
++)
849 if (m
->me_name
== s
) return(m
->me_fun
);
850 pd_error(x
, "%s: no method for message '%s'", c
->c_name
->s_name
, s
->s_name
);
851 return((t_gotfn
)nullfn
);
854 t_gotfn
zgetfn(t_pd
*x
, t_symbol
*s
)
860 for (i
= c
->c_nmethod
, m
= c
->c_methods
; i
--; m
++)
861 if (m
->me_name
== s
) return(m
->me_fun
);