From 57045df5fe3ec557e57dc7434ac1a07b5521bffc Mon Sep 17 00:00:00 2001 From: Guenter Geiger Date: Mon, 29 Jul 2002 17:06:19 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r58, which included commits to RCS files with non-trunk default branches. svn path=/trunk/; revision=59 --- pd/src/m_class.c | 772 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 772 insertions(+) create mode 100644 pd/src/m_class.c (limited to 'pd/src/m_class.c') diff --git a/pd/src/m_class.c b/pd/src/m_class.c new file mode 100644 index 00000000..9d6329d6 --- /dev/null +++ b/pd/src/m_class.c @@ -0,0 +1,772 @@ +/* Copyright (c) 1997-1999 Miller Puckette. +* For information on usage and redistribution, and for a DISCLAIMER OF ALL +* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#define PD_CLASS_DEF +#include "m_imp.h" +#include +#ifdef UNIX +#include +#endif +#ifdef NT +#include +#endif + +#include +#include + +static t_symbol *class_loadsym; /* name under which an extern is invoked */ +static void pd_defaultfloat(t_pd *x, t_float f); +static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv); +t_pd pd_objectmaker; /* factory for creating "object" boxes */ +t_pd pd_canvasmaker; /* factory for creating canvases */ + +static void pd_defaultanything(t_pd *x, t_symbol *s, int argc, t_atom *argv) +{ + pd_error(x, "%s: no method for '%s'", (*x)->c_name->s_name, s->s_name); +} + +static void pd_defaultbang(t_pd *x) +{ + if (*(*x)->c_listmethod != pd_defaultlist) + (*(*x)->c_listmethod)(x, 0, 0, 0); + else (*(*x)->c_anymethod)(x, &s_bang, 0, 0); +} + +static void pd_defaultpointer(t_pd *x, t_gpointer *gp) +{ + if (*(*x)->c_listmethod != pd_defaultlist) + { + t_atom at; + SETPOINTER(&at, gp); + (*(*x)->c_listmethod)(x, 0, 1, &at); + } + else + { + t_atom at; + SETPOINTER(&at, gp); + (*(*x)->c_anymethod)(x, &s_pointer, 1, &at); + } +} + +static void pd_defaultfloat(t_pd *x, t_float f) +{ + if (*(*x)->c_listmethod != pd_defaultlist) + { + t_atom at; + SETFLOAT(&at, f); + (*(*x)->c_listmethod)(x, 0, 1, &at); + } + else + { + t_atom at; + SETFLOAT(&at, f); + (*(*x)->c_anymethod)(x, &s_float, 1, &at); + } +} + +static void pd_defaultsymbol(t_pd *x, t_symbol *s) +{ + if (*(*x)->c_listmethod != pd_defaultlist) + { + t_atom at; + SETSYMBOL(&at, s); + (*(*x)->c_listmethod)(x, 0, 1, &at); + } + else + { + t_atom at; + SETSYMBOL(&at, s); + (*(*x)->c_anymethod)(x, &s_symbol, 1, &at); + } +} + +void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv); + + /* handle "list" messages to Pds without explicit list methods defined. */ +static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv) +{ + /* a list with one element which is a number can be handled by a + "float" method if any is defined; same for "symbol", "pointer". */ + if (argc == 1) + { + if (argv->a_type == A_FLOAT && + *(*x)->c_floatmethod != pd_defaultfloat) + { + (*(*x)->c_floatmethod)(x, argv->a_w.w_float); + return; + } + else if (argv->a_type == A_SYMBOL && + *(*x)->c_symbolmethod != pd_defaultsymbol) + { + (*(*x)->c_symbolmethod)(x, argv->a_w.w_symbol); + return; + } + else if (argv->a_type == A_POINTER && + *(*x)->c_pointermethod != pd_defaultpointer) + { + (*(*x)->c_pointermethod)(x, argv->a_w.w_gpointer); + return; + } + } + /* Next try for an "anything" method */ + if ((*x)->c_anymethod != pd_defaultanything) + (*(*x)->c_anymethod)(x, &s_list, argc, argv); + + /* if the object is patchable (i.e., can have proper inlets) + send it on to obj_list which will unpack the list into the inlets */ + else if ((*x)->c_patchable) + obj_list((t_object *)x, s, argc, argv); + /* otherwise gove up and complain. */ + else pd_defaultanything(x, &s_list, argc, argv); +} + + /* for now we assume that all "gobjs" are text unless explicitly + overridden later by calling class_setbehavior(). I'm not sure + how to deal with Pds that aren't gobjs; shouldn't there be a + way to check that at run time? Perhaps the presence of a "newmethod" + should be our cue, or perhaps the "tiny" flag. */ + + /* another matter. This routine does two unrelated things: it creates + a Pd class, but also adds a "new" method to create an instance of it. + These are combined for historical reasons and for brevity in writing + objects. To avoid adding a "new" method send a null function pointer. + To add additional ones, use class_addcreator below. Some "classes", like + "select", are actually two classes of the same name, one for the single- + argument form, one for the multiple one; see select_setup() to find out + how this is handled. */ + +extern t_widgetbehavior text_widgetbehavior; + +t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod, + size_t size, int flags, t_atomtype type1, ...) +{ + va_list ap; + t_atomtype vec[MAXPDARG+1], *vp = vec; + int count = 0; + t_class *c; + int typeflag = flags & CLASS_TYPEMASK; + if (!typeflag) typeflag = CLASS_PATCHABLE; + *vp = type1; + + va_start(ap, type1); + while (*vp) + { + if (count == MAXPDARG) + { + error("class %s: sorry: only %d creation args allowed", + s->s_name, MAXPDARG); + break; + } + vp++; + count++; + *vp = va_arg(ap, t_atomtype); + } + va_end(ap); + if (pd_objectmaker && newmethod) + { + /* add a "new" method by the name specified by the object */ + class_addmethod(pd_objectmaker, (t_method)newmethod, s, + vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]); + if (class_loadsym) + { + /* if we're loading an extern it might have been invoked by a + longer file name; in this case, make this an admissible name + too. */ + char *loadstring = class_loadsym->s_name, + l1 = strlen(s->s_name), l2 = strlen(loadstring); + if (l2 > l1 && !strcmp(s->s_name, loadstring + (l2 - l1))) + class_addmethod(pd_objectmaker, (t_method)newmethod, + class_loadsym, + vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]); + } + } + c = (t_class *)t_getbytes(sizeof(*c)); + c->c_name = c->c_helpname = s; + c->c_size = size; + c->c_methods = t_getbytes(0); + c->c_nmethod = 0; + c->c_freemethod = (t_method)freemethod; + c->c_bangmethod = pd_defaultbang; + c->c_pointermethod = pd_defaultpointer; + c->c_floatmethod = pd_defaultfloat; + c->c_symbolmethod = pd_defaultsymbol; + c->c_listmethod = pd_defaultlist; + c->c_anymethod = pd_defaultanything; + c->c_wb = (typeflag == CLASS_PATCHABLE ? &text_widgetbehavior : 0); + c->c_pwb = 0; + c->c_firstin = ((flags & CLASS_NOINLET) == 0); + c->c_patchable = (typeflag == CLASS_PATCHABLE); + c->c_gobj = (typeflag >= CLASS_GOBJ); + c->c_drawcommand = 0; + c->c_floatsignalin = 0; +#if 0 + post("class: %s", c->c_name->s_name); +#endif + return (c); +} + + /* add a creation method, which is a function that returns a Pd object + suitable for putting in an object box. We presume you've got a class it + can belong to, but this won't be used until the newmethod is actually + called back (and the new method explicitly takes care of this.) */ + +void class_addcreator(t_newmethod newmethod, t_symbol *s, + t_atomtype type1, ...) +{ + va_list ap; + t_atomtype vec[MAXPDARG+1], *vp = vec; + int count = 0; + *vp = type1; + + va_start(ap, type1); + while (*vp) + { + if (count == MAXPDARG) + { + error("class %s: sorry: only %d creation args allowed", + s->s_name, MAXPDARG); + break; + } + vp++; + count++; + *vp = va_arg(ap, t_atomtype); + } + va_end(ap); + class_addmethod(pd_objectmaker, (t_method)newmethod, s, + vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]); +} + +void class_addmethod(t_class *c, t_method fn, t_symbol *sel, + t_atomtype arg1, ...) +{ + va_list ap; + t_methodentry *m; + t_atomtype argtype = arg1; + int nargs; + + va_start(ap, arg1); + /* "signal" method specifies that we take audio signals but + that we don't want automatic float to signal conversion. This + is obsolete; you should now use the CLASS_MAINSIGNALIN macro. */ + if (sel == &s_signal) + { + if (c->c_floatsignalin) + post("warning: signal method overrides class_mainsignalin"); + c->c_floatsignalin = -1; + } + /* check for special cases. "Pointer" is missing here so that + pd_objectmaker's pointer method can be typechecked differently. */ + if (sel == &s_bang) + { + if (argtype) goto phooey; + class_addbang(c, fn); + } + else if (sel == &s_float) + { + if (argtype != A_FLOAT || va_arg(ap, t_atomtype)) goto phooey; + class_doaddfloat(c, fn); + } + else if (sel == &s_symbol) + { + if (argtype != A_SYMBOL || va_arg(ap, t_atomtype)) goto phooey; + class_addsymbol(c, fn); + } + else if (sel == &s_list) + { + if (argtype != A_GIMME) goto phooey; + class_addlist(c, fn); + } + else if (sel == &s_anything) + { + if (argtype != A_GIMME) goto phooey; + class_addanything(c, fn); + } + else + { + c->c_methods = t_resizebytes(c->c_methods, + c->c_nmethod * sizeof(*c->c_methods), + (c->c_nmethod + 1) * sizeof(*c->c_methods)); + m = c->c_methods + c->c_nmethod; + c->c_nmethod++; + m->me_name = sel; + m->me_fun = (t_gotfn)fn; + nargs = 0; + while (argtype != A_NULL && nargs < MAXPDARG) + { + m->me_arg[nargs++] = argtype; + argtype = va_arg(ap, t_atomtype); + } + if (argtype != A_NULL) + error("%s_%s: only 5 arguments are typecheckable; use A_GIMME", + c->c_name->s_name, sel->s_name); + va_end(ap); + m->me_arg[nargs] = A_NULL; + } + return; +phooey: + bug("class_addmethod: %s_%s: bad argument types\n", + c->c_name->s_name, sel->s_name); +} + + /* Instead of these, see the "class_addfloat", etc., macros in m_pd.h */ +void class_addbang(t_class *c, t_method fn) +{ + c->c_bangmethod = (t_bangmethod)fn; +} + +void class_addpointer(t_class *c, t_method fn) +{ + c->c_pointermethod = (t_pointermethod)fn; +} + +void class_doaddfloat(t_class *c, t_method fn) +{ + c->c_floatmethod = (t_floatmethod)fn; +} + +void class_addsymbol(t_class *c, t_method fn) +{ + c->c_symbolmethod = (t_symbolmethod)fn; +} + +void class_addlist(t_class *c, t_method fn) +{ + c->c_listmethod = (t_listmethod)fn; +} + +void class_addanything(t_class *c, t_method fn) +{ + c->c_anymethod = (t_anymethod)fn; +} + +void class_setwidget(t_class *c, t_widgetbehavior *w) +{ + c->c_wb = w; +} + +void class_setparentwidget(t_class *c, t_parentwidgetbehavior *pw) +{ + c->c_pwb = pw; +} + +char *class_getname(t_class *c) +{ + return (c->c_name->s_name); +} + +char *class_gethelpname(t_class *c) +{ + return (c->c_helpname->s_name); +} + +void class_sethelpsymbol(t_class *c, t_symbol *s) +{ + c->c_helpname = s; +} + +t_parentwidgetbehavior *pd_getparentwidget(t_pd *x) +{ + return ((*x)->c_pwb); +} + +void class_setdrawcommand(t_class *c) +{ + c->c_drawcommand = 1; +} + +int class_isdrawcommand(t_class *c) +{ + return (c->c_drawcommand); +} + +static void pd_floatforsignal(t_pd *x, t_float f) +{ + int offset = (*x)->c_floatsignalin; + if (offset > 0) + *(t_sample *)(((char *)x) + offset) = f; + else + pd_error(x, "%s: float unexpected for signal input", + (*x)->c_name->s_name); +} + +void class_domainsignalin(t_class *c, int onset) +{ + if (onset <= 0) onset = -1; + else + { + if (c->c_floatmethod != pd_defaultfloat) + post("warning: %s: float method overwritten", c->c_name->s_name); + c->c_floatmethod = (t_floatmethod)pd_floatforsignal; + } + c->c_floatsignalin = onset; +} + +/* ---------------- the symbol table ------------------------ */ + +#define HASHSIZE 1024 + +static t_symbol *symhash[HASHSIZE]; + +t_symbol *dogensym(char *s, t_symbol *oldsym) +{ + t_symbol **sym1, *sym2; + unsigned int hash1 = 0, hash2 = 0; + int length = 0; + char *s2 = s; + while (*s2) + { + hash1 += *s2; + hash2 += hash1; + length++; + s2++; + } + sym1 = symhash + (hash2 & (HASHSIZE-1)); + while (sym2 = *sym1) + { + if (!strcmp(sym2->s_name, s)) return(sym2); + sym1 = &sym2->s_next; + } + if (oldsym) sym2 = oldsym; + else + { + sym2 = (t_symbol *)t_getbytes(sizeof(*sym2)); + sym2->s_name = t_getbytes(length+1); + sym2->s_next = 0; + sym2->s_thing = 0; + strcpy(sym2->s_name, s); + } + *sym1 = sym2; + return (sym2); +} + +t_symbol *gensym(char *s) +{ + return(dogensym(s, 0)); +} + +static t_symbol *addfileextent(t_symbol *s) +{ + char namebuf[MAXPDSTRING], *str = s->s_name; + int ln = strlen(str); + if (!strcmp(str + ln - 3, ".pd")) return (s); + strcpy(namebuf, str); + strcpy(namebuf+ln, ".pd"); + return (gensym(namebuf)); +} + +static int tryingalready; + +void canvas_popabstraction(t_canvas *x); +extern t_pd *newest; + +t_symbol* pathsearch(t_symbol *s,char* ext); +int pd_setloadingabstraction(t_symbol *sym); + + /* this routine is called when a new "object" is requested whose class Pd + doesn't know. Pd tries to load it as an extern, then as an absteaction. */ +void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv) +{ + t_pd *current; + t_symbol *dir = canvas_getcurrentdir(); + int fd; + char dirbuf[MAXPDSTRING], *nameptr; + if (tryingalready) return; + newest = 0; + class_loadsym = s; + if (sys_load_lib(dir->s_name, s->s_name)) + { + tryingalready = 1; + typedmess(dummy, s, argc, argv); + tryingalready = 0; + return; + } + class_loadsym = 0; + current = s__X.s_thing; + if ((fd = open_via_path(dir->s_name, s->s_name, ".pd", + dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0) + { + close (fd); + if (!pd_setloadingabstraction(s)) + { + canvas_setargs(argc, argv); /* bug fix by Krzysztof Czaja */ + binbuf_evalfile(gensym(nameptr), gensym(dirbuf)); + if (s__X.s_thing != current) + canvas_popabstraction((t_canvas *)(s__X.s_thing)); + canvas_setargs(0, 0); + } + else error("%s: can't load abstraction within itself\n", s->s_name); + } + else newest = 0; +} + +t_symbol s_pointer = {"pointer", 0, 0}; +t_symbol s_float = {"float", 0, 0}; +t_symbol s_symbol = {"symbol", 0, 0}; +t_symbol s_bang = {"bang", 0, 0}; +t_symbol s_list = {"list", 0, 0}; +t_symbol s_anything = {"anything", 0, 0}; +t_symbol s_signal = {"signal", 0, 0}; +t_symbol s__N = {"#N", 0, 0}; +t_symbol s__X = {"#X", 0, 0}; +t_symbol s_x = {"x", 0, 0}; +t_symbol s_y = {"y", 0, 0}; +t_symbol s_ = {"", 0, 0}; + +static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang, + &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_}; + +void mess_init(void) +{ + t_symbol **sp; + int i; + + if (pd_objectmaker) return; + for (i = sizeof(symlist)/sizeof(*symlist), sp = symlist; i--; sp++) + (void) dogensym((*sp)->s_name, *sp); + pd_objectmaker = class_new(gensym("objectmaker"), 0, 0, sizeof(t_pd), + CLASS_DEFAULT, A_NULL); + pd_canvasmaker = class_new(gensym("classmaker"), 0, 0, sizeof(t_pd), + CLASS_DEFAULT, A_NULL); + pd_bind(&pd_canvasmaker, &s__N); + class_addanything(pd_objectmaker, (t_method)new_anything); +} + +t_pd *newest; + + /* horribly, we need prototypes for each of the artificial function + calls in typedmess(), to keep the compiler quiet. */ +typedef t_pd *(*t_newgimme)(t_symbol *s, int argc, t_atom *argv); +typedef void(*t_messgimme)(t_pd *x, t_symbol *s, int argc, t_atom *argv); + +typedef t_pd *(*t_fun0)( + t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); +typedef t_pd *(*t_fun1)(t_int i1, + t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); +typedef t_pd *(*t_fun2)(t_int i1, t_int i2, + t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); +typedef t_pd *(*t_fun3)(t_int i1, t_int i2, t_int i3, + t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); +typedef t_pd *(*t_fun4)(t_int i1, t_int i2, t_int i3, t_int i4, + t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); +typedef t_pd *(*t_fun5)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, + t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); +typedef t_pd *(*t_fun6)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, t_int i6, + t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); + +void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv) +{ + t_method *f; + t_class *c = *x; + t_methodentry *m; + t_atomtype *wp, wanttype; + int i; + t_int ai[MAXPDARG+1], *ap = ai; + t_floatarg ad[MAXPDARG+1], *dp = ad; + int narg = 0; + t_pd *bonzo; + + /* check for messages that are handled by fixed slots in the class + structure. We don't catch "pointer" though so that sending "pointer" + to pd_objectmaker doesn't require that we supply a pointer value. */ + if (s == &s_float) + { + if (!argc) (*c->c_floatmethod)(x, 0.); + else if (argv->a_type == A_FLOAT) + (*c->c_floatmethod)(x, argv->a_w.w_float); + else goto badarg; + return; + } + if (s == &s_bang) + { + (*c->c_bangmethod)(x); + return; + } + if (s == &s_list) + { + (*c->c_listmethod)(x, s, argc, argv); + return; + } + if (s == &s_symbol) + { + if (argc && argv->a_type == A_SYMBOL) + (*c->c_symbolmethod)(x, argv->a_w.w_symbol); + else + (*c->c_symbolmethod)(x, &s_); + return; + } + for (i = c->c_nmethod, m = c->c_methods; i--; m++) + if (m->me_name == s) + { + wp = m->me_arg; + if (*wp == A_GIMME) + { + if (x == &pd_objectmaker) + newest = (*((t_newgimme)(m->me_fun)))(s, argc, argv); + else (*((t_messgimme)(m->me_fun)))(x, s, argc, argv); + return; + } + if (argc > MAXPDARG) argc = MAXPDARG; + if (x != &pd_objectmaker) *(ap++) = (t_int)x, narg++; + while (wanttype = *wp++) + { + switch (wanttype) + { + case A_POINTER: + if (!argc) goto badarg; + else + { + if (argv->a_type == A_POINTER) + *ap = (t_int)(argv->a_w.w_gpointer); + else goto badarg; + argc--; + argv++; + } + narg++; + ap++; + break; + case A_FLOAT: + if (!argc) goto badarg; + case A_DEFFLOAT: + if (!argc) *dp = 0; + else + { + if (argv->a_type == A_FLOAT) + *dp = argv->a_w.w_float; + else goto badarg; + argc--; + argv++; + } + dp++; + break; + case A_SYMBOL: + if (!argc) goto badarg; + case A_DEFSYM: + if (!argc) *ap = (t_int)(&s_); + else + { + if (argv->a_type == A_SYMBOL) + *ap = (t_int)(argv->a_w.w_symbol); + /* if it's an unfilled "dollar" argument it appears + as zero here; cheat and bash it to the null + symbol. Unfortunately, this lets real zeros + pass as symbols too, which seems wrong... */ + else if (x == &pd_objectmaker && argv->a_type == A_FLOAT + && argv->a_w.w_float == 0) + *ap = (t_int)(&s_); + else goto badarg; + argc--; + argv++; + } + narg++; + ap++; + } + } + switch (narg) + { + case 0 : bonzo = (*(t_fun0)(m->me_fun)) + (ad[0], ad[1], ad[2], ad[3], ad[4]); break; + case 1 : bonzo = (*(t_fun1)(m->me_fun)) + (ai[0], ad[0], ad[1], ad[2], ad[3], ad[4]); break; + case 2 : bonzo = (*(t_fun2)(m->me_fun)) + (ai[0], ai[1], ad[0], ad[1], ad[2], ad[3], ad[4]); break; + case 3 : bonzo = (*(t_fun3)(m->me_fun)) + (ai[0], ai[1], ai[2], ad[0], ad[1], ad[2], ad[3], ad[4]); break; + case 4 : bonzo = (*(t_fun4)(m->me_fun)) + (ai[0], ai[1], ai[2], ai[3], + ad[0], ad[1], ad[2], ad[3], ad[4]); break; + case 5 : bonzo = (*(t_fun5)(m->me_fun)) + (ai[0], ai[1], ai[2], ai[3], ai[4], + ad[0], ad[1], ad[2], ad[3], ad[4]); break; + case 6 : bonzo = (*(t_fun6)(m->me_fun)) + (ai[0], ai[1], ai[2], ai[3], ai[4], ai[5], + ad[0], ad[1], ad[2], ad[3], ad[4]); break; + default: bonzo = 0; + } + if (x == &pd_objectmaker) + newest = bonzo; + return; + } + (*c->c_anymethod)(x, s, argc, argv); + return; +badarg: + pd_error(x, "Bad arguments for message '%s' to object '%s'", + s->s_name, c->c_name->s_name); +} + +void pd_vmess(t_pd *x, t_symbol *sel, char *fmt, ...) +{ + va_list ap; + t_atom arg[MAXPDARG], *at =arg; + int nargs = 0; + char *fp = fmt; + + va_start(ap, fmt); + while (1) + { + if (nargs > MAXPDARG) + { + pd_error(x, "pd_vmess: only %d allowed", MAXPDARG); + break; + } + switch(*fp++) + { + case 'f': SETFLOAT(at, va_arg(ap, double)); break; + case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break; + case 'i': SETFLOAT(at, va_arg(ap, t_int)); break; + case 'p': SETPOINTER(at, va_arg(ap, t_gpointer *)); break; + default: goto done; + } + at++; + nargs++; + } +done: + va_end(ap); + typedmess(x, sel, nargs, arg); +} + +void pd_forwardmess(t_pd *x, int argc, t_atom *argv) +{ + if (argc) + { + t_atomtype t = argv->a_type; + if (t == A_SYMBOL) pd_typedmess(x, argv->a_w.w_symbol, argc-1, argv+1); + else if (t == A_POINTER) + { + if (argc == 1) pd_pointer(x, argv->a_w.w_gpointer); + else pd_list(x, &s_list, argc, argv); + } + else if (t == A_FLOAT) + { + if (argc == 1) pd_float(x, argv->a_w.w_float); + else pd_list(x, &s_list, argc, argv); + } + else bug("pd_forwardmess"); + } + +} + +void nullfn(void) {} + +t_gotfn getfn(t_pd *x, t_symbol *s) +{ + t_class *c = *x; + t_methodentry *m; + int i; + + for (i = c->c_nmethod, m = c->c_methods; i--; m++) + if (m->me_name == s) return(m->me_fun); + pd_error(x, "%s: no method for message '%s'", c->c_name->s_name, s->s_name); + return((t_gotfn)nullfn); +} + +t_gotfn zgetfn(t_pd *x, t_symbol *s) +{ + t_class *c = *x; + t_methodentry *m; + int i; + + for (i = c->c_nmethod, m = c->c_methods; i--; m++) + if (m->me_name == s) return(m->me_fun); + return(0); +} -- cgit v1.2.1