From 8dbec761cf858ea65900c8a094599857208d8c3a Mon Sep 17 00:00:00 2001 From: "N.N." Date: Tue, 5 Jan 2010 22:49:36 +0000 Subject: svn path=/trunk/; revision=12907 --- desiredata/src/kernel.c | 2373 ----------------------------------------------- 1 file changed, 2373 deletions(-) delete mode 100644 desiredata/src/kernel.c (limited to 'desiredata/src/kernel.c') diff --git a/desiredata/src/kernel.c b/desiredata/src/kernel.c deleted file mode 100644 index 08a869e2..00000000 --- a/desiredata/src/kernel.c +++ /dev/null @@ -1,2373 +0,0 @@ -/* $Id: kernel.c,v 1.1.2.92 2007/09/09 21:34:56 matju Exp $ - * Copyright 2006-2007 Mathieu Bouchard. - * Copyright (c) 1997-2006 Miller Puckette. - * For information on usage and redistribution, and for a DISCLAIMER OF ALL - * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -/* IOhannes : - * changed the canvas_restore in "g_canvas.c", so that it might accept $args as well (like "pd $0_test") - * so you can make multiple & distinguishable templates - * 1511:forum::für::umläute:2001 - * change marked with IOhannes - */ - -#define PD_PLUSPLUS_FACE -#include "desire.h" -using namespace desire; -#include "m_simd.h" -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef UNISTD -#include -#endif -#ifdef MSW -#include -#endif - -#define a_float a_w.w_float -#define a_symbol a_w.w_symbol -#define a_gpointer a_w.w_gpointer -#define a_index a_w.w_index - -using namespace std; - -/* T.Grill - bit alignment for signal vectors (must be a multiple of 8!) */ -/* if undefined no alignment occurs */ -#ifdef SIMD_BYTEALIGN - #define VECTORALIGNMENT (SIMD_BYTEALIGN*8) -#else - #define VECTORALIGNMENT 128 -#endif - -void *getbytes(size_t nbytes) { - if (nbytes < 1) nbytes = 1; - void *ret = (void *)calloc(nbytes, 1); - if (!ret) error("pd: getbytes() failed -- out of memory"); - return ret; -} - -void *copybytes(void *src, size_t nbytes) { - void *ret = getbytes(nbytes); - if (nbytes) memcpy(ret, src, nbytes); - return ret; -} - -void *resizebytes(void *old, size_t oldsize, size_t newsize) { - if (newsize < 1) newsize = 1; - if (oldsize < 1) oldsize = 1; - void *ret = (void *)realloc((char *)old, newsize); - if (newsize > oldsize && ret) memset(((char *)ret) + oldsize, 0, newsize - oldsize); - if (!ret) error("pd: resizebytes() failed -- out of memory"); - return ret; -} - -void freebytes(void *old, size_t nbytes) {free(old);} - -/* in the following size_t is assumed to have the same size as a pointer type !!! */ - -/* T.Grill - get aligned memory */ -void *getalignedbytes(size_t nbytes) { - /* to align the region we also need some extra memory to save the original pointer location - it is saved immediately before the aligned vector memory */ - void *vec = getbytes(nbytes+(VECTORALIGNMENT/8-1)+sizeof(void *)); - if (!vec) return 0; - t_int alignment = ((t_int)vec+sizeof(void *))&(VECTORALIGNMENT/8-1); - void *ret = (unsigned char *)vec+sizeof(void *)+(alignment == 0?0:VECTORALIGNMENT/8-alignment); - *(void **)((unsigned char *)ret-sizeof(void *)) = vec; - return ret; -} - -/* T.Grill - free aligned vector memory */ -void freealignedbytes(void *ptr,size_t nbytes) { - free(*(void **)((unsigned char *)ptr-sizeof(void *))); -} - -/* T.Grill - resize aligned vector memory */ -void *resizealignedbytes(void *ptr,size_t oldsize, size_t newsize) { - if (newsize<1) newsize=1; - void *ori = *(void **)((unsigned char *)ptr-sizeof(void *)); - void *vec = realloc(ori,newsize+(VECTORALIGNMENT/8-1)+sizeof(void *)); - t_int alignment = ((t_int)vec+sizeof(void *))&(VECTORALIGNMENT/8-1); - void *ret = (unsigned char *)vec+sizeof(void *)+(alignment == 0?0:VECTORALIGNMENT/8-alignment); - *(void **)((unsigned char *)ret-sizeof(void *)) = vec; - return ret; -} - -/* TB: copy to aligned vector memory */ -void *copyalignedbytes(void *src, size_t nbytes) { - void *ret = getalignedbytes(nbytes); - if (nbytes) memcpy(ret, src, nbytes); - return ret; -} - -t_class *hash_class; - -/*extern "C"*/ void hash_setup () { - hash_class = class_new(gensym("#V"), (t_newmethod)0 /*hash_new*/, - 0 /*(t_method)hash_free*/, sizeof(t_object), CLASS_PD, A_GIMME, 0); -} - -/* convenience routines for checking and getting values of atoms. - There's no "pointer" version since there's nothing safe to return if there's an error. */ - -t_float atom_getfloat( t_atom *a) {return a->a_type==A_FLOAT ? a->a_float : 0;} -t_int atom_getint( t_atom *a) {return (t_int)atom_getfloat(a);} -t_symbol * atom_getsymbol(t_atom *a) {return a->a_type==A_SYMBOL ? a->a_symbol : &s_symbol;} -const char *atom_getstring(t_atom *a) {return atom_getsymbol(a)->name;} - -t_symbol *atom_gensym(t_atom *a) { /* this works better for graph labels */ - if (a->a_type == A_SYMBOL) return a->a_symbol; - if (a->a_type == A_FLOAT) {char buf[30]; sprintf(buf, "%g", a->a_float); return gensym(buf);} - return gensym("???"); -} - -t_float atom_getfloatarg( int which, int argc, t_atom *argv) {return argc<=which ? 0 : atom_getfloat( argv+which);} -t_symbol * atom_getsymbolarg(int which, int argc, t_atom *argv) {return argc<=which ? &s_ : atom_getsymbol(argv+which);} -t_int atom_getintarg( int which, int argc, t_atom *argv) {return t_int(atom_getfloatarg(which,argc,argv));} -const char *atom_getstringarg(int which, int argc, t_atom *argv) {return atom_getsymbolarg(which,argc,argv)->name;} - -/* convert an atom into a string, in the reverse sense of binbuf_text (q.v.) - special attention is paid to symbols containing the special characters - ';', ',', '$', and '\'; these are quoted with a preceding '\', except that - the '$' only gets quoted at the beginning of the string. */ - -//static int should_quote(char *s) {return strchr(";,\\{}\"",*s) || isspace(*s) || (*s=='$' && isdigit(s[1]));} -static int should_quote(char *s) {return strchr(";,\\{}\" ",*s) || (*s=='$' && isdigit(s[1]));} - -void atom_ostream(t_atom *a, ostream &buf) { - switch(a->a_type) { - case A_SEMI: buf << ";"; break; - case A_COMMA: buf << ","; break; - case A_POINTER: buf << "(pointer)"; break; - case A_FLOAT: buf << a->a_float; break; - case A_SYMBOL: { - bool quote=0; - for (char *sp = a->a_symbol->name; *sp; sp++) if (should_quote(sp)) {quote = 1; break;} - if (quote) { - for (char *sp = a->a_symbol->name; *sp; sp++) { - if (should_quote(sp)) buf << '\\'; - buf << *sp; - } - } else buf << a->a_symbol->name; - } break; - case A_DOLLAR: buf << "$" << a->a_index; break; - case A_DOLLSYM: buf << a->a_symbol->name; break; - default: bug("%s",__PRETTY_FUNCTION__); - } -} - -/* this is not completely compatible with Miller's, as it won't do anything special for short bufsizes. */ -void atom_string(t_atom *a, char *buf, unsigned int bufsize) { - ostringstream b; - atom_ostream(a,b); - strncpy(buf,b.str().data(),bufsize); - buf[bufsize-1]=0; -} - -void atom_init(t_atom *a, size_t n) { - for (size_t i=0; i *object_table; - -t_pd *pd_new(t_class *c) { - if (!c) bug("pd_new: apparently called before setup routine"); - t_pd *x = (t_pd *)getbytes(c->size); - x->_class = c; - object_table->set(x,1); - if (c->gobj) ((t_gobj *)x)->g_adix = appendix_new((t_gobj *)x); - if (c->patchable) { - ((t_object *)x)->inlet = 0; - ((t_object *)x)->outlet = 0; - } - return x; -} - -void pd_free_zombie(t_pd *x) { - t_class *c = x->_class; - if (c->gobj) appendix_free((t_gobj *)x); - if (c->size) free(x); - object_table->del(x); -} - -void pd_free(t_pd *x) { - t_class *c = x->_class; - if (c->freemethod) ((t_gotfn)(c->freemethod))(x); - if (c->patchable) { - t_object *y = (t_object *)x; - while (y->outlet) outlet_free(y->outlet); - while (y-> inlet) inlet_free(y-> inlet); - if (y->binbuf) binbuf_free(y->binbuf); - } - /* schedule for deletion if need to keep the allocation around */ - if (c->gobj && (object_table->get(x)&2)) { - object_table->set(x,object_table->get(x)&~1); - gobj_changed((t_gobj *)x,""); - //char *xx = (char *)x; for (int i=0; isize; i++) xx[i]="\xde\xad\xbe\xef"[i&3]; - } else pd_free_zombie(x); -} - -void gobj_save(t_gobj *x, t_binbuf *b) { - t_class *c = x->g_pd; - if (c->savefn) c->savefn(x, b); -} - -/* deal with several objects bound to the same symbol. If more than one, - we actually bind a collection object to the symbol, which forwards messages sent to the symbol. */ - -static t_class *bindlist_class; - -struct t_bindelem { - t_pd *who; - t_bindelem *next; -}; - -struct t_bindlist : t_pd { - t_bindelem *list; -}; - -#define bind_each(e,x) for (t_bindelem *e = x->list; e; e = e->next) -static void bindlist_bang (t_bindlist *x) {bind_each(e,x) pd_bang(e->who);} -static void bindlist_float (t_bindlist *x, t_float f) {bind_each(e,x) pd_float(e->who,f);} -static void bindlist_symbol (t_bindlist *x, t_symbol *s) {bind_each(e,x) pd_symbol(e->who,s);} -static void bindlist_pointer (t_bindlist *x, t_gpointer *gp) {bind_each(e,x) pd_pointer(e->who, gp);} -static void bindlist_list (t_bindlist *x, t_symbol *s, int argc, t_atom *argv) {bind_each(e,x) pd_list(e->who, s,argc,argv);} -static void bindlist_anything(t_bindlist *x, t_symbol *s, int argc, t_atom *argv) {bind_each(e,x) pd_typedmess(e->who, s,argc,argv);} - -static t_bindelem *bindelem_new(t_pd *who, t_bindelem *next) { - t_bindelem *self = (t_bindelem *)malloc(sizeof(t_bindelem)); - self->who = who; - self->next = next; - return self; -} - -void pd_bind(t_pd *x, t_symbol *s) { - if (s->thing) { - if (s->thing->_class == bindlist_class) { - t_bindlist *b = (t_bindlist *)s->thing; - b->list = bindelem_new(x,b->list); - } else { - t_bindlist *b = (t_bindlist *)pd_new(bindlist_class); - b->list = bindelem_new(x,bindelem_new(s->thing,0)); - s->thing = b; - } - } else s->thing = x; -} - -/* bindlists always have at least two elements... if the number - goes down to one, get rid of the bindlist and bind the symbol - straight to the remaining element. */ -void pd_unbind(t_pd *x, t_symbol *s) { - if (s->thing == x) {s->thing = 0; return;} - if (s->thing && s->thing->_class == bindlist_class) { - t_bindlist *b = (t_bindlist *)s->thing; - t_bindelem *e, *e2; - if ((e = b->list)->who == x) { - b->list = e->next; - free(e); - } else for (e = b->list; (e2=e->next); e = e2) if (e2->who == x) { - e->next = e2->next; - free(e2); - break; - } - if (!b->list->next) { - s->thing = b->list->who; - free(b->list); - pd_free(b); - } - } else error("%s: couldn't unbind", s->name); -} - -t_pd *pd_findbyclass(t_symbol *s, t_class *c) { - t_pd *x = 0; - if (!s->thing) return 0; - if (s->thing->_class == c) return s->thing; - if (s->thing->_class == bindlist_class) { - t_bindlist *b = (t_bindlist *)s->thing; - int warned = 0; - bind_each(e,b) if (e->who->_class == c) { - if (x && !warned) {post("warning: %s: multiply defined", s->name); warned = 1;} - x = e->who; - } - } - return x; -} - -/* stack for maintaining bindings for the #X symbol during nestable loads. */ - -#undef g_next - -struct t_gstack { - t_pd *what; - t_symbol *loading_abstr; - t_gstack *next; - long base_o_index; -}; - -static t_gstack *gstack_head = 0; -static t_pd *lastpopped; -static t_symbol *pd_loading_abstr; - -int pd_setloadingabstraction(t_symbol *sym) { - t_gstack *foo = gstack_head; - for (foo = gstack_head; foo; foo = foo->next) if (foo->loading_abstr == sym) return 1; - pd_loading_abstr = sym; - return 0; -} - -int gstack_empty() {return !gstack_head;} - -long canvas_base_o_index() { - return gstack_head ? gstack_head->base_o_index : 0; -} - -void pd_pushsym(t_pd *x) { - t_gstack *y = (t_gstack *)malloc(sizeof(*y)); - y->what = s__X.thing; - y->next = gstack_head; - y->loading_abstr = pd_loading_abstr; - y->base_o_index = x->_class == canvas_class ? ((t_canvas *)x)->next_o_index : -666; - pd_loading_abstr = 0; - gstack_head = y; - s__X.thing = x; -} - -void pd_popsym(t_pd *x) { - if (!gstack_head || s__X.thing != x) {bug("gstack_pop"); return;} - t_gstack *headwas = gstack_head; - s__X.thing = headwas->what; - gstack_head = headwas->next; - free(headwas); - lastpopped = x; -} - -static void stackerror(t_pd *x) {error("stack overflow");} - -/* to enable multithreading, make those variables "thread-local". this means that they have to go in - a thread-specific place instead of plain global. do not ever use tim's atomic counters for this, - as they count all threads together as if they're one, and they're especially incompatible with - use of the desiredata-specific stack[] variable. */ -int pd_stackn = 0; /* how much of the stack is in use */ -t_call pd_stack[STACKSIZE]; - -static inline uint64 rdtsc() {uint64 x; __asm__ volatile (".byte 0x0f, 0x31":"=A"(x)); return x;} - -//#define PROFILER -#ifdef PROFILER -#define ENTER_PROF uint64 t = rdtsc(); -#define LEAVE_PROF if (x->_class->gobj && ((t_gobj *)x)->dix) ((t_gobj *)x)->dix->elapsed += rdtsc() - t; -#else -#define ENTER_PROF -#define LEAVE_PROF -#endif - -#define ENTER(SELECTOR) if(pd_stackn >= STACKSIZE) {stackerror(x); return;} \ - pd_stack[pd_stackn].self = x; pd_stack[pd_stackn].s = SELECTOR; pd_stackn++; ENTER_PROF -#define LEAVE pd_stackn--; LEAVE_PROF - -/* matju's 2007.07.14 inlet-based stack check needs to be implemented in: - pd_bang pd_float pd_pointer pd_symbol pd_string pd_list pd_typedmess */ -void pd_bang(t_pd *x) {ENTER(&s_bang); x->_class->bangmethod(x); LEAVE;} -void pd_float(t_pd *x, t_float f) {ENTER(&s_float); x->_class->floatmethod(x,f); LEAVE;} -void pd_pointer(t_pd *x, t_gpointer *gp) {ENTER(&s_pointer); x->_class->pointermethod(x,gp); LEAVE;} -void pd_symbol(t_pd *x, t_symbol *s) {ENTER(&s_symbol); x->_class->symbolmethod(x,s); LEAVE;} -/* void pd_string(t_pd *x, const char *s){ENTER(&s_symbol); x->_class->stringmethod(x,s); LEAVE;} future use */ -void pd_list(t_pd *x, t_symbol *s, int ac, t_atom *av) {ENTER(s); x->_class->listmethod(x,&s_list,ac,av); LEAVE;} - -/* this file handles Max-style patchable objects, i.e., objects which -can interconnect via inlets and outlets; also, the (terse) generic -behavior for "gobjs" appears at the end of this file. */ - -union inletunion { - t_symbol *symto; - t_gpointer *pointerslot; - t_float *floatslot; - t_symbol **symslot; - t_sample floatsignalvalue; -}; - -struct _inlet : t_pd { - struct _inlet *next; - t_object *owner; - t_pd *dest; - t_symbol *symfrom; - union inletunion u; - t_symbol* tip; -}; - -static t_class *inlet_class, *pointerinlet_class, *floatinlet_class, *symbolinlet_class; - -#define ISINLET(pd) ( \ - pd->_class == inlet_class || \ - pd->_class == pointerinlet_class || \ - pd->_class == floatinlet_class || \ - pd->_class == symbolinlet_class) - -/* --------------------- generic inlets ala max ------------------ */ - -static void object_append_inlet(t_object *owner, t_inlet *x) { - t_inlet *y = owner->inlet, *y2; - if (y) { - while ((y2 = y->next)) y = y2; - y->next = x; - } else owner->inlet = x; -} - -t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2) { - t_inlet *x = (t_inlet *)pd_new(inlet_class); - x->owner = owner; - x->dest = dest; - if (s1 == &s_signal) x->u.floatsignalvalue = 0; else x->u.symto = s2; - x->symfrom = s1; - x->next = 0; - x->tip = gensym("?"); - object_append_inlet(owner,x); - return x; -} - -t_inlet *signalinlet_new(t_object *owner, t_float f) { - t_inlet *x = inlet_new(owner, owner, &s_signal, &s_signal); - x->u.floatsignalvalue = f; - return x; -} - -static void inlet_wrong(t_inlet *x, t_symbol *s) { - error("inlet: expected '%s' but got '%s'", x->symfrom->name, s->name); -} - -void inlet_settip(t_inlet* i,t_symbol* s) {i->tip = s;} - -const char *inlet_tip(t_inlet* i,int num) { - if (num < 0) return "???"; - while (num-- && i) i = i->next; - if (i && i->tip) return i->tip->name; - return "?"; -} - -static void inlet_bang(t_inlet *x) { - if (x->symfrom == &s_bang) pd_vmess(x->dest, x->u.symto, ""); - else if (!x->symfrom) pd_bang(x->dest); - else inlet_wrong(x, &s_bang);} -static void inlet_pointer(t_inlet *x, t_gpointer *gp) { - if (x->symfrom == &s_pointer) pd_vmess(x->dest, x->u.symto, "p", gp); - else if (!x->symfrom) pd_pointer(x->dest, gp); - else inlet_wrong(x, &s_pointer);} -static void inlet_float(t_inlet *x, t_float f) { - if (x->symfrom == &s_float) pd_vmess(x->dest, x->u.symto, "f", (t_floatarg)f); - else if (x->symfrom == &s_signal) x->u.floatsignalvalue = f; - else if (!x->symfrom) pd_float(x->dest, f); - else inlet_wrong(x, &s_float);} -static void inlet_symbol(t_inlet *x, t_symbol *s) { - if (x->symfrom == &s_symbol) pd_vmess(x->dest, x->u.symto, "s", s); - else if (!x->symfrom) pd_symbol(x->dest, s); - else inlet_wrong(x, &s_symbol);} -static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv) { - if (x->symfrom == &s_list || x->symfrom == &s_float || x->symfrom == &s_symbol || x->symfrom == &s_pointer) - typedmess(x->dest, x->u.symto, argc, argv); - else if (!x->symfrom) pd_list(x->dest, s, argc, argv); - else inlet_wrong(x, &s_list);} -static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv) { - if (x->symfrom == s) typedmess(x->dest, x->u.symto, argc, argv); - else if (!x->symfrom) typedmess(x->dest, s, argc, argv); - else inlet_wrong(x, s);} - -void inlet_free(t_inlet *x) { - t_object *y = x->owner; - if (y->inlet == x) y->inlet = x->next; - else for (t_inlet *x2 = y->inlet; x2; x2 = x2->next) if (x2->next == x) {x2->next = x->next; break;} - pd_free(x); -} - -/* ----- pointerinlets, floatinlets, syminlets: optimized inlets ------- */ - -static void pointerinlet_pointer(t_inlet *x, t_gpointer *gp) { - gpointer_unset(x->u.pointerslot); - *(x->u.pointerslot) = *gp; - if (gp->o) gp->o->refcount++; -} - -static void floatinlet_float( t_inlet *x, t_float f) {*x->u.floatslot = f;} -static void symbolinlet_symbol(t_inlet *x, t_symbol *s) {*x->u.symslot = s;} - -#define COMMON(qlass,sym,slot) \ - t_inlet *x=(t_inlet *)pd_new(qlass); \ - x->symfrom=&sym; \ - x->u.slot = p; \ - x->owner = owner; \ - x->dest = 0; \ - x->next = 0; \ - object_append_inlet(owner,x); \ - return x; - -t_inlet * floatinlet_new(t_object *owner, t_float * p) {COMMON( floatinlet_class,s_float ,floatslot )} -t_inlet * symbolinlet_new(t_object *owner, t_symbol ** p) {COMMON( symbolinlet_class,s_symbol ,symslot )} -t_inlet *pointerinlet_new(t_object *owner, t_gpointer *p) {COMMON(pointerinlet_class,s_pointer,pointerslot)} -#undef COMMON - -/* ---------------------- routine to handle lists ---------------------- */ - -/* objects interpret lists by feeding them to the individual inlets. Before you call this, - check that the object doesn't have a more specific way to handle lists. */ -void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv) { - t_atom *ap; - int count; - t_inlet *ip = ((t_object *)x)->inlet; - if (!argc) return; - for (count = argc-1, ap = argv+1; ip && count--; ap++, ip = ip->next) { - if (ap->a_type == A_POINTER) pd_pointer(ip,ap->a_gpointer); - else if (ap->a_type == A_FLOAT) pd_float(ip,ap->a_float); - else pd_symbol(ip,ap->a_symbol); - } - if (argv->a_type == A_POINTER) pd_pointer(x,argv->a_gpointer); - else if (argv->a_type == A_FLOAT) pd_float(x,argv->a_float); - else pd_symbol(x,argv->a_symbol); -} - -void obj_init () { - inlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0); - floatinlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0); - symbolinlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0); - pointerinlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0); - class_addbang(inlet_class, inlet_bang); - class_addpointer(inlet_class, inlet_pointer); - class_addfloat(inlet_class, inlet_float); - class_addsymbol(inlet_class, inlet_symbol); - class_addlist(inlet_class, inlet_list); - class_addanything(inlet_class, inlet_anything); - class_addfloat( floatinlet_class, floatinlet_float); - class_addsymbol( symbolinlet_class, symbolinlet_symbol); - class_addpointer(pointerinlet_class, pointerinlet_pointer); -} - -/* --------------------------- outlets ------------------------------ */ - -/* this is fairly obsolete stuff, I think */ -static int outlet_eventno; -void outlet_setstacklim () {outlet_eventno++;} -int sched_geteventno( void) {return outlet_eventno;} - -t_inlet *t_object:: in(int n) {t_inlet *i= inlet; while(n--) i=i->next; return i;} -t_outlet *t_object::out(int n) {t_outlet *o=outlet; while(n--) o=o->next; return o;} - -t_class *wire_class; -t_wire *wire_new (t_symbol *s, int argc, t_atom *argv) { - t_wire *self = (t_wire *)pd_new(wire_class); - self->g_adix = appendix_new((t_gobj *)self); - return self; -} -void wire_free (t_wire *self) {/* nothing here */} - -/* this is only used for pd_upload yet, right? so, it can use the new indices instead already */ -void wire_save (t_wire *self, t_binbuf *b) { -// t_canvas *c = self->dix->canvas; - binbuf_addv(b,"ttiiii;","#X","connect", -// canvas_getindex(c,self->from), self->outlet, -// canvas_getindex(c,self->to ), self-> inlet); - self->from->dix->index, self->outlet, - self->to ->dix->index, self-> inlet); - appendix_save((t_gobj *)self,b); -} - -t_outlet *outlet_new(t_object *owner, t_symbol *s) { - t_outlet *x = (t_outlet *)malloc(sizeof(*x)), *y, *y2; - x->owner = owner; - x->next = 0; - y = owner->outlet; - if (y) { - while ((y2 = y->next)) y = y2; - y->next = x; - } else owner->outlet = x; - x->connections = 0; - x->sym = s; - return x; -} - -#define each_connect(oc,x) for (t_outconnect *oc = x->connections; oc; oc = oc->next) -void outlet_bang(t_outlet *x) {each_connect(oc,x) pd_bang( oc->oc_to);} -void outlet_pointer(t_outlet *x, t_gpointer *v) {t_gpointer gp = *v; each_connect(oc,x) pd_pointer(oc->oc_to,&gp);} -void outlet_float(t_outlet *x, t_float v) {each_connect(oc,x) pd_float( oc->oc_to,v);} -void outlet_symbol(t_outlet *x, t_symbol *v) {each_connect(oc,x) pd_symbol( oc->oc_to,v);} -void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv) {each_connect(oc,x) pd_list( oc->oc_to,s,argc,argv);} -void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv){each_connect(oc,x) typedmess( oc->oc_to,s,argc,argv);} - -void outlet_atom(t_outlet *x, t_atom *a) { - if (a->a_type==A_FLOAT ) x->send(a->a_float); - else if (a->a_type==A_SYMBOL ) x->send(a->a_symbol); - else if (a->a_type==A_POINTER) x->send(a->a_gpointer); - else error("can't send atom whose type is %d",a->a_type); -} - -/* get the outlet's declared symbol */ -t_symbol *outlet_getsymbol(t_outlet *x) {return x->sym;} - -void outlet_free(t_outlet *x) { - t_object *y = x->owner; - if (y->outlet == x) y->outlet = x->next; - else for (t_outlet *x2 = y->outlet; x2; x2 = x2->next) if (x2->next == x) { - x2->next = x->next; - break; - } - free(x); -} - -#define each_inlet(i,obj) for ( t_inlet *i=obj->inlet ; i; i=i->next) -#define each_outlet(o,obj) for (t_outlet *o=obj->outlet; o; o=o->next) - -static t_pd *find_inlet(t_object *to, int inlet) { - if (to->_class->firstin) {if (inlet) inlet--; else return (t_pd *)to;} - each_inlet(i,to) if (inlet) inlet--; else return (t_pd *)i; - return 0; -} - -static t_outlet *find_outlet(t_object *from, int outlet) { - each_outlet(o,from) if (outlet) outlet--; else return o; - return 0; -} - -t_outconnect *obj_connect(t_object *from, int outlet, t_object *to, int inlet) { - t_outlet *o = find_outlet(from,outlet); - t_pd *i = find_inlet(to,inlet); - if (!o||!i) return 0; - t_outconnect *oc = wire_new(0,0,0), *oc2; - oc->next = 0; - oc->oc_to = i; - oc->from = from; oc->outlet = outlet; - oc->to = to; oc->inlet = inlet; - /* append it to the end of the list */ - /* LATER we might cache the last "oc" to make this faster. */ - if ((oc2 = o->connections)) { - while (oc2->next) oc2 = oc2->next; - oc2->next = oc; - } else o->connections = oc; - if (o->sym == &s_signal) canvas_update_dsp(); - return oc; -} - -void obj_disconnect(t_object *from, int outlet, t_object *to, int inlet) { - t_outlet *o = find_outlet(from,outlet); if (!o) {post("outlet does not exist"); return;} - t_pd *i = find_inlet(to, inlet); if (!i) {post( "inlet does not exist"); return;} - t_outconnect *oc = o->connections, *oc2; - if (!oc) {post("outlet has no connections"); return;} - if (oc->oc_to == i) { - o->connections = oc->next; - pd_free(oc); - goto done; - } - while ((oc2 = oc->next)) { - if (oc2->oc_to == i) { - oc->next = oc2->next; - pd_free(oc2); - goto done; - } - oc = oc2; - } - post("connection not found"); -done: - if (o->sym == &s_signal) canvas_update_dsp(); -} - -/* ------ traversal routines for code that can't see our structures ------ */ - -int obj_noutlets(t_object *x) { - int n=0; - each_outlet(o,x) n++; - return n; -} - -int obj_ninlets(t_object *x) { - int n=!!x->_class->firstin; - each_inlet(i,x) n++; - return n; -} - -t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout) { - t_outlet *o = x->outlet; - while (nout-- && o) o = o->next; - *op = o; - return o ? o->connections : 0; -} - -t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect, t_object **destp, t_inlet **inletp, int *whichp) { - t_pd *y = lastconnect->oc_to; - if (ISINLET(y)) { - t_inlet *i = (t_inlet *)y; - t_object *dest = i->owner; - int n = dest->_class->firstin; - each_inlet(i2,dest) if (i2==i) break; else n++; - *whichp = n; - *destp = dest; - *inletp = i; - } else { - *whichp = 0; - *inletp = 0; - *destp = (t_object *)y; - } - return lastconnect->next; -} - -/* this one checks that a pd is indeed a patchable object, and returns it, - correctly typed, or zero if the check failed. */ -t_object *pd_checkobject(t_pd *x) { - return x->_class->patchable ? (t_object *)x : 0; -} - -/* move an inlet or outlet to the head of the list. this code is not safe with the latest additions in t_outconnect ! */ -void obj_moveinletfirst( t_object *x, t_inlet *i) {if (x->inlet == i) return; - each_inlet( i2,x) if (i2->next == i) {i2->next = i->next; i->next = x-> inlet; x-> inlet = i; return;}} -void obj_moveoutletfirst(t_object *x, t_outlet *o) {if (x->outlet == o) return; - each_outlet(o2,x) if (o2->next == o) {o2->next = o->next; o->next = x->outlet; x->outlet = o; return;}} - -/* routines for DSP sorting, which are used in d_ugen.c and g_canvas.c */ -/* LATER try to consolidate all the slightly different routines. */ - -int obj_nsiginlets(t_object *x) { - int n=0; - each_inlet(i,x) if (i->symfrom == &s_signal) n++; - if (x->_class->firstin && x->_class->floatsignalin) n++; - return n; -} -int obj_nsigoutlets(t_object *x) { - int n=0; - each_outlet(o,x) if (o->sym == &s_signal) n++; - return n; -} - -/* get the index, among signal inlets, of the mth inlet overall */ -int obj_siginletindex(t_object *x, int m) { - int n=0; - if (x->_class->firstin && x->_class->floatsignalin) {if (!m--) return 0; else n++;} - each_inlet(i,x) if (i->symfrom == &s_signal) {if (!m) return n; else {n++; m--;}} - return -1; -} -int obj_sigoutletindex(t_object *x, int m) { - int n=0; - each_outlet(o,x) if (o->sym == &s_signal) {if (!m) return n; else {n++; m--;}} - return -1; -} - -int obj_issignalinlet(t_object *x, int m) { - if (x->_class->firstin) {if (!m) return x->_class->floatsignalin; else m--;} - t_inlet *i; - for (i = x->inlet; i && m; i = i->next, m--) {} - return i && i->symfrom==&s_signal; -} -int obj_issignaloutlet(t_object *x, int m) { - t_outlet *o2; - for (o2 = x->outlet; o2 && m--; o2 = o2->next) {} - return o2 && o2->sym==&s_signal; -} - -t_sample *obj_findsignalscalar(t_object *x, int m) { - int n = 0; - t_inlet *i; - if (x->_class->firstin && x->_class->floatsignalin) { - if (!m--) return x->_class->floatsignalin > 0 ? (t_sample *)(((char *)x) + x->_class->floatsignalin) : 0; - n++; - } - for (i = x->inlet; i; i = i->next, m--) if (i->symfrom == &s_signal) { - if (m == 0) return &i->u.floatsignalvalue; - n++; - } - return 0; -} - -/* and those two are only used in desire.c... */ -int inlet_getsignalindex(t_inlet *x) { - int n=0; for ( t_inlet *i = x->owner-> inlet; i; i = i->next) if (i==x) return n; else if (i->symfrom == &s_signal) n++; - return -1;} -int outlet_getsignalindex(t_outlet *x) { - int n=0; for (t_outlet *o = x->owner->outlet; o; o = o->next) if (o==x) return n; else if (o->sym == &s_signal) n++; - return -1;} - -#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) { - error("%s: no method for '%s'", x->_class->name->name, 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); -} - -t_symbol *qualified_name(t_symbol *s) { - char *buf; - asprintf(&buf, "%s%s%s", pd_library_name, QUALIFIED_NAME, s->name); - t_symbol *sym = gensym(buf); - free(buf); - return sym; -} - -#undef class_new2 -#undef class_addcreator2 -#undef class_addmethod2 - -/* Note that some classes such as "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. */ -t_class *class_new2(const char *ss, t_newmethod newmethod, t_method freemethod, -size_t size, int flags, const char *sig) { - t_symbol *s = ss?gensym(ss):0; - int typeflag = flags & CLASS_TYPEMASK; - if (!typeflag) typeflag = CLASS_PATCHABLE; -#ifdef QUALIFIED_NAME - if (pd_library_name) s = qualified_name(s); -#endif - if (pd_objectmaker._class && newmethod) { - /* add a "new" method by the name specified by the object */ - class_addmethod2(pd_objectmaker._class, (t_method)newmethod, s->name, sig); - 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->name, l1 = strlen(s->name), l2 = strlen(loadstring); - if (l2 > l1 && !strcmp(s->name, loadstring + (l2 - l1))) - class_addmethod2(pd_objectmaker._class, (t_method)newmethod, class_loadsym->name, sig); - } - } - t_class *c = (t_class *)malloc(sizeof(*c)); - c->name = c->helpname = s; - c->size = size; - c->methods = (t_methodentry *)malloc(1); - 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 - // like a class_addcreator - if (pd_library_name && newmethod) class_addmethod2(pd_objectmaker._class, (t_method)newmethod, ss, sig); -#endif - c->onsubscribe = gobj_onsubscribe; - class_table->set(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_addcreator2(const char *ss, t_newmethod newmethod, const char *sig) { - t_symbol *s = gensym(ss); - class_addmethod2(pd_objectmaker._class, (t_method)newmethod, ss, sig); -#ifdef QUALIFIED_NAME - class_addmethod2(pd_objectmaker._class, (t_method)newmethod, pd_library_name ? qualified_name(s)->name : ss, sig); -#endif - class_table->set(s,0); -} - -void class_addmethod2(t_class *c, t_method fn, const char *ss, const char *fmt) { - t_symbol *sel = gensym(ss); - t_methodentry *m; - int argtype = *fmt++; - /* "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. */ - /* is anyone actually using those five cases? */ - 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!='*') goto phooey; class_addanything(c,fn);} - else { - /* SLOW, especially for [objectmaker] */ - c->methods = (t_methodentry *)realloc(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; - int 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) error("%s_%s: only 5 arguments are typecheckable; use A_GIMME aka '*'", c->name->name, sel->name); - m->me_arg[nargs] = A_NULL; - } - return; -phooey: - bug("class_addmethod: %s_%s: bad argument types", c->name->name, sel->name); -} - -#define COMMON(R) \ - char fmt[42],*f=fmt; va_list ap; va_start(ap,arg1); int t=arg1; \ - while(t) {if (t>A_CANT) {error("%s: ARRGH! t=%d",__func__,t); return R;} *f++ = " fsp;,FS$@*!"[t]; t=(t_atomtype)va_arg(ap,int);} \ - *f=0; va_end(ap); - -t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod, size_t size, int flags, t_atomtypearg arg1, ...) { - COMMON(0); return class_new2(s?s->name:0,newmethod,freemethod,size,flags,fmt); -} -void class_addcreator(t_newmethod newmethod, t_symbol *s, t_atomtypearg arg1, ...) { - COMMON(); class_addcreator2(s?s->name:0,newmethod,fmt); -} -void class_addmethod(t_class *c, t_method fn, t_symbol *sel, t_atomtypearg arg1, ...) { - COMMON(); class_addmethod2(c,fn,sel->name,fmt); -} -#undef COMMON - -/* 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->name;} -char *class_gethelpname( t_class *c) {return c->helpname->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 ;} -void class_setonsubscribe(t_class *c, t_onsubscribe onsubscribe) {c->onsubscribe = onsubscribe;} - -static void pd_floatforsignal(t_pd *x, t_float f) { - int offset = x->_class->floatsignalin; - if (offset>0) *(t_sample *)((char *)x + offset) = f; - else error("%s: float unexpected for signal input", x->_class->name->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->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->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(const char *s, size_t n) { - unsigned short hash1 = 0, hash2 = 0; -#else -static int hash(const char *s, size_t n) { - unsigned int hash1 = 0, hash2 = 0; -#endif - const char *s2 = s; - while (n) { - hash1 += *s2; - hash2 += hash1; - s2++; - n--; - } - return hash2; -} - -/* tb: made dogensym() threadsafe */ -static t_symbol *symhash[HASHSIZE]; -t_symbol *dogensym(const char *s, size_t n, t_symbol *oldsym) { -#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->name, s)) return sym2; - sym1 = &sym2->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->name, s)) { - pthread_mutex_unlock(&hash_lock); - return sym2; - } - sym1 = &sym2->next; - } -#endif - - if (oldsym) sym2 = oldsym; - else { - sym2 = (t_symbol *)malloc(sizeof(*sym2)); - sym2->name = (char *)malloc(n+1); - sym2->next = 0; - sym2->thing = 0; - memcpy(sym2->name, s, n); - sym2->name[n]=0; - sym2->n=n; - } - *sym1 = sym2; -#ifdef THREADSAFE_GENSYM - pthread_mutex_unlock(&hash_lock); -#endif - return sym2; -} - -t_symbol *gensym( const char *s) {return dogensym(s,strlen(s),0);} -t_symbol *gensym2(const char *s, size_t n) {return dogensym(s,n,0);} -extern "C" t_symbol *symprintf(const char *s, ...) { - char *buf; - va_list args; - va_start(args,s); - vasprintf(&buf,s,args); - va_end(args); - t_symbol *r = gensym(buf); - free(buf); - return r; -} - -bool symbol_lt (t_symbol *a, t_symbol *b) {return strcmp(a->name,b->name)<0;} - -void glob_symbol_table (t_pd *, float onlybound) { - post("symbol_table = {"); - std::vector all; - for (size_t i=0; inext) all.push_back(s); - sort(all.begin(),all.end(),symbol_lt); - for (size_t i=0; ithing) { - if (all[i]->thing->_class==bindlist_class) j=2; else j=1; - } - if (j>0 || !onlybound) post(" %0*lx: %s (%d)",2*sizeof(void*),long(all[i]),all[i]->name,j); - } - post("}"); -} - -static int tryingalready; -extern "C" 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 abstraction. */ -void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv) { - int fd; - char *dirbuf, *nameptr; - if (tryingalready) return; - newest = 0; - class_loadsym = s; - if (sys_load_lib(canvas_getcurrent(), s->name)) { - tryingalready = 1; - typedmess((t_pd *)dummy, s, argc, argv); - tryingalready = 0; - return; - } - class_loadsym = 0; - t_pd *current = s__X.thing; - if ((fd = canvas_open2(canvas_getcurrent(), s->name, ".pd", &dirbuf, &nameptr, 0)) >= 0 || - (fd = canvas_open2(canvas_getcurrent(), s->name, ".pat", &dirbuf, &nameptr, 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.thing != current) canvas_popabstraction((t_canvas *)s__X.thing); - canvas_setargs(0, 0); - } else error("%s: can't load abstraction within itself", s->name); - free(dirbuf); - } else newest = 0; -} - -#define MAKESYM(CSYM,S) t_symbol CSYM = {(char *)(S),0,0,1,0xdeadbeef}; -MAKESYM(s_pointer ,"pointer") -MAKESYM(s_float ,"float") -MAKESYM(s_symbol ,"symbol") -MAKESYM(s_bang ,"bang") -MAKESYM(s_list ,"list") -MAKESYM(s_anything,"anything") -MAKESYM(s_signal ,"signal") -MAKESYM(s__N ,"#N") -MAKESYM(s__X ,"#X") -MAKESYM(s_x ,"x") -MAKESYM(s_y ,"y") -MAKESYM(s_ ,"") - -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_}; - -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 () {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_2(t_pd *x, t_symbol *s, int argc, t_atom *argv) { - t_class *c = x->_class; - t_atomtype *wp, wanttype; - t_int ai[MAXPDARG+1], *ap = ai; - t_floatarg ad[MAXPDARG+1], *dp = ad; - int narg = 0; - /* 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_float); - else error("expected one float, in class [%s]", c->name->name); - 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_symbol : &s_); return;} - t_methodentry *m = c->methods; - for (int i = c->nmethod; 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; - if (argv->a_type!=A_POINTER) goto badarg; - *ap = t_int(argv->a_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_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_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_float == 0) - *ap = t_int(&s_); - else goto badarg; - argc--; argv++; - } - narg++; - ap++; - default: {} - } - } - t_pd *bonzo; - 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: - error("Bad arguments for message '%s' to object '%s'", s->name, c->name->name); -} - -void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv) { - ENTER(s); pd_typedmess_2(x,s,argc,argv); LEAVE; -} - -void pd_vmess(t_pd *x, t_symbol *sel, const char *fmt, ...) { - va_list ap; - t_atom arg[MAXPDARG], *at =arg; - int nargs = 0; - const char *fp = fmt; - va_start(ap, fmt); - while (1) { - if (nargs > MAXPDARG) { - error("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_symbol, argc-1, argv+1); - else if (t==A_POINTER) {if (argc==1) pd_pointer(x, argv->a_gpointer); else pd_list(x, &s_list, argc, argv);} - else if (t==A_FLOAT) {if (argc==1) pd_float( x, argv->a_float); else pd_list(x, &s_list, argc, argv);} - else bug("pd_forwardmess"); - } -} - -void nullfn () {} - -t_gotfn getfn(t_pd *x, t_symbol *s) { - t_class *c = x->_class; t_methodentry *m = c->methods; - for (int i=c->nmethod; i--; m++) if (m->me_name == s) return m->me_fun; - error("%s: no method for message '%s'", c->name->name, s->name); - return (t_gotfn)nullfn; -} -t_gotfn zgetfn(t_pd *x, t_symbol *s) { - t_class *c = x->_class; t_methodentry *m = c->methods; - for (int i=c->nmethod; 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) { - const 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); - for (int i=0; infields; i++) if (x->fields[i]==sy) return i; - return -1; -} - -/* only looks for already loaded classes though. */ -t_class *class_find (t_symbol *s) {return (t_class *)class_table->get(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->name,c->helpname->name,c->externdir->name, - c->size,c->gobj,c->patchable,c->firstin,c->firsttip->name); - if (c-> bangmethod != pd_defaultbang) sys_vgui(" "); - if (c->pointermethod != pd_defaultpointer) sys_vgui(" "); - if (c-> floatmethod != pd_defaultfloat) sys_vgui(" "); - if (c-> symbolmethod != pd_defaultsymbol) sys_vgui(" "); - if (c-> listmethod != pd_defaultlist) sys_vgui(" "); - if (c-> anymethod != pd_defaultanything) sys_vgui(" "); - for (int i=0; inmethod; i++) sys_vgui("%s ",c->methods[i].me_name->name); - sys_vgui("}]; %s %s %s\n",cb_recv->name, cb_sel->name, s->name); -} - -t_class *binbuf_class; - -t_binbuf *binbuf_new () { - t_binbuf *x = (t_binbuf *)pd_new(binbuf_class); - x->n = 0; - x->capa = 1; - x->v = (t_atom *)malloc(1*sizeof(t_atom)); - return x; -} - -/* caution: capa >= x->n and capa >= 1 too */ -static void binbuf_capa(t_binbuf *x, int capa) { - x->v = (t_atom *)realloc(x->v, capa*sizeof(*x->v)); - x->capa = capa; -} - -void binbuf_free(t_binbuf *x) {pd_free(x);} -void binbuf_free2(t_binbuf *x) {free(x->v);} - -t_binbuf *binbuf_duplicate(t_binbuf *y) { - t_binbuf *x = (t_binbuf *)malloc(sizeof(*x)); - x->capa = x->n = y->n; - x->v = (t_atom *)malloc(x->n * sizeof(*x->v)); - memcpy(x->v,y->v,x->n*sizeof(*x->v)); - return x; -} - -void binbuf_clear(t_binbuf *x) { - x->n = 0; - x->v = (t_atom *)realloc(x->v,4); - x->capa = 4; -} - -/* called just after a doublequote in version 1 parsing */ -const char *binbuf_text_quoted(t_binbuf *x, const char *t, char *end) { - ostringstream buf; - while (t!=end) { - char c = *t++; - if (c=='"') break; - if (c!='\\') {buf << c; continue;} - c = *t++; - if (c=='a') {buf << '\a'; continue;} - if (c=='b') {buf << '\b'; continue;} - if (c=='f') {buf << '\f'; continue;} - if (c=='n') {buf << '\n'; continue;} - if (c=='r') {buf << '\r'; continue;} - if (c=='v') {buf << '\v'; continue;} - if (c=='t') {buf << '\t'; continue;} - if (c=='"') {buf << '\"'; continue;} - if (c=='\\'){buf << '\\'; continue;} - if (c=='\n'){continue;} - /* if (c=='u') ... */ - /* if (c=='x') ... */ - /* if (isdigit(c)) ... */ - buf << c; /* ignore syntax error (should it?) */ - } - binbuf_addv(x,"t",buf.str().data()); - return t; /* ignore syntax error (should it?) */ -} - -/* find the first atom in text, in any, and add it to this binbuf; - returns pointer to end of atom text */ -/* this one is for pd format version 1 */ -/* TODO: double-quotes, braces, test backslashes&dollars */ -const char *binbuf_text_matju(t_binbuf *x, const char *t, const char *end) { - int doll=0; - while (t!=end && isspace(*t)) t++; - if (t==end) return t; - if (*t==';') {binbuf_addv(x,";"); return t+1;} - if (*t==',') {binbuf_addv(x,","); return t+1;} - /* if (*t=='"') return binbuf_text_quoted(x,t,end); */ - if (*t=='+' || *t=='-' || *t=='.' || isdigit(*t)) { - char *token; - double v = strtod(t,&token); - if (t==end || isspace(*token)) {binbuf_addv(x,"f",v); return token;} - } - ostringstream buf; - for (; t!=end && *t!=',' && *t!=';' && !isspace(*t); ) { - doll |= t[0]=='$' && t+1!=end && isdigit(t[1]); - if (*t=='\\') t++; - if (t!=end) buf << *t++; - } - if (doll) { - const char *b = buf.str().data(); - if (b[0]!='$') doll=0; - for (b++; *b; b++) if (!isdigit(*b)) doll=0; - if (doll) binbuf_addv(x,"$",atoi(buf.str().data()+1)); - else binbuf_addv(x,"&",gensym(buf.str().data())); - } else binbuf_addv(x,"t",buf.str().data()); - return t; -} - -/* this one is for pd format version 0 */ -const char *binbuf_text_miller(t_binbuf *x, const char *t, const char *end) { - ostringstream buf; - /* it's an atom other than a comma or semi */ - int q = 0, slash = 0, lastslash = 0, dollar = 0; - /* skip leading space */ - while (t!=end && isspace(*t)) t++; - if (t==end) return t; - if (*t==';') {binbuf_addv(x,";"); return t+1;} - if (*t==',') {binbuf_addv(x,","); return t+1;} - do { - char c = *t++; - lastslash = slash; - slash = c=='\\'; - if (q >= 0) { - int digit = isdigit(c), dot=c=='.', minus=c=='-', plusminus=minus||c=='+', expon=c=='e'||c=='E'; - if (q==0) { /* beginning */ if (minus) q=1; else if (digit) q=2; else if (dot) q=3; else q=-1;} - else if (q==1) { /* got minus */ if (digit) q=2; else if (dot) q=3; else q=-1;} - else if (q==2) { /* got digits */ if (dot) q=4; else if (expon) q=6; else if (!digit) q=-1;} - else if (q==3) { /* got '.' without digits */ if (digit) q=5; else q=-1;} - else if (q==4) { /* got '.' after digits */ if (digit) q=5; else if (expon) q=6; else q=-1;} - else if (q==5) { /* got digits after . */ if (expon) q=6; else if (!digit) q=-1;} - else if (q==6) { /* got 'e' */ if (plusminus) q=7; else if (digit) q=8; else q=-1;} - else if (q==7) { /* got plus or minus */ if (digit) q=8; else q=-1;} - else if (q==8) { /* got digits */ if (!digit) q=-1;} - } - if (!lastslash && c == '$' && t!=end && isdigit(*t)) dollar = 1; -#if 1 - if (slash&&lastslash) slash=0; -#endif - if (!slash) buf << c; - } while (t!=end && (slash || !strchr(" \n\r\t,;",*t))); - if (q == 2 || q == 4 || q == 5 || q == 8) {binbuf_addv(x,"f",atof(buf.str().data())); return t;} - /* LATER try to figure out how to mix "$" and "\$" correctly; here, the backslashes were already - stripped so we assume all "$" chars are real dollars. In fact, we only know at least one was. */ - if (dollar) { - const char *b = buf.str().data(); - //printf("b=%s\n",b); - if (*b != '$') dollar = 0; - for (b++; *b; b++) if (!isdigit(*b)) dollar = 0; - if (dollar) binbuf_addv(x,"$",atoi(buf.str().data()+1)); - else binbuf_addv(x,"&",gensym(buf.str().data())); - } else binbuf_addv(x,"t",buf.str().data()); - return t; -} - -int sys_syntax = 0; - -void binbuf_text(t_binbuf *x, const char *t, size_t size) { - const char *end=t+size; - binbuf_clear(x); - while (t!=end) t = sys_syntax ? binbuf_text_matju(x,t,end) : binbuf_text_miller(x,t,end); - binbuf_capa(x,x->n); -} - -void pd_eval_text(const char *t, size_t size) { - t_binbuf *x = binbuf_new(); - const char *end = t+size; - while (t!=end) { - t = sys_syntax ? binbuf_text_matju(x,t,end) : binbuf_text_miller(x,t,end); - if (x->n && x->v[x->n-1].a_type == A_SEMI) { - binbuf_eval(x,0,0,0); - binbuf_clear(x); - } - } - binbuf_free(x); -} - -namespace desire { -void voprintf(ostream &buf, const char *s, va_list args) { - char *b; - vasprintf(&b,s,args); - buf << b; - free(b); -} -void oprintf(ostream &buf, const char *s, ...) { - va_list args; - va_start(args,s); - voprintf(buf,s,args); - va_end(args); -} -};//end namespace desire - -/* convert a binbuf to text; no null termination. */ -void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp) { - ostringstream buf; - t_atom *ap = x->v; - char nextdelim=0; - for (int i=x->n; i--; ap++) { - if (ap->a_type != A_SEMI && ap->a_type != A_COMMA && nextdelim) buf << (char)nextdelim; - atom_ostream(ap,buf); - nextdelim = ap->a_type == A_SEMI ? '\n' : ' '; - } - //if (nextdelim) buf << (char)nextdelim; - *bufp = strdup(buf.str().data()); - *lengthp = buf.str().size();// - (nextdelim == ' '); -} - -/* convert a binbuf to text with null termination, as return value */ -char *binbuf_gettext2(t_binbuf *x) { - char *buf; int n; - binbuf_gettext(x,&buf,&n); - buf[n] = 0; - return (char *)realloc(buf,n+1); -} - -/* Miller said: fix this so that writing to file doesn't buffer everything together. */ -/* matju said: make this use vector size doubling as it used to be in binbuf_text */ -void binbuf_add(t_binbuf *x, int argc, t_atom *argv) { - int newsize = x->n + argc; - t_atom *ap = (t_atom *)realloc(x->v,newsize*sizeof(*x->v)); - x->v = ap; - ap += x->n; - for (int i = argc; i--; ap++) *ap = *(argv++); - x->capa = x->n = newsize; -} - -#define MAXADDMESSV 100 -void binbuf_addv(t_binbuf *x, const char *fmt, ...) { - va_list ap; - t_atom arg[MAXADDMESSV], *at =arg; - int nargs = 0; - const char *fp = fmt; - va_start(ap, fmt); - while (1) { - if (nargs >= MAXADDMESSV) { - error("binbuf_addmessv: only %d allowed", MAXADDMESSV); - break; - } - switch(*fp++) { - case 'i': SETFLOAT( at, va_arg(ap, int)); break; - case 'f': SETFLOAT( at, va_arg(ap, double)); break; - case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break; - case 't': SETSYMBOL(at, gensym(va_arg(ap, char *))); break; - case ';': SETSEMI(at); break; - case ',': SETCOMMA(at); break; - case '$': SETDOLLAR(at, va_arg(ap, int)); break; - case '&': SETDOLLSYM(at, va_arg(ap, t_symbol *)); break; - default: goto done; - } - at++; - nargs++; - } -done: - va_end(ap); - binbuf_add(x, nargs, arg); -} - -/* add a binbuf to another one for saving. Semicolons and commas go to -symbols ";", "'",; the symbol ";" goes to "\;", etc. */ - -void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y) { - t_binbuf *z = binbuf_new(); - binbuf_add(z, y->n, y->v); - t_atom *ap = z->v; - for (size_t i=0; i < z->n; i++, ap++) { - switch (ap->a_type) { - case A_FLOAT: break; - case A_SEMI: SETSYMBOL(ap, gensym(";")); break; - case A_COMMA: SETSYMBOL(ap, gensym(",")); break; - case A_DOLLAR: SETSYMBOL(ap, symprintf("$%ld", ap->a_index)); break; - case A_DOLLSYM: { - ostringstream b; - atom_ostream(ap,b); - SETSYMBOL(ap, gensym(b.str().data()));} break; - case A_SYMBOL: - /* FIXME make this general */ - if (!strcmp(ap->a_symbol->name, ";")) SETSYMBOL(ap, gensym(";")); - else if (!strcmp(ap->a_symbol->name, ",")) SETSYMBOL(ap, gensym(",")); - break; - default: - //bug("binbuf_addbinbuf: stray atom of type %d",ap->a_type); - //abort(); - ; - } - } - binbuf_add(x, z->n, z->v); -} - -void binbuf_addsemi(t_binbuf *x) { - t_atom a; - SETSEMI(&a); - binbuf_add(x, 1, &a); -} - -/* Supply atoms to a binbuf from a message, making the opposite changes -from binbuf_addbinbuf. The symbol ";" goes to a semicolon, etc. */ - -void binbuf_restore(t_binbuf *x, int argc, t_atom *argv) { - int newsize = x->n + argc; - t_atom *ap = (t_atom *)realloc(x->v,(newsize+1)*sizeof(*x->v)); - if (!ap) {error("binbuf_addmessage: out of space"); return;} - x->v = ap; - ap = x->v + x->n; - for (int i = argc; i--; ap++) { - if (argv->a_type == A_SYMBOL) { - char *str = argv->a_symbol->name, *str2; - if (!strcmp(str, ";")) SETSEMI(ap); - else if (!strcmp(str, ",")) SETCOMMA(ap); - else if ((str2 = strchr(str, '$')) && isdigit(str2[1])) { - int dollsym = 0; - if (*str != '$') dollsym = 1; - else for (str2 = str + 1; *str2; str2++) if (!isdigit(*str2)) { - dollsym = 1; - break; - } - if (dollsym) SETDOLLSYM(ap, gensym(str)); - else { - int dollar = 0; - sscanf(argv->a_symbol->name + 1, "%d", &dollar); - SETDOLLAR(ap, dollar); - } - } else *ap = *argv; - argv++; - } else *ap = *(argv++); - } - x->n = newsize; -} - -#define MSTACKSIZE 2048 - -void binbuf_print(t_binbuf *x) { - int startedpost = 0, newline = 1; - for (size_t i=0; i < x->n; i++) { - if (newline) { - if (startedpost) endpost(); - startpost("%s",""); /* dummy string to fool __attribute__ */ - startedpost = 1; - } - postatom(1, x->v + i); - newline = !! x->v[i].a_type == A_SEMI; - } - if (startedpost) endpost(); -} - -int binbuf_getnatom(t_binbuf *x) {return x->n;} -t_atom *binbuf_getvec(t_binbuf *x) {return x->v;} - -int canvas_getdollarzero (); - -/* JMZ: - * s points to the first character after the $ - * (e.g. if the org.symbol is "$1-bla", then s will point to "1-bla") - * (e.g. org.symbol="hu-$1mu", s="1mu") - * LATER: think about more complex $args, like ${$1+3} - * - * the return value holds the length of the $arg (in most cases: 1) - * buf holds the expanded $arg - * - * if some error occurred, "-1" is returned - * - * e.g. "$1-bla" with list "10 20 30" - * s="1-bla" - * buf="10" - * return value = 1; (s+1=="-bla") - */ -static int binbuf_expanddollsym(char *s, std::ostream &buf, t_atom dollar0, int ac, t_atom *av, int tonew) { - int argno=atol(s); - int arglen=0; - char*cs=s; - char c=*cs; - while (c && isdigit(c)) { - c=*cs++; - arglen++; - } - /* invalid $-expansion (like "$bla") */ - if (cs==s) {buf << "$"; return 0;} - if (argno < 0 || argno > ac) { /* undefined argument */ - if(!tonew) return 0; - buf << "$" << argno; - } else if (argno == 0) { /* $0 */ - atom_ostream(&dollar0, buf); - } else { /* fine! */ - atom_ostream(av+(argno-1), buf); - } - return arglen-1; -} - -/* LATER remove the dependence on the current canvas for $0; should be another argument. */ -t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew) { - ostringstream buf2; - char *str=s->name; - t_atom dollarnull; - SETFLOAT(&dollarnull, canvas_getdollarzero()); - /* JMZ: currently, a symbol is detected to be A_DOLLSYM if it starts with '$' - * the leading $ is stripped and the rest stored in "s". i would suggest to NOT strip the leading $ - * and make everything a A_DOLLSYM that contains(!) a $ whenever this happened, enable this code */ - char *substr=strchr(str, '$'); - if(!substr) return s; - oprintf(buf2,"%.*s",substr-str,str); - str=substr+1; - for (;;) { - std::ostringstream buf; - int next = binbuf_expanddollsym(str, buf, dollarnull, ac, av, tonew); - if (next<0) break; - /* JMZ: i am not sure what this means, so i might have broken it. it seems like that if "tonew" is - set and the $arg cannot be expanded (or the dollarsym is in reality a A_DOLLAR). - 0 is returned from binbuf_realizedollsym; this happens when expanding in a message-box, - but does not happen when the A_DOLLSYM is the name of a subpatch */ - /* JMZ: this should mimick the original behaviour */ - if(!tonew && !next && buf.str().size()==0) return 0; - buf2 << buf.str(); - str+=next; - substr=strchr(str, '$'); - if(substr) { - oprintf(buf2,"%.*s",substr-str,str); - str=substr+1; - } else { - buf2 << str; - return gensym(buf2.str().data()); - } - } - return gensym(buf2.str().data()); -} - -void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv) { - static t_atom mstack[MSTACKSIZE], *msp = mstack, *ems = mstack+MSTACKSIZE; - t_atom *stackwas = msp; - t_atom *at = x->v; - int ac = x->n; - int nargs; - while (1) { - t_pd *nexttarget; - while (!target) { - t_symbol *s; - while (ac && (at->a_type == A_SEMI || at->a_type == A_COMMA)) {ac--; at++;} - if (!ac) break; - if (at->a_type == A_DOLLAR) { - if (at->a_index<=0 || at->a_index>argc) {error("$%ld: not enough arguments supplied",long(at->a_index)); goto cleanup;} - else if (argv[at->a_index-1].a_type!=A_SYMBOL) {error("$%ld: symbol needed as receiver",long(at->a_index)); goto cleanup;} - else s = argv[at->a_index-1].a_symbol; - } else if (at->a_type == A_DOLLSYM) { - s = binbuf_realizedollsym(at->a_symbol, argc, argv, 0); - if (!s) {error("$%s: not enough arguments supplied", at->a_symbol->name); goto cleanup;} - } else s = atom_getsymbol(at); - target = s->thing; - /* IMPD: allows messages to unbound objects, via pointers */ - if (!target) { - if (!sscanf(s->name,".x%lx",(long*)&target)) target=0; - if (target) { - if (!object_table->exists(target) || !object_table->get(target)) { - error("%s target is not a currently valid pointer",s->name); - return; - } - } - } - if (!target) {error("%s: no such object", s->name); goto cleanup;} - at++; - ac--; - break; - cleanup: - do {at++; ac--;} while (ac && at->a_type != A_SEMI); /* is this the correct thing to do? */ - continue; - } - if (!ac) break; - nargs = 0; - nexttarget = target; - while (1) { - if (!ac) goto gotmess; - if (msp >= ems) {error("message too long"); goto broken;} - switch (at->a_type) { - /* semis and commas in new message just get bashed to a symbol. This is needed so you can pass them to "expr." */ - case A_SEMI: if (target == &pd_objectmaker) {SETSYMBOL(msp, gensym(";")); break;} else {nexttarget = 0; goto gotmess;} - case A_COMMA: if (target == &pd_objectmaker) {SETSYMBOL(msp, gensym(",")); break;} else goto gotmess; - case A_FLOAT: - case A_SYMBOL: - *msp = *at; - break; - case A_DOLLAR: - if (at->a_index > 0 && at->a_index <= argc) *msp = argv[at->a_index-1]; - else if (at->a_index == 0) SETFLOAT(msp, canvas_getdollarzero()); - else { - SETFLOAT(msp, 0); - if (target != &pd_objectmaker) error("$%ld: argument number out of range",long(at->a_index)); - } - break; - case A_DOLLSYM: { - t_symbol *s9 = binbuf_realizedollsym(at->a_symbol, argc, argv, target == &pd_objectmaker); - if (!s9) { - error("%s: argument number out of range", at->a_symbol->name); - SETSYMBOL(msp, at->a_symbol); - } else SETSYMBOL(msp, s9); - break;} - default: - bug("bad item in binbuf"); - goto broken; - } - msp++; - ac--; - at++; - nargs++; - } - gotmess: - if (nargs) { - switch (stackwas->a_type) { - case A_SYMBOL: typedmess(target, stackwas->a_symbol, nargs-1, stackwas+1); break; - case A_FLOAT: if (nargs == 1) pd_float(target, stackwas->a_float); else pd_list(target, 0, nargs, stackwas); break; - default: {} - } - } - msp = stackwas; - if (!ac) break; - target = nexttarget; - at++; - ac--; - } - return; -broken: - msp = stackwas; -} - -static int binbuf_doopen(char *s, int mode) { - char namebuf[strlen(s)+1]; -#ifdef MSW - mode |= O_BINARY; -#endif - sys_bashfilename(s, namebuf); - return open(namebuf, mode); -} - -static FILE *binbuf_dofopen(const char *s, const char *mode) { - char namebuf[strlen(s)+1]; - sys_bashfilename(s, namebuf); - return fopen(namebuf, mode); -} - -int binbuf_read(t_binbuf *b, const char *filename, const char *dirname, int flags) { - long length; - char *buf; - char *namebuf=0; - if (*dirname) asprintf(&namebuf,"%s/%s",dirname,filename); - else asprintf(&namebuf, "%s", filename); - int fd = binbuf_doopen(namebuf, 0); - if (fd < 0) {error("open: %s: %s",namebuf,strerror(errno)); return 1;} - if ((length = lseek(fd, 0, SEEK_END)) < 0 || lseek(fd, 0, SEEK_SET) < 0 || !(buf = (char *)malloc(length))) { - error("lseek: %s: %s",namebuf,strerror(errno)); - close(fd); free(namebuf); - return 1; - } - int readret = read(fd, buf, length); - if (readret < length) { - error("read (%d %ld) -> %d; %s: %s", fd, length, readret, namebuf, strerror(errno)); - close(fd); free(namebuf); free(buf); - return 1; - } - if (flags&1) for (int i=0; in; - for (t_atom *ap = x->v; indx--; ap++) { - /* estimate how many characters will be needed. Printing out symbols may need extra characters for inserting backslashes. */ - int length = (ap->a_type == A_SYMBOL || ap->a_type == A_DOLLSYM) ? 80 + strlen(ap->a_symbol->name) : 40; - if (ep - bp < length) { - if (fwrite(sbuf, bp-sbuf, 1, f) < 1) {error("write: %s: %s",fbuf.str().data(),strerror(errno)); goto fail;} - bp = sbuf; - } - if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) && bp > sbuf && bp[-1] == ' ') bp--; - if (!crflag || ap->a_type != A_SEMI) { - atom_string(ap, bp, (ep-bp)-2); - length = strlen(bp); - bp += length; - ncolumn += length; - } - if (ap->a_type == A_SEMI || (!crflag && ncolumn > 65)) { - *bp++ = '\n'; - ncolumn = 0; - } else { - *bp++ = ' '; - ncolumn++; - } - } - if (fwrite(sbuf, bp-sbuf, 1, f) < 1) {error("write: %s: %s",fbuf.str().data(),strerror(errno)); goto fail;} - if (deleteit) binbuf_free(x); - fclose(f); - return 0; -fail: - if (deleteit) binbuf_free(x); - if (f) fclose(f); - return 1; -} - -/* The following routine attempts to convert from max to pd or back. The max to pd direction is working OK - but you will need to make lots of abstractions for objects like "gate" which don't exist in Pd. Conversion - from Pd to Max hasn't been tested for patches with subpatches yet! */ -#define MAXSTACK 1000 -#define ISSYMBOL(a, b) ((a)->a_type == A_SYMBOL && !strcmp((a)->a_symbol->name, (b))) -#define GETF(i) atom_getfloatarg(i,natom,nextmess) -static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd) { - t_binbuf *newb = binbuf_new(); - t_atom *vec = oldb->v; - t_int n = oldb->n, nextindex, stackdepth = 0, stack[MAXSTACK], nobj = 0; - t_atom outmess[MAXSTACK], *nextmess; - if (!maxtopd) binbuf_addv(newb,"tt;","max","v2"); - for (nextindex = 0; nextindex < n; ) { - int endmess, natom; - for (endmess = nextindex; endmess < n && vec[endmess].a_type != A_SEMI; endmess++) {} - if (endmess == n) break; - if (endmess == nextindex || endmess == nextindex + 1 - || vec[nextindex].a_type != A_SYMBOL || vec[nextindex+1].a_type != A_SYMBOL) { - nextindex = endmess + 1; - continue; - } - natom = endmess - nextindex; - if (natom > MAXSTACK-10) natom = MAXSTACK-10; - nextmess = vec + nextindex; - char *first = nextmess ->a_symbol->name; - char *second = (nextmess+1)->a_symbol->name; - if (maxtopd) { /* case 1: importing a ".pat" file into Pd. */ - /* dollar signs in file translate to symbols */ - for (int i=0; iname)); - } - } - if (!strcmp(first, "#N")) { - if (!strcmp(second, "vpatcher")) { - if (stackdepth >= MAXSTACK) {post("too many embedded patches"); return newb;} - stack[stackdepth] = nobj; - stackdepth++; - nobj = 0; - binbuf_addv(newb,"ttfffff;","#N","canvas", GETF(2), GETF(3), GETF(4)-GETF(2), GETF(5)-GETF(3), 10.); - } - } - if (!strcmp(first, "#P")) { - /* drop initial "hidden" flag */ - if (!strcmp(second, "hidden")) { - nextmess++; - natom--; - second = (nextmess+1)->a_symbol->name; - } - if (natom >= 7 && !strcmp(second, "newobj") - && (ISSYMBOL(&nextmess[6], "patcher") || ISSYMBOL(&nextmess[6], "p"))) { - binbuf_addv(newb,"ttffts;","#X","restore", GETF(2), GETF(3), - "pd", atom_getsymbolarg(7, natom, nextmess)); - if (stackdepth) stackdepth--; - nobj = stack[stackdepth]; - nobj++; - } else if (!strcmp(second, "newex") || !strcmp(second, "newobj")) { - t_symbol *classname = atom_getsymbolarg(6, natom, nextmess); - if (classname == gensym("trigger") || classname == gensym("t")) { - for (int i=7; i 5 ? "inlet~" : "inlet"); - nobj++; - } else if (!strcmp(second, "outlet")) { - binbuf_addv(newb,"ttfft;","#X","obj",GETF(2),GETF(3), natom > 5 ? "outlet~" : "outlet"); - nobj++; - } else if (!strcmp(second, "user")) { - binbuf_addv(newb,"ttffs;","#X","obj", GETF(3), GETF(4), atom_getsymbolarg(2, natom, nextmess)); - nobj++; - } else if (!strcmp(second, "connect") || !strcmp(second, "fasten")) { - binbuf_addv(newb,"ttffff;","#X","connect", nobj-GETF(2)-1, GETF(3), nobj-GETF(4)-1, GETF(5)); - } - } - } else { /* Pd to Max */ - if (!strcmp(first, "#N")) { - if (!strcmp(second, "canvas")) { - if (stackdepth >= MAXSTACK) { - post("too many embedded patches"); - return newb; - } - stack[stackdepth] = nobj; - stackdepth++; - nobj = 0; - binbuf_addv(newb,"ttffff;","#N","vpatcher", GETF(2), GETF(3), GETF(4), GETF(5)); - } - } - if (!strcmp(first, "#X")) { - if (natom >= 5 && !strcmp(second, "restore") && (ISSYMBOL (&nextmess[4], "pd"))) { - binbuf_addv(newb,"tt;","#P","pop"); - binbuf_addv(newb,"ttffffts;","#P","newobj", GETF(2), GETF(3), 50., 1., - "patcher", atom_getsymbolarg(5, natom, nextmess)); - if (stackdepth) stackdepth--; - nobj = stack[stackdepth]; - nobj++; - } else if (!strcmp(second, "obj")) { - t_symbol *classname = atom_getsymbolarg(4, natom, nextmess); - if (classname == gensym("inlet")) binbuf_addv(newb,"ttfff;","#P","inlet", GETF(2), GETF(3), 15.); - else if (classname == gensym("inlet~")) binbuf_addv(newb,"ttffff;","#P","inlet", GETF(2), GETF(3), 15., 1.); - else if (classname == gensym("outlet")) binbuf_addv(newb,"ttfff;","#P","outlet", GETF(2), GETF(3), 15.); - else if (classname == gensym("outlet~")) binbuf_addv(newb,"ttffff;","#P","outlet", GETF(2), GETF(3), 15., 1.); - else if (classname == gensym("bng")) binbuf_addv(newb,"ttffff;","#P","button", GETF(2), GETF(3), GETF(5), 0.); - else if (classname == gensym("tgl")) binbuf_addv(newb,"ttffff;","#P","toggle", GETF(2), GETF(3), GETF(5), 0.); - else if (classname == gensym("vsl")) binbuf_addv(newb,"ttffffff;","#P","slider", - GETF(2), GETF(3), GETF(5), GETF(6), (GETF(8)-GETF(7)) / (GETF(6)==1?1:GETF(6)-1), GETF(7)); - else { - binbuf_addv(newb,"ttffff","#P","newex", GETF(2), GETF(3), 50., 1.); - for (int i=4; in - searchbuf->n; indexin++) { - for (size_t nmatched = 0; nmatched < searchbuf->n; nmatched++) { - t_atom *a1 = &inbuf->v[indexin + nmatched], *a2 = &searchbuf->v[nmatched]; - if (a1->a_type != a2->a_type || - (a1->a_type == A_SYMBOL && a1->a_symbol != a2->a_symbol) || - (a1->a_type == A_FLOAT && a1->a_float != a2->a_float ) || - (a1->a_type == A_DOLLAR && a1->a_index != a2->a_index ) || - (a1->a_type == A_DOLLSYM && a1->a_symbol != a2->a_symbol)) goto nomatch; - } - return 1; - nomatch: ; - } - return 0; -} - -/* LATER figure out how to log errors */ -void binbuf_evalfile(t_symbol *name, t_symbol *dir) { - t_binbuf *b = binbuf_new(); - int import = !strcmp(name->name + strlen(name->name) - 4, ".pat"); - /* set filename so that new canvases can pick them up */ - int dspstate = canvas_suspend_dsp(); - glob_setfilename(0, name, dir); - if (import) { - if (binbuf_read(b, name->name, dir->name, 0)) {perror(name->name); goto bye;} - t_binbuf *newb = binbuf_convert(b, 1); - binbuf_free(b); - b = newb; - } else { - if (binbuf_read(b, name->name, dir->name, 2)) perror(name->name); - } -bye: - glob_setfilename(0, &s_, &s_); /* bug fix by Krzysztof Czaja */ - binbuf_free(b); - canvas_resume_dsp(dspstate); -} - -void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir) { - /* even though binbuf_evalfile appears to take care of dspstate, we have to do it again here, because - canvas_startdsp() assumes that all toplevel canvases are visible. LATER: check if this is still necessary (probably not) */ - int dspstate = canvas_suspend_dsp(); - binbuf_evalfile(name, dir); - t_pd *x = 0; - while ((x != s__X.thing) && (x = s__X.thing)) vmess(x, gensym("pop"), "i", 1); - if (lastpopped) pd_vmess(lastpopped, gensym("loadbang"), ""); - lastpopped = 0; - canvas_resume_dsp(dspstate); -} - -//copied from m_pd.h -#define class_new2(NAME,NU,FREE,SIZE,FLAGS,SIG) class_new2(NAME,(t_newmethod)NU,(t_method)FREE,SIZE,FLAGS,SIG) - -extern "C" { -void conf_init(); -void glob_init(); -void boxes_init(); -void garray_init(); -void pd_init() { - object_table = new t_hash(127); - bindlist_class = class_new(gensym("bindlist"), 0, 0, sizeof(t_bindlist), CLASS_PD, 0); - class_addbang(bindlist_class, (t_method)bindlist_bang); - class_addfloat(bindlist_class, (t_method)bindlist_float); - class_addsymbol(bindlist_class, (t_method)bindlist_symbol); - class_addpointer(bindlist_class, (t_method)bindlist_pointer); - class_addlist(bindlist_class, (t_method)bindlist_list); - class_addanything(bindlist_class, (t_method)bindlist_anything); - binbuf_class = class_new2("__list", binbuf_new, binbuf_free2, sizeof(t_binbuf), CLASS_PD, "*"); - wire_class = class_new2("__wire", wire_new, wire_free, sizeof(t_wire), CLASS_GOBJ, "*"); - class_setsavefn(wire_class,(t_savefn)wire_save); - if (pd_objectmaker._class) bug("ARGH"); - for (size_t i=0; in = strlen(symlist[i]->name); - dogensym(symlist[i]->name, symlist[i]->n, symlist[i]); /* why does this take three args? */ - } - pd_objectmaker._class = class_new2("objectmaker", 0, 0, sizeof(t_pd), CLASS_DEFAULT, ""); - pd_canvasmaker._class = class_new2("canvasmaker", 0, 0, sizeof(t_pd), CLASS_DEFAULT, ""); - pd_bind(&pd_canvasmaker, &s__N); - class_addanything(pd_objectmaker._class, (t_method)new_anything); - obj_init(); - conf_init(); - glob_init(); - boxes_init(); - garray_init(); -} -}; - -#ifndef HAVE_ASPRINTF -#define HAVE_ASPRINTF -#undef asprintf -#undef vasprintf -int asprintf(char **str, const char *fmt, ...) throw () { - va_list ap; - int ret; - *str = NULL; - va_start(ap, fmt); - ret = vasprintf(str, fmt, ap); - va_end(ap); - return ret; -} -#endif /* HAVE_ASPRINTF */ -#ifndef HAVE_VASPRINTF -#define HAVE_VASPRINTF -#include -#include -#include -#include -#include - -#ifndef VA_COPY -# ifdef HAVE_VA_COPY -# define VA_COPY(dest, src) va_copy(dest, src) -# else -# ifdef HAVE___VA_COPY -# define VA_COPY(dest, src) __va_copy(dest, src) -# else -# define VA_COPY(dest, src) (dest) = (src) -# endif -# endif -#endif - -#define INIT_SZ 128 - -int vasprintf(char **str, const char *fmt, va_list ap) throw () { - int ret = -1; - va_list ap2; - char *string, *newstr; - size_t len; - VA_COPY(ap2, ap); - if ((string = (char *)malloc(INIT_SZ)) == NULL) - goto fail; - ret = vsnprintf(string, INIT_SZ, fmt, ap2); - if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */ - *str = string; - } else if (ret == INT_MAX || ret < 0) { /* Bad length */ - goto fail; - } else { /* bigger than initial, realloc allowing for nul */ - len = (size_t)ret + 1; - if ((newstr = (char *)realloc(string, len)) == NULL) { - free(string); - goto fail; - } else { - va_end(ap2); - VA_COPY(ap2, ap); - ret = vsnprintf(newstr, len, fmt, ap2); - if (ret >= 0 && (size_t)ret < len) { - *str = newstr; - } else { /* failed with realloc'ed string, give up */ - free(newstr); - goto fail; - } - } - } - va_end(ap2); - return ret; -fail: - *str = NULL; - errno = ENOMEM; - va_end(ap2); - return -1; -} -#endif /* HAVE_VASPRINTF */ -- cgit v1.2.1