Update of /cvsroot/pure-data/pd/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9536
Modified Files: Tag: desiredata kernel.c makefile.in Removed Files: Tag: desiredata m_class.c Log Message: m_class.c merged into kernel.c
Index: makefile.in =================================================================== RCS file: /cvsroot/pure-data/pd/src/makefile.in,v retrieving revision 1.4.4.2.2.21.2.15 retrieving revision 1.4.4.2.2.21.2.16 diff -C2 -d -r1.4.4.2.2.21.2.15 -r1.4.4.2.2.21.2.16 *** makefile.in 20 Dec 2006 06:24:18 -0000 1.4.4.2.2.21.2.15 --- makefile.in 28 Dec 2006 00:30:42 -0000 1.4.4.2.2.21.2.16 *************** *** 29,33 ****
# from pd miller ! SRC += m_class.c m_binbuf.c m_sched.c \ s_main.c s_inter.c s_loader.c s_path.c s_audio.c s_midi.c \ d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \ --- 29,33 ----
# from pd miller ! SRC += m_binbuf.c m_sched.c \ s_main.c s_inter.c s_loader.c s_path.c s_audio.c s_midi.c \ d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \
--- m_class.c DELETED ---
Index: kernel.c =================================================================== RCS file: /cvsroot/pure-data/pd/src/Attic/kernel.c,v retrieving revision 1.1.2.9 retrieving revision 1.1.2.10 diff -C2 -d -r1.1.2.9 -r1.1.2.10 *** kernel.c 27 Dec 2006 23:30:34 -0000 1.1.2.9 --- kernel.c 28 Dec 2006 00:30:42 -0000 1.1.2.10 *************** *** 1001,1004 **** --- 1001,1751 ---- }
+ /* 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 "desire.h" + #include "s_stuff.h" + #include <stdlib.h> + #ifdef UNISTD + #include <unistd.h> + #endif + #ifdef MSW + #include <io.h> + #endif + + #include <stdio.h> /* grrrr: for sprintf */ + #include <stdarg.h> + #include <string.h> + #include <pthread.h> /* tb: for hashtable locking */ + + #ifdef QUALIFIED_NAME + static char *pd_library_name = 0; + void pd_set_library_name(char *libname){ + pd_library_name=libname; + } + #endif + + t_hash *class_table=0; + + 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 t_symbol *class_extern_dir = &s_; + + static void pd_defaultanything(t_pd *x, t_symbol *s, int argc, t_atom *argv) { + pd_error(x, "%s: no method for '%s'", (*x)->name->s_name, s->s_name); + } + + static void pd_defaultbang(t_pd *x) { + t_class *c = pd_class(x); + if (c->listmethod != pd_defaultlist) c->listmethod(x,0,0,0); + else c->anymethod(x,&s_bang,0,0); + } + + static void pd_defaultfloat(t_pd *x, t_float f) { + t_class *c = pd_class(x); t_atom at; SETFLOAT(&at, f); + if (c->listmethod != pd_defaultlist) c->listmethod(x,0,1,&at); else c->anymethod(x,&s_float,1,&at); + } + static void pd_defaultsymbol(t_pd *x, t_symbol *s) { + t_class *c = pd_class(x); t_atom at; SETSYMBOL(&at, s); + if (c->listmethod != pd_defaultlist) c->listmethod(x,0,1,&at); else c->anymethod(x,&s_symbol,1,&at); + } + static void pd_defaultpointer(t_pd *x, t_gpointer *gp) { + t_class *c = pd_class(x); t_atom at; SETPOINTER(&at, gp); + if (c->listmethod != pd_defaultlist) c->listmethod(x,0,1,&at); else c->anymethod(x,&s_pointer,1,&at); + } + + + void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv); + static void class_nosavefn(t_gobj *z, t_binbuf *b); + + /* 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) { + t_class *c = pd_class(x); + /* a list with no elements is handled by the 'bang' method if one exists. */ + if (argc == 0 && c->bangmethod != pd_defaultbang) {c->bangmethod(x); return;} + /* 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) { + #define HANDLE(A,M,D,F) if (argv->a_type==A && c->M != D) {c->M(x, argv->a_w.F); return;} + HANDLE(A_FLOAT ,floatmethod ,pd_defaultfloat ,w_float) + HANDLE(A_SYMBOL ,symbolmethod ,pd_defaultsymbol ,w_symbol) + HANDLE(A_POINTER,pointermethod,pd_defaultpointer,w_gpointer) + } + /* Next try for an "anything" method; 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. otherwise gove up and complain. */ + if (c->anymethod != pd_defaultanything) c->anymethod(x,&s_list,argc,argv); + else if (c->patchable) obj_list((t_object *)x, s, argc, argv); + 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 void text_save(t_gobj *z, t_binbuf *b); + + 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; + #ifdef QUALIFIED_NAME + t_symbol *S=gensym(s->s_name); + #endif + 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); + + #ifdef QUALIFIED_NAME + if (pd_library_name) { + char namespacename[MAXPDSTRING]; + sprintf(namespacename, "%s%s%s", pd_library_name, QUALIFIED_NAME, s->s_name); + s=gensym(namespacename); + } + #endif + + 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->name = c->helpname = s; + c->size = size; + c->methods = (t_methodentry *)t_getbytes(0); + c->nmethod = 0; + c->freemethod = (t_method)freemethod; + c->bangmethod = pd_defaultbang; + c->pointermethod = pd_defaultpointer; + c->floatmethod = pd_defaultfloat; + c->symbolmethod = pd_defaultsymbol; + c->listmethod = pd_defaultlist; + c->anymethod = pd_defaultanything; + c->firstin = ((flags & CLASS_NOINLET) == 0); + c->firsttip = gensym("?"); + c->fields = (t_symbol **)malloc(sizeof(t_symbol *)*31); + c->nfields = 0; + c->patchable = (typeflag == CLASS_PATCHABLE); + c->gobj = (typeflag >= CLASS_GOBJ); + c->drawcommand = 0; + c->floatsignalin = 0; + c->externdir = class_extern_dir; + c->savefn = (typeflag == CLASS_PATCHABLE ? text_save : class_nosavefn); + #ifdef QUALIFIED_NAME + c->helpname = S; + // like a class_addcreator + if (pd_library_name && newmethod) { + class_addmethod(pd_objectmaker, (t_method)newmethod, S, vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]); + } + #endif + hash_set(class_table, c->name, c); + 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]); + + #ifdef QUALIFIED_NAME + if (pd_library_name) { + char namespacename[MAXPDSTRING]; + sprintf(namespacename, "%s%s%s", pd_library_name, QUALIFIED_NAME, s->s_name); + s=gensym(namespacename); + } + class_addmethod(pd_objectmaker, (t_method)newmethod, s, vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]); + #endif + hash_set(class_table,s,0); + } + + void class_addmethod2(t_class *c, t_method fn, t_symbol *sel, const char *fmt) { + t_methodentry *m; + int argtype = *fmt++; + int nargs; + /* "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->floatsignalin) post("warning: signal method overrides class_mainsignalin"); + 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!='f' || *fmt) goto phooey; class_doaddfloat(c,fn);} + else if (sel == &s_symbol) {if (argtype!='s' || *fmt) goto phooey; class_addsymbol(c, fn);} + else if (sel == &s_list) {if (argtype!='*') goto phooey; class_addlist(c, fn);} + else if (sel == &s_anything) {if (argtype != A_GIMME) goto phooey; class_addanything(c, fn);} + else { + c->methods = (t_methodentry *)t_resizebytes(c->methods, + c->nmethod * sizeof(*c->methods), (c->nmethod+1) * sizeof(*c->methods)); + m = c->methods + c->nmethod; + c->nmethod++; + m->me_name = sel; + m->me_fun = (t_gotfn)fn; + nargs = 0; + while (argtype && nargs < MAXPDARG) { + t_atomtype t; + switch(argtype) { + case 'f': t=A_FLOAT; break; + case 's': t=A_SYMBOL; break; + case 'p': t=A_POINTER; break; + case ';': t=A_SEMI; break; + case ',': t=A_COMMA; break; + case 'F': t=A_DEFFLOAT; break; + case 'S': t=A_DEFSYMBOL;break; + case '$': t=A_DOLLAR; break; + case '@': t=A_DOLLSYM; break; + case '*': t=A_GIMME; break; + case '!': t=A_CANT; break; + default: goto phooey; + }; + m->me_arg[nargs++] = t; + argtype = *fmt++; + } + if (argtype != A_NULL) + error("%s_%s: only 5 arguments are typecheckable; use A_GIMME", c->name->s_name, sel->s_name); + m->me_arg[nargs] = A_NULL; + } + return; + phooey: + bug("class_addmethod: %s_%s: bad argument types\n", c->name->s_name, sel->s_name); + } + + void class_addmethod(t_class *c, t_method fn, t_symbol *sel, t_atomtype arg1, ...) + { + char fmt[42],*f=fmt; + int t; + va_list ap; + va_start(ap,arg1); + t=arg1; + for(;;) { + if (!t) break; + if (t>A_CANT) {error("class_addmethod: ARRGH! t=%d",t); return;} + *f++ = " fsp;,FS$@*!"[t]; + t=va_arg(ap, t_atomtype); + } + *f = 0; + va_end(ap); + class_addmethod2(c,fn,sel,fmt); + } + + /* see also the "class_addfloat", etc., macros in m_pd.h */ + #undef class_addbang + #undef class_addpointer + #undef class_addsymbol + #undef class_addlist + #undef class_addanything + void class_addbang( t_class *c, t_method fn) { c->bangmethod = (t_bangmethod)fn;} + void class_addpointer( t_class *c, t_method fn) {c->pointermethod = (t_pointermethod)fn;} + void class_doaddfloat( t_class *c, t_method fn) { c->floatmethod = (t_floatmethod)fn;} + void class_addsymbol( t_class *c, t_method fn) {c->symbolmethod = (t_symbolmethod)fn;} + void class_addlist( t_class *c, t_method fn) {c->listmethod = (t_listmethod)fn;} + void class_addanything(t_class *c, t_method fn) { c->anymethod = (t_anymethod)fn;} + + char *class_getname(t_class *c) {return c->name->s_name;} + char *class_gethelpname(t_class *c) {return c->helpname->s_name;} + void class_sethelpsymbol(t_class *c, t_symbol *s) {c->helpname = s;} + void class_setdrawcommand(t_class *c) {c->drawcommand = 1;} + int class_isdrawcommand( t_class *c) {return c->drawcommand;} + void class_setnotice(t_class *c, t_notice notice) {c->notice = notice;} + + static void pd_floatforsignal(t_pd *x, t_float f) { + int offset = (*x)->floatsignalin; + if (offset > 0) + *(t_sample *)(((char *)x) + offset) = f; + else + pd_error(x, "%s: float unexpected for signal input", (*x)->name->s_name); + } + + void class_domainsignalin(t_class *c, int onset) { + if (onset <= 0) onset = -1; + else { + if (c->floatmethod != pd_defaultfloat) + post("warning: %s: float method overwritten", c->name->s_name); + c->floatmethod = (t_floatmethod)pd_floatforsignal; + } + c->floatsignalin = onset; + } + + void class_set_extern_dir(t_symbol *s) {class_extern_dir = s;} + char *class_gethelpdir(t_class *c) {return c->externdir->s_name;} + + static void class_nosavefn(t_gobj *z, t_binbuf *b) { + bug("save function called but not defined"); + } + + void class_setsavefn(t_class *c, t_savefn f) {c->savefn = f;} + t_savefn class_getsavefn(t_class *c) {return c->savefn;} + + /* ---------------- the symbol table ------------------------ */ + + /* tb: new 16 bit hash table: multiplication hash */ + #ifndef NEWHASH + #define HASHSIZE 1024 + #else + #define HASHSIZE 65536 + #define HASHFACTOR 40503 /* donald knuth: (sqrt(5) - 1)/2*pow(2,16) */ + #endif + + #ifdef NEWHASH + static short hash(char *s, size_t n) { + unsigned short hash1 = 0, hash2 = 0; + #else + static int hash(char *s, size_t n) { + unsigned int hash1 = 0, hash2 = 0; + #endif + char *s2 = s; + while (n) { + hash1 += *s2; + hash2 += hash1; + s2++; + n--; + } + return hash2; + } + + /* tb: made dogensym() threadsafe + * supported by vibrez.net */ + t_symbol *dogensym(char *s, size_t n, t_symbol *oldsym) { + static t_symbol *symhash[HASHSIZE]; + #ifdef THREADSAFE_GENSYM + static pthread_mutex_t hash_lock = PTHREAD_MUTEX_INITIALIZER; + #endif + t_symbol **sym1, *sym2; + #ifdef NEWHASH + unsigned short hash2 = hash(s,n); + #else + unsigned int hash2 = hash(s,n); + #endif + #ifdef NEWHASH + hash2 = hash2 * HASHFACTOR; + sym1 = symhash + hash2; + #else + sym1 = symhash + (hash2 & (HASHSIZE-1)); + #endif + while (sym2 = *sym1) { + if (!strcmp(sym2->s_name, s)) return sym2; + sym1 = &sym2->s_next; + } + #ifdef THREADSAFE_GENSYM + pthread_mutex_lock(&hash_lock); + /* tb: maybe another thread added the symbol to the hash table; double check */ + while (sym2 = *sym1) + { + if (!strcmp(sym2->s_name, s)) + { + pthread_mutex_unlock(&hash_lock); + return(sym2); + } + sym1 = &sym2->s_next; + } + #endif + + if (oldsym) sym2 = oldsym; + else { + sym2 = (t_symbol *)t_getbytes(sizeof(*sym2)); + sym2->s_name = (char *)t_getbytes(n+1); + sym2->s_next = 0; + sym2->s_thing = 0; + memcpy(sym2->s_name, s, n); + sym2->s_name[n]=0; + sym2->s_size=n; + } + *sym1 = sym2; + #ifdef THREADSAFE_GENSYM + pthread_mutex_unlock(&hash_lock); + #endif + return sym2; + } + + t_symbol *gensym(char *s) {return dogensym(s,strlen(s),0);} + t_symbol *gensym2(char *s, size_t n) {return dogensym(s,n,0);} + + 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); + + + /* replace everything but [a-zA-Z0-9_] by "0x%x" */ + static char *alternative_classname(char*classname) { + char *altname=(char*)getbytes(sizeof(char)*MAXPDSTRING); + int count=0; + int i=0; + for(i=0; i<MAXPDSTRING; i++) altname[i]=0; + i=0; + while(*classname) { + char c=*classname; + if((c>=48 && c<=57) || (c>=65 && c<=90) || (c>=97 && c<=122) || c==95) { + altname[i]=c; + i++; + } else { + sprintf(altname+i, "0x%02x", c); + i+=4; + count++; + } + classname++; + } + if(count>0)return altname; + /* seems like the given classname is fine as can be */ + freebytes(altname, sizeof(char)*MAXPDSTRING); + return 0; + } + + + /* 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 abstraction. */ + void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv) + { + t_pd *current; + int fd; + char dirbuf[MAXPDSTRING], *nameptr; + if (tryingalready) return; + newest = 0; + class_loadsym = s; + if (sys_load_lib(canvas_getcurrent(), s->s_name)) + { + tryingalready = 1; + typedmess((t_pd *)dummy, s, argc, argv); + tryingalready = 0; + return; + } + class_loadsym = 0; + current = s__X.s_thing; + if ((fd = canvas_open(canvas_getcurrent(), s->s_name, ".pd", dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0 || + (fd = canvas_open(canvas_getcurrent(), s->s_name, ".pat", 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, strlen((*sp)->s_name), *sp); + pd_objectmaker = class_new(gensym("objectmaker"), 0, 0, sizeof(t_pd), CLASS_DEFAULT, A_NULL); + pd_canvasmaker = class_new(gensym("canvasmaker"), 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; + + /* This is externally available, but note that it might later disappear; the + whole "newest" thing is a hack which needs to be redesigned. */ + t_pd *pd_newest(void) {return 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); + + #define REST t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5 + typedef t_pd *(*t_fun0)(REST); + typedef t_pd *(*t_fun1)(t_int i1, REST); + typedef t_pd *(*t_fun2)(t_int i1, t_int i2, REST); + typedef t_pd *(*t_fun3)(t_int i1, t_int i2, t_int i3, REST); + typedef t_pd *(*t_fun4)(t_int i1, t_int i2, t_int i3, t_int i4, REST); + typedef t_pd *(*t_fun5)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, REST); + typedef t_pd *(*t_fun6)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, t_int i6, REST); + #undef REST + + void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv) { + 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->floatmethod(x, 0.); + else if (argv->a_type == A_FLOAT) c->floatmethod(x, argv->a_w.w_float); + else goto badarg; + return; + } + if (s == &s_bang) {c->bangmethod(x); return;} + if (s == &s_list) {c->listmethod(x,s,argc,argv); return;} + if (s == &s_symbol) { + c->symbolmethod(x, argc && argv->a_type==A_SYMBOL ? argv->a_w.w_symbol : &s_); + return; + } + for (i = c->nmethod, m = c->methods; i--; m++) if (m->me_name == s) { + wp = m->me_arg; + if (*wp == A_GIMME) { + if (x == &pd_objectmaker) pd_set_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) goto badarg; + *ap = (t_int)(argv->a_w.w_gpointer); + 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) goto badarg; + *dp = argv->a_w.w_float; + 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) { + #define REST ad[0],ad[1],ad[2],ad[3],ad[4] + case 0 : bonzo = ((t_fun0)(m->me_fun))( REST); break; + case 1 : bonzo = ((t_fun1)(m->me_fun))(ai[0], REST); break; + case 2 : bonzo = ((t_fun2)(m->me_fun))(ai[0],ai[1], REST); break; + case 3 : bonzo = ((t_fun3)(m->me_fun))(ai[0],ai[1],ai[2], REST); break; + case 4 : bonzo = ((t_fun4)(m->me_fun))(ai[0],ai[1],ai[2],ai[3], REST); break; + case 5 : bonzo = ((t_fun5)(m->me_fun))(ai[0],ai[1],ai[2],ai[3],ai[4], REST); break; + case 6 : bonzo = ((t_fun6)(m->me_fun))(ai[0],ai[1],ai[2],ai[3],ai[4],ai[5],REST); break; + default: bonzo = 0; + } + if (x == &pd_objectmaker) pd_set_newest(bonzo); + return; + } + c->anymethod(x, s, argc, argv); + return; + badarg: + pd_error(x, "Bad arguments for message '%s' to object '%s'", s->s_name, 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->nmethod, m = c->methods; i--; m++) if (m->me_name == s) return m->me_fun; + pd_error(x, "%s: no method for message '%s'", 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->nmethod, m = c->methods; i--; m++) if (m->me_name == s) return m->me_fun; + return 0; + } + + void class_settip(t_class *x,t_symbol* s) {x->firsttip = s;} + + /* must be called only once */ + void class_setfieldnames(t_class *x, const char *s) { + char foo[64]; + while (*s) { + char *t = strchr(s,' '); + int i = t-s; + if (!t) return; + memcpy(foo,s,i); + foo[i]=0; + x->fields[x->nfields++] = gensym(foo); + s=s+i+1; + } + } + + int class_getfieldindex(t_class *x, const char *s) { + t_symbol *sy = gensym((char *)s); + int i; + for (i=0; i<x->nfields; i++) if (x->fields[i]==sy) return i; + return -1; + } + + /* O(n) asymptotic time :-} */ + /* only looks for already loaded classes though. */ + + t_class *class_find (t_symbol *s) {return hash_get(class_table,s);} + + void glob_update_class_info (t_pd *bogus, t_symbol *s, t_symbol *cb_recv, t_symbol *cb_sel) { + t_class *c = class_find(s); + if (!c) { post("class not found!"); return; } + sys_vgui("global class_info; set class_info(%s) [list " + "helpname "%s" externdir "%s" size "%d" " + /* + t_methodentry *c_methods; int c_nmethod; + t_method c_freemethod; + t_savefn c_savefn; + int c_floatsignalin; + */ + "gobj "%d" patchable "%d" firstin "%d" " + "firsttip "%s" methods {",s->s_name,c->helpname->s_name,c->externdir->s_name, + c->size,c->gobj,c->patchable,c->firstin,c->firsttip->s_name); + if (c-> bangmethod != pd_defaultbang) sys_vgui("<bang> "); + if (c->pointermethod != pd_defaultpointer) sys_vgui("<pointer> "); + if (c-> floatmethod != pd_defaultfloat) sys_vgui("<float> "); + if (c-> symbolmethod != pd_defaultsymbol) sys_vgui("<symbol> "); + if (c-> listmethod != pd_defaultlist) sys_vgui("<list> "); + if (c-> anymethod != pd_defaultanything) sys_vgui("<any> "); + {int i; for (i=0; i<c->nmethod; i++) sys_vgui("%s ",c->methods[i].me_name->s_name);} + sys_vgui("}]; %s %s %s\n",cb_recv->s_name, cb_sel->s_name, s->s_name); + }
void mess_init(void);