From d0f6986345970955d6390a6953c35babf587c262 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Thu, 19 Feb 2004 22:23:18 +0000 Subject: many small improvements in toxy, plustot added svn path=/trunk/externals/miXed/; revision=1321 --- toxy/Makefile | 4 + toxy/Makefile.objects | 20 + toxy/Makefile.sources | 3 +- toxy/build_counter | 2 +- toxy/plustot.c | 2020 ++++++++++++++++++++++++++++++++++++++++++++++ toxy/plustot.env.c | 150 ++++ toxy/plustot.h | 81 ++ toxy/plustot.in.c | 126 +++ toxy/plustot.out.c | 71 ++ toxy/plustot.print.c | 90 +++ toxy/plustot.qlist.c | 212 +++++ toxy/plustot.var.c | 130 +++ toxy/tot.c | 8 +- toxy/toxy-shared.include | 4 + toxy/widget.c | 225 ++++-- toxy/widgettype.c | 147 ++-- toxy/widgettype.h | 5 +- 17 files changed, 3151 insertions(+), 147 deletions(-) create mode 100644 toxy/plustot.c create mode 100644 toxy/plustot.env.c create mode 100644 toxy/plustot.h create mode 100644 toxy/plustot.in.c create mode 100644 toxy/plustot.out.c create mode 100644 toxy/plustot.print.c create mode 100644 toxy/plustot.qlist.c create mode 100644 toxy/plustot.var.c (limited to 'toxy') diff --git a/toxy/Makefile b/toxy/Makefile index fc022be..1718111 100644 --- a/toxy/Makefile +++ b/toxy/Makefile @@ -1,2 +1,6 @@ ROOT_DIR = .. +redefault: default.wiq default +default.wiq: $(ROOT_DIR)/test/toxy/default.wid + $(ROOT_DIR)/quoteinitializer $< \ + '"puts [concat loading built-in widget definitions]\n"' > $@ include $(ROOT_DIR)/Makefile.common diff --git a/toxy/Makefile.objects b/toxy/Makefile.objects index fde293c..f063097 100644 --- a/toxy/Makefile.objects +++ b/toxy/Makefile.objects @@ -7,6 +7,26 @@ hammer/gui.o \ common/props.o \ toxy/scriptlet.o +PLUSTOT_OBJECTS = \ +unstable/fragile.o \ +unstable/forky.o \ +common/loud.o \ +common/grow.o \ +hammer/file.o \ +common/props.o \ +toxy/scriptlet.o \ +toxy/plusbob.o + +PLUSTOT_PRIVATEOBJECTS = \ +plustot.env.o \ +plustot.in.o \ +plustot.var.o \ +plustot.out.o \ +plustot.qlist.o \ +plustot.print.o + +PLUSTOT_LIBS = $(TCL_LIB) + TOW_OBJECTS = \ common/loud.o \ unstable/loader.o diff --git a/toxy/Makefile.sources b/toxy/Makefile.sources index b0f3646..1626cd6 100644 --- a/toxy/Makefile.sources +++ b/toxy/Makefile.sources @@ -1,5 +1,6 @@ -TYPES = TOT TOW WIDGET +TYPES = TOT TOW WIDGET PLUSTOT TOT_SOURCES = tot.c TOW_SOURCES = tow.c WIDGET_SOURCES = widget.c +PLUSTOT_SOURCES = plustot.c diff --git a/toxy/build_counter b/toxy/build_counter index 5774bf7..a4b640c 100644 --- a/toxy/build_counter +++ b/toxy/build_counter @@ -1,3 +1,3 @@ #define TOXY_VERSION "0.1" #define TOXY_RELEASE "alpha" -#define TOXY_BUILD 1 +#define TOXY_BUILD 2 diff --git a/toxy/plustot.c b/toxy/plustot.c new file mode 100644 index 0000000..bfaeb32 --- /dev/null +++ b/toxy/plustot.c @@ -0,0 +1,2020 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include +#include "m_pd.h" +#include "g_canvas.h" +#include "common/loud.h" +#include "common/grow.h" +#include "hammer/file.h" +#include "common/props.h" +#include "toxy/scriptlet.h" +#include "toxy/plusbob.h" +#include "plustot.h" +#include "build_counter" + +#define PLUSTOT_VERBOSE +#define PLUSTOT_DEBUG +//#define PLUSTOT_DEBUGREFCOUNTS + +#ifdef PLUSTOT_DEBUG +# define PLUSDEBUG_ENDPOST(fn) endpost() +#else +# define PLUSDEBUG_ENDPOST(fn) +#endif + +#ifdef PLUSTOT_DEBUGREFCOUNTS +# define PLUSDEBUG_INCRREFCOUNT(ob, fn) \ + {post("++ %x "fn, (int)(ob)); Tcl_IncrRefCount(ob);} +# define PLUSDEBUG_DECRREFCOUNT(ob, fn) \ + {post("-- %x "fn, (int)(ob)); Tcl_DecrRefCount(ob);} +#else +# define PLUSDEBUG_INCRREFCOUNT(ob, fn) Tcl_IncrRefCount(ob) +# define PLUSDEBUG_DECRREFCOUNT(ob, fn) Tcl_DecrRefCount(ob) +#endif + +static t_symbol *plusps_tot; +static t_symbol *plusps_env; +static t_symbol *plusps_in; +static t_symbol *plusps_var; +static t_symbol *plusps_out; +static t_symbol *plusps_qlist; +static t_symbol *plusps_print; +static t_symbol *totps_query; + +static void plusloud_tcldirty(t_pd *caller, char *fnname) +{ + loud_warning((caller == PLUSBOB_OWNER ? 0 : caller), + "(%s) tcl plays dirty tricks, sorry", fnname); +} + +void plusloud_tclerror(t_pd *caller, Tcl_Interp *interp, char *msg) +{ + Tcl_Obj *ob = Tcl_GetObjResult(interp); + loud_error((caller == PLUSBOB_OWNER ? 0 : caller), msg); + if (ob) + { + int len; + char *res = Tcl_GetStringFromObj(ob, &len); + if (res && len > 0) + { + char buf[MAXPDSTRING]; + if (len > (MAXPDSTRING-2)) + { + len = (MAXPDSTRING-2); + buf[MAXPDSTRING-2] = '*'; + buf[MAXPDSTRING-1] = 0; + } + else buf[len] = 0; + strncpy(buf, res, len); + loud_errand((caller == PLUSBOB_OWNER ? 0 : caller), + "(tcl) %s", buf); + } + else ob = 0; + Tcl_ResetResult(interp); + } + if (!ob) loud_errand((caller == PLUSBOB_OWNER ? 0 : caller), + "unknown error (probably a bug)"); +} + +/* Plustin (aka +Ti) is a Tcl_Interp wrapped as a +bob. + This is a glist-based flavor of Plusenv. */ + +struct _plustin +{ + t_plusenv tin_env; + t_glist *tin_glist; + Tcl_Interp *tin_interp; +}; + +static t_plustype *plustin_basetype; +static t_plustype *plustin_type; +static t_plustin *plustin_default = 0; + +/* To be called from derived constructors or plustin's provider. */ +t_plustin *plustin_create(t_plustype *tp, t_plusbob *parent, t_symbol *id) +{ + t_plustin *tin = 0; + Tcl_Interp *interp = Tcl_CreateInterp(); + if (interp && (tin = (t_plustin *)plusenv_create(tp, parent, id))) + { +#ifdef PLUSTOT_DEBUG + post("plustin_create '%s' over %x", + (id ? id->s_name : "default"), (int)interp); +#endif + tin->tin_interp = interp; + Tcl_Preserve(interp); + if (Tcl_Init(interp) == TCL_ERROR) + plusloud_tclerror(0, interp, "interpreter initialization failed"); + Tcl_Release(interp); + } + else loud_error(0, "failed attempt to create an interpreter"); + return (tin); +} + +/* To be registered for calling from plusbob_release(). + Should never be called explicitly. */ +static void plustin_delete(t_plustin *tin) +{ +#ifdef PLUSTOT_DEBUG + t_symbol *id = plusenv_getid((t_plusenv *)tin); + post("plustin_delete '%s' over %x", + (id ? id->s_name : "default"), (int)tin->tin_interp); +#endif + Tcl_Preserve(tin->tin_interp); + if (!Tcl_InterpDeleted(tin->tin_interp)) + Tcl_DeleteInterp(tin->tin_interp); + Tcl_Release(tin->tin_interp); +} + +Tcl_Interp *plustin_getinterp(t_plustin *tin) +{ + return (tin->tin_interp); +} + +t_symbol *plustin_glistid(t_glist *gl) +{ + char buf[32]; + sprintf(buf, "+ti%x", (int)gl); + return (gensym(buf)); +} + +t_plustin *plustin_glistfind(t_glist *gl, int mode) +{ + t_plustin *tin = 0; + if (mode == PLUSTIN_GLIST_UP) + { + gl = gl->gl_owner; + mode = PLUSTIN_GLIST_ANY; + } + if (mode == PLUSTIN_GLIST_THIS) + return ((t_plustin *)plusenv_find(plustin_glistid(gl), + (t_plusenv *)plustin_default)); + else + { + while (gl) + { + char buf[32]; + sprintf(buf, "+ti%x", (int)gl); + if (tin = (t_plustin *)plusenv_find(gensym(buf), + (t_plusenv *)plustin_default)) + break; + gl = gl->gl_owner; + } + return (tin ? tin : plustin_default); + } +} + +/* To be called from client code, instead of plustin_create(). + Preserving is caller's responsibility. + Never returns null, even when called with create == 0: + if requested id not found, default returned, created if necessary. */ +t_plustin *plustin_glistprovide(t_glist *gl, int mode, int create) +{ + t_plustin *tin = 0; + t_plusbob *parent = plusenv_getparent(plustin_type); + if (mode == PLUSTIN_GLIST_UP) + { + gl = gl->gl_owner; + mode = PLUSTIN_GLIST_ANY; + } + tin = plustin_glistfind(gl, mode); + if (!tin && create) + { + if (tin = plustin_create(plustin_type, parent, plustin_glistid(gl))) + tin->tin_glist = gl; + } + if (!tin) + { + if (!plustin_default) + plustin_default = plustin_create(plustin_type, parent, 0); + tin = plustin_default; + } + return (tin); +} + +t_symbol *plustin_getglistname(t_plustin *tin) +{ + return (tin->tin_glist ? tin->tin_glist->gl_name : 0); +} + +/* Plustob (aka +To) is a Tcl_Obj wrapped as a +bob. */ + +/* LATER rethink the plustob/plusvar rules, measure performance. + There are two cases: + + `Bobbing' is taking an object from its wrapping bob, wrapping it into + another bob and, optionally, setting a variable to it. + + The main deal of bobbing design is not to Tcl_DuplicateObj while passing + bobs around. + + `Messing' is converting a Pd message (float, symbol or list) to an object, + wrapping it and, optionally, setting a variable to it. + + The obvious sequence of {Decr(old), New, Incr(new), SetVar(new)}, which + is currently used, involves picking a new object (New), while returning + an old one to the pool (by SetVar or Decr, depending on a third party + changing or not the tcl variable's value in the meantime). I guess + the overhead is negligible, unless we hit at the bottom of the pool. + Moreover, we can reduce the sequence to just {Set(old), SetVar(old)}, + in the case when old is not shared (referenced neither by a variable, + nor by a third party). The main advantage is being consistent with + the way Tcl itself was designed. + + An alternative: in the original messing design, the trick was to: + + . call Set on a prepicked object, instead of New + . call SetVar on a preserved object, as usual (var would not own its value) + . alternate between two prepicked objects in order to avoid calling UnsetVar + + So, the sequence was just {Set(v1), SetVar(v1)}, then {Set(v2), SetVar(v2)}, + again {Set(v1), SetVar(v1)}, and so on, unless a third party (other than + plusvar and a tcl variable) referenced our prepicked object. */ + +#define PLUSTOB_INIELBUFSIZE 128 /* LATER rethink */ + +struct _plustob +{ + t_plusbob tob_bob; + Tcl_Obj *tob_value; + t_plustin *tob_tin; /* redundant, LATER rethink */ + t_plusifsharedfn tob_ifsharedfn; + int tob_elbufsize; + Tcl_Obj **tob_elbuf; + Tcl_Obj *tob_elbufini[PLUSTOB_INIELBUFSIZE]; +}; + +static t_plustype *plustob_type; + +/* To be called from derived constructors. + Preserving is caller's responsibility. */ +t_plustob *plustob_create(t_plustype *tp, t_plustin *tin, Tcl_Obj *ob) +{ + t_plustob *tob = 0; + if (tin && (ob != PLUSTOB_MAKEIT || (ob = Tcl_NewObj())) + && (tob = (t_plustob *)plusbob_create(tp, (t_plusbob *)tin))) + { + if (ob) PLUSDEBUG_INCRREFCOUNT(ob, "plustob_create"); + plusbob_preserve((t_plusbob *)tin); + tob->tob_value = ob; + tob->tob_tin = tin; + tob->tob_ifsharedfn = 0; + tob->tob_elbufsize = PLUSTOB_INIELBUFSIZE; + tob->tob_elbuf = tob->tob_elbufini; + } + return (tob); +} + +/* To be registered for calling from plusbob_release(). + Should never be called explicitly. */ +static void plustob_delete(t_plustob *tob) +{ + if (tob->tob_tin) + plusbob_release((t_plusbob *)tob->tob_tin); + if (tob->tob_value) + PLUSDEBUG_DECRREFCOUNT(tob->tob_value, "plustob_delete"); + if (tob->tob_elbuf != tob->tob_elbufini) + freebytes(tob->tob_elbuf, tob->tob_elbufsize * sizeof(*tob->tob_elbuf)); +} + +/* To be registered for calling from plusbob_attach(). + Should never be called explicitly. */ +static void plustob_attach(t_plustob *tob) +{ + t_plustin *tin; + if (tin = (t_plustin *)plusbob_getparent((t_plusbob *)tob)) + { + if (tob->tob_tin) + plusbob_release((t_plusbob *)tob->tob_tin); + tob->tob_tin = tin; + plusbob_preserve((t_plusbob *)tin); + } + else bug("plustob_attach"); +} + +/* To be called from client code. + Preserving is caller's responsibility. */ +t_plustob *plustob_new(t_plustin *tin, Tcl_Obj *ob) +{ + return (plustob_create(plustob_type, tin, ob)); +} + +void plustob_setifshared(t_plustob *tob, t_plusifsharedfn ifsharedfn) +{ + tob->tob_ifsharedfn = ifsharedfn; +} + +int plustob_isshared(t_plustob *tob) +{ + return (tob->tob_value && Tcl_IsShared(tob->tob_value)); +} + +Tcl_Obj *plustob_getvalue(t_plustob *tob) +{ + return (tob->tob_value); +} + +/* silent, if caller is empty */ +t_plustin *plustag_tobtin(t_symbol *tag, t_pd *caller) +{ + return (plustag_validroot(tag, plusps_To, caller) + ? ((t_plustob *)tag)->tob_tin : 0); +} + +/* silent, if caller is empty */ +Tcl_Obj *plustag_tobvalue(t_symbol *tag, t_pd *caller) +{ + return (plustag_validroot(tag, plusps_To, caller) + ? ((t_plustob *)tag)->tob_value : 0); +} + +/* silent, if caller is empty */ +Tcl_Obj *plusatom_tobvalue(t_atom *ap, t_pd *caller) +{ + if (ap->a_type == A_SYMBOL) + return (plustag_tobvalue(ap->a_w.w_symbol, caller)); + else if (caller) + { + char buf[80]; + atom_string(ap, buf, 80); + loud_error((caller == PLUSBOB_OWNER ? 0 : caller), + "+tot does not understand '%s' (check object connections)", buf); + } + return (0); +} + +Tcl_Obj *plustob_set(t_plustob *tob, t_plustin *tin, Tcl_Obj *ob) +{ + if (tin != tob->tob_tin) + { + /* FIXME */ + loud_warning(0, "+To: environment mismatch"); + return (0); + } + if (ob != tob->tob_value) + { + if (tob->tob_value) + PLUSDEBUG_DECRREFCOUNT(tob->tob_value, "plustob_set"); + if (ob) + { + PLUSDEBUG_INCRREFCOUNT(ob, "plustob_set"); + if (Tcl_IsShared(ob)) + { + /* FIXME */ + } + } + tob->tob_value = ob; + } + return (ob); +} + +Tcl_Obj *plustob_setfloat(t_plustob *tob, t_float f) +{ + Tcl_Obj *ob = tob->tob_value; + if (!ob || Tcl_IsShared(ob)) + { + Tcl_Obj *tmp; + int i = (int)f; + if (ob && tob->tob_ifsharedfn) + { + if ((*tob->tob_ifsharedfn)((t_plusbob *)tob, ob) == 0) + return (0); + } + if (f == i) /* LATER rethink */ + tmp = Tcl_NewIntObj(i); + else + tmp = Tcl_NewDoubleObj((double)f); + if (tmp) + { + if (ob) PLUSDEBUG_DECRREFCOUNT(ob, "plustob_setfloat"); + tob->tob_value = ob = tmp; + PLUSDEBUG_INCRREFCOUNT(ob, "plustob_setfloat"); + } + else return (0); + } + else + { + int i = (int)f; + if (f == i) /* LATER rethink */ + Tcl_SetIntObj(ob, i); + else + Tcl_SetDoubleObj(ob, (double)f); + } + return (ob); +} + +Tcl_Obj *plustob_setsymbol(t_plustob *tob, t_symbol *s) +{ + if (plustag_isvalid(s, 0)) + { + if (plustag_validroot(s, plusps_To, PLUSBOB_OWNER)) + { + t_plustob *from = (t_plustob *)s; + return (plustob_set(tob, from->tob_tin, from->tob_value)); + } + else return (0); + } + else + { + Tcl_Obj *ob = tob->tob_value; + if (!ob || Tcl_IsShared(ob)) + { + Tcl_Obj *tmp; + if (ob && tob->tob_ifsharedfn) + { + if ((*tob->tob_ifsharedfn)((t_plusbob *)tob, ob) == 0) + return (0); + } + if (tmp = Tcl_NewStringObj(s->s_name, -1)) + { + if (ob) PLUSDEBUG_DECRREFCOUNT(ob, "plustob_setsymbol"); + tob->tob_value = ob = tmp; + PLUSDEBUG_INCRREFCOUNT(ob, "plustob_setsymbol"); + } + else return (0); + } + else Tcl_SetStringObj(ob, s->s_name, -1); + return (ob); + } +} + +Tcl_Obj *plustob_setlist(t_plustob *tob, int ac, t_atom *av) +{ + if (ac == 1) + { + if (av->a_type == A_FLOAT) + return (plustob_setfloat(tob, av->a_w.w_float)); + else if (av->a_type == A_SYMBOL) + return (plustob_setsymbol(tob, av->a_w.w_symbol)); + } + else if (ac > 1) + { + Tcl_Obj *ob = tob->tob_value; + int count; + t_atom *ap; + for (count = 0, ap = av; count < ac; count++, ap++) + if (ap->a_type != A_FLOAT && ap->a_type != A_SYMBOL) + break; + if (count > tob->tob_elbufsize) + { +#ifdef PLUSTOT_DEBUG + post("growing +To %d -> %d", tob->tob_elbufsize, count); +#endif + tob->tob_elbuf = + grow_nodata(&count, &tob->tob_elbufsize, tob->tob_elbuf, + PLUSTOB_INIELBUFSIZE, tob->tob_elbufini, + sizeof(*tob->tob_elbuf)); + } + if (count > 0) + { + int i; + Tcl_Obj **elp; + for (i = 0, elp = tob->tob_elbuf; i < count; i++, elp++, av++) + { + if (av->a_type == A_FLOAT) + *elp = Tcl_NewDoubleObj((double)av->a_w.w_float); + else if (av->a_type == A_SYMBOL) + *elp = Tcl_NewStringObj(av->a_w.w_symbol->s_name, -1); + } + if (!ob || Tcl_IsShared(ob)) + { + Tcl_Obj *tmp; + if (ob && tob->tob_ifsharedfn) + { + if ((*tob->tob_ifsharedfn)((t_plusbob *)tob, ob) == 0) + return (0); + } + if (tmp = Tcl_NewListObj(count, tob->tob_elbuf)) + { + if (ob) PLUSDEBUG_DECRREFCOUNT(ob, "plustob_setlist"); + tob->tob_value = ob = tmp; + PLUSDEBUG_INCRREFCOUNT(ob, "plustob_setlist"); + } + else return (0); + } + else Tcl_SetListObj(ob, count, tob->tob_elbuf); + return (ob); + } + } + return (0); /* count == 0, LATER rethink */ +} + +static int plustob_parseatoms(int ac, t_atom *av, int *natomsp, int *nlistsp, + Tcl_Obj **listobs, Tcl_Obj **atomobs) +{ + int i, natoms = 0, nlists = 0, start = 1; + t_atom *ap; + int atomcnt = 0; + Tcl_Obj **atomptr = atomobs; + for (i = 0, ap = av; i < ac; i++, ap++) + { + if (ap->a_type == A_SEMI || ap->a_type == A_COMMA) + { + /* empty lists are filtered out, LATER rethink */ + if (!start) + { + if (listobs) + { + if (listobs[nlists] = Tcl_NewListObj(atomcnt, atomptr)) + { + atomptr += atomcnt; + atomcnt = 0; + } + else goto parsefailed; + } + nlists++; + } + start = 1; + } + else + { + /* other types are ignored, LATER rethink */ + start = 0; + if (ap->a_type == A_FLOAT || ap->a_type == A_SYMBOL) + { + if (atomobs) + { + if (!(atomobs[natoms] = + (ap->a_type == A_FLOAT ? + Tcl_NewDoubleObj((double)ap->a_w.w_float) : + Tcl_NewStringObj(ap->a_w.w_symbol->s_name, -1)))) + goto parsefailed; + atomcnt++; + } + natoms++; + } + } + } + if (natoms && !start) + { + if (listobs && + !(listobs[nlists] = Tcl_NewListObj(atomcnt, atomptr))) + goto parsefailed; + nlists++; + } + if (natomsp) *natomsp = natoms; + if (nlistsp) *nlistsp = nlists; + return (1); +parsefailed: + /* FIXME cleanup */ + return (0); +} + +Tcl_Obj *plustob_setbinbuf(t_plustob *tob, t_binbuf *bb) +{ + int ac = binbuf_getnatom(bb); + if (ac) + { + t_atom *av = binbuf_getvec(bb); + Tcl_Obj *ob = tob->tob_value; + int count, natoms, nlists; + plustob_parseatoms(ac, av, &natoms, &nlists, 0, 0); + count = natoms + nlists; + if (count > tob->tob_elbufsize) + { + int n = count; +#ifdef PLUSTOT_DEBUG + post("growing +To %d -> %d", tob->tob_elbufsize, count); +#endif + tob->tob_elbuf = + grow_nodata(&n, &tob->tob_elbufsize, tob->tob_elbuf, + PLUSTOB_INIELBUFSIZE, tob->tob_elbufini, + sizeof(*tob->tob_elbuf)); + if (n < count) + goto setbbfailed; + } + if (!plustob_parseatoms(ac, av, 0, 0, + tob->tob_elbuf, tob->tob_elbuf + nlists)) + goto setbbfailed; + if (!ob || Tcl_IsShared(ob)) + { + Tcl_Obj *tmp; + if (ob && tob->tob_ifsharedfn) + { + if ((*tob->tob_ifsharedfn)((t_plusbob *)tob, ob) == 0) + goto setbbfailed; + } + if (tmp = Tcl_NewListObj(nlists, tob->tob_elbuf)) + { + if (ob) PLUSDEBUG_DECRREFCOUNT(ob, "plustob_setbinbuf"); + tob->tob_value = ob = tmp; + PLUSDEBUG_INCRREFCOUNT(ob, "plustob_setbinbuf"); + } + else goto setbbfailed; + } + else Tcl_SetListObj(ob, nlists, tob->tob_elbuf); + return (ob); + } +setbbfailed: + return (0); +} + +Tcl_Obj *plustob_grabresult(t_plustob *tob) +{ + Tcl_Interp *interp = tob->tob_tin->tin_interp; + Tcl_Obj *rob; + if (rob = Tcl_GetObjResult(interp)) + { + if (rob == tob->tob_value) + Tcl_ResetResult(interp); + else + { + PLUSDEBUG_INCRREFCOUNT(rob, "plustob_grabresult"); + Tcl_ResetResult(interp); + if (Tcl_IsShared(rob)) + { + /* FIXME */ + } + if (tob->tob_value) + PLUSDEBUG_DECRREFCOUNT(tob->tob_value, "plustob_grabresult"); + tob->tob_value = rob; + } + } + else plusloud_tcldirty(plusbob_getowner((t_plusbob *)tob), + "plustob_grabresult"); + return (rob); +} + +Tcl_Obj *plustob_evalob(t_plustob *tob, Tcl_Obj *ob) +{ + Tcl_Interp *interp = tob->tob_tin->tin_interp; + Tcl_Obj *rob; + Tcl_Preserve(interp); + if (Tcl_EvalObj(interp, ob) == TCL_OK) + rob = plustob_grabresult(tob); + else + { + plusloud_tclerror(plusbob_getowner((t_plusbob *)tob), interp, + "immediate command failed"); + rob = 0; + } + Tcl_Release(interp); + return (rob); +} + +/* Plusvar (aka +Tv) is a plustob with a one-way link to a tcl variable. + Whenever plusvar's value changes, the variable is set to it (the opposite + update requires explicitly calling the plusvar_pull() request). + This is different from one-way linking by passing TCL_LINK_READ_ONLY flag + to Tcl_LinkVar(): plusvar's variable is not forced to be read-only, + and its value's form and internal representation are not constrained. */ + +struct _plusvar +{ + t_plustob var_tob; + char *var_name; + char *var_index; + Tcl_Obj *var_part1; + Tcl_Obj *var_part2; +}; + +static t_plustype *plusvar_type; + +/* Since tcl always uses a hash table of string indices for array element + lookup, there are never any gains when using integer indices. */ + +/* To be called from derived constructors. + Preserving is caller's responsibility. */ +t_plusvar *plusvar_create(t_plustype *tp, t_plustin *tin, Tcl_Obj *ob, + char *name, char *index) +{ + t_plusvar *var = 0; + Tcl_Obj *ntob = 0; + Tcl_Obj *itob = 0; + if (name && *name) + { + if (ntob = Tcl_NewStringObj(name, -1)) + { + PLUSDEBUG_INCRREFCOUNT(ntob, "plusvar_create"); + } + else goto varfailed1; + } + else + { + bug("plusvar_create"); + goto varfailed2; + } + if (index) + { + if (itob = Tcl_NewStringObj(index, -1)) + { + PLUSDEBUG_INCRREFCOUNT(itob, "plusvar_create"); + } + else goto varfailed1; + } + if (var = (t_plusvar *)plustob_create(tp, tin, ob)) + { + var->var_name = getbytes(strlen(name) + 1); + strcpy(var->var_name, name); + if (index) + { + var->var_index = getbytes(strlen(index) + 1); + strcpy(var->var_index, index); + } + else var->var_index = 0; + var->var_part1 = ntob; + var->var_part2 = itob; + } + else goto varfailed2; + return (var); +varfailed1: + plusloud_tcldirty(0, "plusvar_create"); +varfailed2: + if (ntob) PLUSDEBUG_DECRREFCOUNT(ntob, "plusvar_create"); + if (itob) PLUSDEBUG_DECRREFCOUNT(itob, "plusvar_create"); + return (0); +} + +/* To be registered for calling from plusbob_release(). + Should never be called explicitly. */ +static void plusvar_delete(t_plusvar *var) +{ + freebytes(var->var_name, strlen(var->var_name) + 1); + if (var->var_index) + freebytes(var->var_index, strlen(var->var_index) + 1); + PLUSDEBUG_DECRREFCOUNT(var->var_part1, "plusvar_delete"); + if (var->var_part2) + PLUSDEBUG_DECRREFCOUNT(var->var_part2, "plusvar_delete"); +} + +/* To be called from client code. + Preserving is caller's responsibility */ +t_plusvar *plusvar_new(char *name, char *index, t_plustin *tin) +{ + return (plusvar_create(plusvar_type, tin, 0, name, index)); +} + +/* not used yet */ +static int plusvar_ifshared(t_plusbob *bob, Tcl_Obj *ob) +{ + /* Shared means either the variable still holds our value, or the value + is referenced by a third party, or both. In either case, we have to + pick a new object. + LATER consider testing for illegal use of a pseudo-variable. */ + return (1); +} + +/* LATER try making it more efficient */ +static Tcl_Obj *plusvar_postset(t_plusvar *var) +{ + Tcl_Obj *rob; + t_plustob *tob = (t_plustob *)var; + Tcl_Interp *interp = tob->tob_tin->tin_interp; + Tcl_Preserve(interp); + if (tob->tob_value) + { + rob = Tcl_ObjSetVar2(interp, var->var_part1, var->var_part2, + tob->tob_value, 0); + if (!rob) + { + if (Tcl_UnsetVar2(interp, var->var_name, 0, + TCL_LEAVE_ERR_MSG) == TCL_OK) + rob = Tcl_ObjSetVar2(interp, var->var_part1, var->var_part2, + tob->tob_value, TCL_LEAVE_ERR_MSG); + } + if (rob) + { +#ifdef PLUSTOT_DEBUGREFCOUNTS + if (var->var_index) + post("vv %x plusvar_postset [%s(%s)]", + (int)tob->tob_value, var->var_name, var->var_index); + else + post("vv %x plusvar_postset [%s]", + (int)tob->tob_value, var->var_name); +#endif + } + else plusloud_tclerror(0, interp, "cannot set variable"); + } + else + { + if (Tcl_UnsetVar2(interp, var->var_name, 0, + TCL_LEAVE_ERR_MSG) != TCL_OK) + plusloud_tclerror(0, interp, "cannot unset variable"); + rob = 0; + } + Tcl_Release(interp); + return (rob); +} + +Tcl_Obj *plusvar_push(t_plusvar *var) +{ + if (((t_plustob *)var)->tob_value) + return (plusvar_postset(var)); + else + return (0); +} + +Tcl_Obj *plusvar_pull(t_plusvar *var) +{ + Tcl_Obj *rob; + t_plustob *tob = (t_plustob *)var; + Tcl_Interp *interp = tob->tob_tin->tin_interp; + Tcl_Preserve(interp); + if (rob = Tcl_ObjGetVar2(interp, var->var_part1, var->var_part2, + TCL_LEAVE_ERR_MSG)) + plustob_set(tob, tob->tob_tin, rob); + else + plusloud_tclerror(0, interp, "cannot read variable"); + Tcl_Release(interp); + return (rob); +} + +Tcl_Obj *plusvar_set(t_plusvar *var, Tcl_Obj *ob, int doit) +{ + t_plustob *tob = (t_plustob *)var; + if (plustob_set(tob, tob->tob_tin, ob)) + return (doit ? plusvar_postset(var) : tob->tob_value); + else + return (0); +} + +Tcl_Obj *plusvar_setfloat(t_plusvar *var, t_float f, int doit) +{ + t_plustob *tob = (t_plustob *)var; + if (plustob_setfloat(tob, f)) + return (doit ? plusvar_postset(var) : tob->tob_value); + else + return (0); +} + +Tcl_Obj *plusvar_setsymbol(t_plusvar *var, t_symbol *s, int doit) +{ + t_plustob *tob = (t_plustob *)var; + if (plustob_setsymbol(tob, s)) + return (doit ? plusvar_postset(var) : tob->tob_value); + else + return (0); +} + +Tcl_Obj *plusvar_setlist(t_plusvar *var, int ac, t_atom *av, int doit) +{ + t_plustob *tob = (t_plustob *)var; + if (plustob_setlist(tob, ac, av)) + return (doit ? plusvar_postset(var) : tob->tob_value); + else + return (0); +} + +/* LATER derive +string from +bob */ + +typedef struct _plusstring +{ + int ps_len; + char *ps_buf; + int ps_refcount; +} t_plusstring; + +/* Resolving dot-separators, unless script is empty. */ +t_plusstring *plusstring_fromatoms(int ac, t_atom *av, t_scriptlet *script) +{ + t_plusstring *ps = 0; + char *buf; + int length; + if (script) + { + char *start; + scriptlet_reset(script); + scriptlet_add(script, 1, 1, ac, av); + start = scriptlet_getcontents(script, &length); + buf = copybytes(start, length); + } + else + { + char *newbuf; + buf = getbytes(0); + length = 0; + while (ac--) + { + char string[MAXPDSTRING]; + int newlength; + if ((av->a_type == A_SEMI || av->a_type == A_COMMA) && + length && buf[length-1] == ' ') length--; + atom_string(av, string, MAXPDSTRING); + newlength = length + strlen(string) + 1; + if (!(newbuf = resizebytes(buf, length, newlength))) break; + buf = newbuf; + strcpy(buf + length, string); + length = newlength; + if (av->a_type == A_SEMI) buf[length-1] = '\n'; + else buf[length-1] = ' '; + av++; + } + if (length && buf[length-1] == ' ') + { + if (newbuf = resizebytes(buf, length, length-1)) + { + buf = newbuf; + length--; + } + } + } + ps = getbytes(sizeof(*ps)); + ps->ps_len = length; + ps->ps_buf = buf; + ps->ps_refcount = 0; + return (ps); +} + +void plusstring_preserve(t_plusstring *ps) +{ + ps->ps_refcount++; +} + +void plusstring_release(t_plusstring *ps) +{ + if (--ps->ps_refcount <= 0) + { + if (ps->ps_refcount == 0) + { + if (ps->ps_buf) freebytes(ps->ps_buf, ps->ps_len); + freebytes(ps, sizeof(*ps)); + } + else bug("plusstring_release"); + } +} + +typedef struct _plusword +{ + int pw_type; + Tcl_Obj *pw_ob; + Tcl_Token *pw_ndxv; /* index part of this word (if array variable) */ + int pw_ndxc; /* numComponents of the above */ +} t_plusword; + +#define PLUSTOT_MAXINLETS 256 /* LATER rethink */ +#define PLUSTOT_INIMAXWORDS 16 + +/* LATER elaborate */ +#define PLUSTOT_ERRUNKNOWN -1 +#define PLUSTOT_ERROTHER -2 + +typedef struct _plusproxy +{ + t_pd pp_pd; + t_pd *pp_master; + t_plusvar *pp_var; + int pp_ndx; + int pp_doit; + int pp_warned; +} t_plusproxy; + +typedef struct _plustot +{ + t_object x_ob; + t_glist *x_glist; + t_plustob *x_tob; /* interpreter's result (after invocation) */ + t_scriptlet *x_script; + Tcl_Obj *x_cname; /* command name, main validation flag */ + Tcl_CmdInfo x_cinfo; + t_plusstring *x_ctail; /* command arguments, parse validation flag */ + Tcl_Parse x_tailparse; + int x_maxwords; /* as allocated */ + int x_nwords; /* as used, including command name */ + t_plusword *x_words; /* arguments, not evaluated */ + t_plusword x_wordsini[PLUSTOT_INIMAXWORDS]; + int x_maxargs; /* == maxwords, except during growing */ + int x_argc; /* 0 or nwords, except during evaluation */ + Tcl_Obj **x_argv; /* command name and evaluated arguments */ + Tcl_Obj *x_argvini[PLUSTOT_INIMAXWORDS]; + int x_pseudoscalar; + int x_nproxies; + t_plusproxy **x_proxies; + t_plusproxy *x_mainproxy; /* == x_proxies[0], unless pseudo-scalar */ + int x_grabwarned; +} t_plustot; + +static t_class *plusproxy_class; +static t_class *plustot_class; + +/* Create a variable here only for the main slot. Other slots are to be + filled during the second parsing pass, in order to fill only the slots + that are actually referenced. If ndx is negative, then create + a pseudo-scalar, otherwise this is a pseudo-array element. */ +static t_plusproxy *plusproxy_new(t_pd *master, int ndx, t_plustin *tin) +{ + t_plusproxy *pp = (t_plusproxy *)pd_new(plusproxy_class); + pp->pp_master = master; + pp->pp_var = (ndx > 0 ? 0 : plusvar_new("in", (ndx ? 0 : "0"), tin)); + if (pp->pp_var) + { + plusbob_preserve((t_plusbob *)pp->pp_var); + plusbob_setowner((t_plusbob *)pp->pp_var, master); + } + pp->pp_ndx = ndx; + pp->pp_doit = (ndx < 1); + pp->pp_warned = 0; + return (pp); +} + +static void plusproxy_free(t_plusproxy *pp) +{ +#ifdef PLUSTOT_DEBUG + post("plusproxy_free (%s %d)", + (pp->pp_var ? pp->pp_var->var_name : "empty"), pp->pp_ndx); +#endif + if (pp->pp_var) + plusbob_release((t_plusbob *)pp->pp_var); +} + +static void plusproxy_emptyhit(t_plusproxy *pp) +{ + if (!pp->pp_warned) + { + loud_error(pp->pp_master, "empty slot hit"); + pp->pp_warned = 1; + } +} + +static void plusproxy_bang(t_plusproxy *pp) +{ + if (pp->pp_var) + plusvar_push(pp->pp_var); + else + plusproxy_emptyhit(pp); +} + +static void plusproxy_float(t_plusproxy *pp, t_float f) +{ + if (pp->pp_var) + plusvar_setfloat(pp->pp_var, f, pp->pp_doit); + else + plusproxy_emptyhit(pp); +} + +static void plusproxy_symbol(t_plusproxy *pp, t_symbol *s) +{ + if (pp->pp_var) + plusvar_setsymbol(pp->pp_var, s, pp->pp_doit); + else + plusproxy_emptyhit(pp); +} + +static void plusproxy_list(t_plusproxy *pp, t_symbol *s, int ac, t_atom *av) +{ + if (pp->pp_var) + plusvar_setlist(pp->pp_var, ac, av, pp->pp_doit); + else + plusproxy_emptyhit(pp); +} + +#ifdef PLUSTOT_DEBUG +static void plusproxy_debug(t_plusproxy *pp) +{ + t_plustin *tin = ((t_plustob *)pp->pp_var)->tob_tin; + t_symbol *id = plusenv_getid((t_plusenv *)tin); + t_symbol *glname = plustin_getglistname(tin); + post("+proxy %d, glist %x", + pp->pp_ndx, (int)((t_plustot *)pp->pp_master)->x_glist); + post(" plustin '%s' (%s) over %x", (id ? id->s_name : "default"), + (glname ? glname->s_name : ""), (int)tin->tin_interp); +} +#endif + +/* First pass (!doit): determine number of slots. + Second pass (doit): create variables for non-empty slots. */ +static int plustot_usevariable(t_plustot *x, Tcl_Token *tp, int doit) +{ + int nc = tp->numComponents; + char *errmess = 0; + int errcode = PLUSTOT_ERRUNKNOWN; +#ifdef PLUSTOT_DEBUG + if (!doit) + { + char buf[MAXPDSTRING]; + int size = tp->size; + if (size > (MAXPDSTRING-2)) + { + size = (MAXPDSTRING-2); + buf[MAXPDSTRING-2] = '*'; + buf[MAXPDSTRING-1] = 0; + } + else buf[size] = 0; + strncpy(buf, tp->start, size); + startpost("%s ", buf); + } +#endif + tp++; + if (nc && tp->type == TCL_TOKEN_TEXT) + { + if (strncmp(tp->start, "in", tp->size)) + { + /* regular variable */ + /* LATER consider tracing it (2nd pass) */ + } + else + { + /* pseudo-variable */ + int inno = -1; + tp++; + if (nc == 1) + { + if (x->x_nproxies && !x->x_pseudoscalar) + { + errmess = "mixed scalar and array forms of pseudo-variable"; + errcode = PLUSTOT_ERROTHER; + goto badvariable; + } + inno = 0; + x->x_pseudoscalar = 1; + } + else if (nc == 2 && tp->type == TCL_TOKEN_TEXT) + { + int i; + char *p; + if (x->x_pseudoscalar) + { + errmess = "mixed scalar and array forms of pseudo-variable"; + errcode = PLUSTOT_ERROTHER; + goto badvariable; + } + inno = 0; + for (i = 0, p = (char *)tp->start; i < tp->size; i++, p++) + { + if (*p < '0' || *p > '9') + { + errmess = "invalid inlet number in pseudo-variable"; + errcode = PLUSTOT_ERROTHER; + goto badvariable; + } + inno = inno * 10 + (int)(*p - '0'); + } + if (inno > PLUSTOT_MAXINLETS) + { + errmess = "inlet number too large in pseudo-variable"; + errcode = PLUSTOT_ERROTHER; + goto badvariable; + } + } + else + { + errmess = "invalid index format in pseudo-variable"; + errcode = PLUSTOT_ERROTHER; + goto badvariable; + } + if (inno >= 0) + { + if (!doit) + { +#ifdef PLUSTOT_DEBUG + startpost("(inlet %d) ", inno); +#endif + if (inno >= x->x_nproxies) + x->x_nproxies = inno + 1; + } + else if (inno < x->x_nproxies) + { + if (inno > 0 && !x->x_proxies[inno]->pp_var) + { + t_plusvar *var; + char buf[8]; + sprintf(buf, "%d", inno); + var = plusvar_new("in", buf, x->x_tob->tob_tin); + plusbob_preserve((t_plusbob *)var); + plusbob_setowner((t_plusbob *)var, (t_pd *)x); + x->x_proxies[inno]->pp_var = var; + } + } + else + { + PLUSDEBUG_ENDPOST("plustot_usevariable"); + bug("plustot_usevariable"); + goto badvariable; + } + } + else + { + errmess = "invalid pseudo-variable"; + errcode = PLUSTOT_ERROTHER; + goto badvariable; + } + } + return (1); + } + else plusloud_tcldirty((t_pd *)x, "plustot_usevariable"); +badvariable: + if (errmess) + { + PLUSDEBUG_ENDPOST("plustot_usevariable"); + loud_error((t_pd *)x, errmess); + } + return (errcode); +} + +static int plustot_doparsevariables(t_plustot *x, Tcl_Interp *interp, + const char *buf, int len, + Tcl_Parse *parsep, int doit) +{ + int nvars = 0; + int errcode = PLUSTOT_ERRUNKNOWN; + if (Tcl_ParseCommand(interp, buf, len, 0, parsep) == TCL_OK) + { + int ntok = parsep->numTokens; + Tcl_Token *tp = parsep->tokenPtr; + while (ntok--) + { + if (tp->type == TCL_TOKEN_VARIABLE) + { + int res = plustot_usevariable(x, tp, doit); + if (res > 0) + nvars++; + else + { + errcode = res; + goto parsefailed; + } + } + else if (tp->type == TCL_TOKEN_COMMAND) + { + if (tp->size > 2) + { + Tcl_Parse parse; + int res = + plustot_doparsevariables(x, interp, tp->start + 1, + tp->size - 2, &parse, doit); + if (res != PLUSTOT_ERRUNKNOWN) + Tcl_FreeParse(&parse); + if (res >= 0) + nvars += res; + else + { + errcode = res; + goto parsefailed; + } + } + } + else if (tp->type == TCL_TOKEN_SIMPLE_WORD + && tp->size > 2 && *tp->start == '{') + { + tp++; +#if 0 && defined(PLUSTOT_DEBUG) + if (doit && tp->size > 0) + { + char buf[MAXPDSTRING+1]; + int sz = (tp->size < MAXPDSTRING ? tp->size : MAXPDSTRING); + strncpy(buf, tp->start, sz); + buf[sz] = 0; + post("simple word's text: %s", buf); + } +#endif + if (ntok-- && tp->type == TCL_TOKEN_TEXT && tp->size > 0) + { + Tcl_Parse parse; + int res = + plustot_doparsevariables(x, interp, tp->start, + tp->size, &parse, doit); + if (res != PLUSTOT_ERRUNKNOWN) + Tcl_FreeParse(&parse); + if (res >= 0) + nvars += res; + else + { + errcode = res; + goto parsefailed; + } + } + else + { + plusloud_tcldirty((t_pd *)x, "plustot_doparsevariables"); + goto parsefailed; + } + } +#if 0 && defined(PLUSTOT_DEBUG) + else if (doit && tp->size > 0) + { + char buf[MAXPDSTRING+1]; + int sz = (tp->size < MAXPDSTRING ? tp->size : MAXPDSTRING); + strncpy(buf, tp->start, sz); + buf[sz] = 0; + post("other type (%d): %s", tp->type, buf); + } +#endif + tp++; + } + } + else goto parsefailed; + return (nvars); +parsefailed: + return (errcode); +} + +static int plustot_parsevariables(t_plustot *x, Tcl_Interp *interp, + const char *buf, int len, + Tcl_Parse *parsep, int doit) +{ + int nvars; +#ifdef PLUSTOT_DEBUG + if (!doit) startpost("variables: "); +#endif + nvars = plustot_doparsevariables(x, interp, buf, len, parsep, doit); +#ifdef PLUSTOT_DEBUG + if (!doit) + { + if (nvars > 0) + { + post("\n%d variable substitutions", nvars); + post("%d inlets requested", x->x_nproxies); + } + else if (nvars == 0) post("none"); + } +#endif + return (nvars); +} + +static int plustot_makeproxies(t_plustot *x) +{ + Tcl_Interp *interp = x->x_tob->tob_tin->tin_interp; + if (interp) + { + if (x->x_nproxies == 1) + { + x->x_mainproxy = + plusproxy_new((t_pd *)x, (x->x_pseudoscalar ? -1 : 0), + x->x_tob->tob_tin); + } + else if (x->x_nproxies > 1 && !x->x_pseudoscalar) + { + if (x->x_proxies = getbytes(x->x_nproxies * sizeof(*x->x_proxies))) + { + int i; + for (i = 0; i < x->x_nproxies; i++) + x->x_proxies[i] = + plusproxy_new((t_pd *)x, i, x->x_tob->tob_tin); + for (i = 1; i < x->x_nproxies; i++) + inlet_new((t_object *)x, (t_pd *)x->x_proxies[i], 0, 0); + x->x_mainproxy = x->x_proxies[0]; + /* second pass: traverse non-empty slots, create variables */ + plustot_parsevariables(x, interp, + x->x_ctail->ps_buf, x->x_ctail->ps_len, + &x->x_tailparse, 1); + } + else goto proxiesfailed; + } + else + { + bug("plustot_makeproxies"); + goto proxiesfailed; + } + return (1); + } +proxiesfailed: + return (0); +} + +static void plustot_initwords(t_plustot *x) +{ + if (x->x_words != x->x_wordsini) + freebytes(x->x_words, x->x_maxwords * sizeof(*x->x_words)); + x->x_maxwords = PLUSTOT_INIMAXWORDS; + x->x_nwords = 0; + x->x_words = x->x_wordsini; +} + +static void plustot_initargs(t_plustot *x) +{ + if (x->x_argv != x->x_argvini) + freebytes(x->x_argv, x->x_maxargs * sizeof(*x->x_argv)); + x->x_maxargs = PLUSTOT_INIMAXWORDS; + x->x_argc = 0; + x->x_argv = x->x_argvini; + x->x_argv[0] = x->x_cname; +} + +static int plustot_resetwords(t_plustot *x) +{ + int i; + for (i = 1; i < x->x_nwords; i++) + PLUSDEBUG_DECRREFCOUNT(x->x_words[i].pw_ob, "plustot_resetwords"); + x->x_nwords = 0; + if (x->x_ctail) + { + int nwords = x->x_tailparse.numWords + 1; + if (nwords > x->x_maxwords) + { + int n = nwords; +#ifdef PLUSTOT_DEBUG + post("growing words %d -> %d", x->x_maxwords, nwords); +#endif + x->x_words = grow_nodata(&n, &x->x_maxwords, x->x_words, + PLUSTOT_INIMAXWORDS, x->x_wordsini, + sizeof(*x->x_words)); + if (n != nwords) + return (0); + } + return (1); + } + else return (0); +} + +static int plustot_resetargs(t_plustot *x) +{ + int i; + for (i = 1; i < x->x_argc; i++) + PLUSDEBUG_DECRREFCOUNT(x->x_argv[i], "plustot_resetargs"); + x->x_argc = 0; + x->x_argv[0] = x->x_cname; + if (x->x_ctail) + { + int nargs = x->x_maxwords; + if (nargs > x->x_maxargs) + { + int n = nargs; +#ifdef PLUSTOT_DEBUG + post("growing argv %d -> %d", x->x_maxargs, nargs); +#endif + x->x_argv = grow_nodata(&n, &x->x_maxargs, x->x_argv, + PLUSTOT_INIMAXWORDS, x->x_argvini, + sizeof(*x->x_argv)); + x->x_argv[0] = x->x_cname; + if (n != nargs) + { + plustot_initwords(x); + plustot_initargs(x); + return (0); + } + } + else if (nargs < x->x_maxargs) + { + bug("plustot_resetargs"); /* LATER rethink */ + plustot_initwords(x); + plustot_initargs(x); + return (0); + } + return (1); + } + else return (0); +} + +static int plustot_makewords(t_plustot *x) +{ + if (plustot_resetwords(x)) + { + int i, ncomponents = 0, nwords = x->x_tailparse.numWords + 1; + Tcl_Token *tp; + int len; + char buf[TCL_UTF_MAX]; +#ifdef PLUSTOT_DEBUG + post("arguments:"); +#endif + for (i = 1, tp = x->x_tailparse.tokenPtr; + i < nwords; i++, tp += ncomponents) + { +#ifdef PLUSTOT_DEBUG + post(" %s token: type %d[%d], having %d[%d] component%s", + loud_ordinal(i), tp->type, tp[1].type, + tp->numComponents, tp[1].numComponents, + (tp->numComponents > 1 ? "s" : "")); +#endif + ncomponents = tp->numComponents; + tp++; + switch (x->x_words[i].pw_type = tp->type) + { + case TCL_TOKEN_TEXT: + x->x_words[i].pw_ob = Tcl_NewStringObj(tp->start, tp->size); + break; + + case TCL_TOKEN_BS: + len = Tcl_UtfBackslash(tp->start, 0, buf); + x->x_words[i].pw_ob = Tcl_NewStringObj(buf, len); + break; + + case TCL_TOKEN_COMMAND: + x->x_words[i].pw_ob = Tcl_NewStringObj(tp->start + 1, + tp->size - 2); + break; + + case TCL_TOKEN_VARIABLE: + if (tp->numComponents > 1) + { + x->x_words[i].pw_ndxv = tp + 2; + x->x_words[i].pw_ndxc = tp->numComponents - 1; + } + else x->x_words[i].pw_ndxv = 0; + x->x_words[i].pw_ob = Tcl_NewStringObj(tp[1].start, tp[1].size); + break; + + default: + plusloud_tcldirty((t_pd *)x, + "plustot_makewords (unexpected token type)"); + goto wordsfailed; + } + PLUSDEBUG_INCRREFCOUNT(x->x_words[i].pw_ob, "plustot_makewords"); + } + x->x_nwords = nwords; + return (1); +wordsfailed: + x->x_nwords = i; + plustot_resetwords(x); + } + return (0); +} + +static int plustot_argsfromwords(t_plustot *x, Tcl_Interp *interp) +{ + if (plustot_resetargs(x)) + { + t_plusword *pw; + int i; + for (i = 1, pw = &x->x_words[1]; i < x->x_nwords; i++, pw++) + { + int result; + if (pw->pw_type == TCL_TOKEN_COMMAND) + { + result = Tcl_EvalObjEx(interp, pw->pw_ob, 0); + if (result == TCL_OK) + { + if (x->x_argv[i] = Tcl_GetObjResult(interp)) + { + PLUSDEBUG_INCRREFCOUNT(x->x_argv[i], + "plustot_argsfromwords"); + Tcl_ResetResult(interp); + } + else + { + plusloud_tcldirty((t_pd *)x, "plustot_argsfromwords"); + goto evalfailed; + } + } + else + { + plusloud_tclerror((t_pd *)x, interp, "bad word (command)"); + goto evalfailed; + } + } + else if (pw->pw_type == TCL_TOKEN_VARIABLE) + { + Tcl_Obj *indexp; + if (x->x_words[i].pw_ndxv) + { + /* FIXME */ + int res = Tcl_EvalTokensStandard(interp, + x->x_words[i].pw_ndxv, + x->x_words[i].pw_ndxc); + if (res == TCL_OK) + { + indexp = Tcl_GetObjResult(interp); + PLUSDEBUG_INCRREFCOUNT(indexp, + "plustot_argsfromwords"); + Tcl_ResetResult(interp); + } + else + { + plusloud_tclerror((t_pd *)x, interp, "bad index"); + goto evalfailed; + } + } + else indexp = 0; + if (x->x_argv[i] = Tcl_ObjGetVar2(interp, pw->pw_ob, indexp, + TCL_LEAVE_ERR_MSG)) + { + PLUSDEBUG_INCRREFCOUNT(x->x_argv[i], + "plustot_argsfromwords"); + Tcl_ResetResult(interp); + } + else + { + plusloud_tclerror((t_pd *)x, interp, "bad word (variable)"); + goto evalfailed; + } + } + else + { + x->x_argv[i] = pw->pw_ob; + /* refcount is 1 already (makewords), but we need to comply to + a general rule: args are decremented after use (resetargs) */ + PLUSDEBUG_INCRREFCOUNT(x->x_argv[i], "plustot_argsfromwords"); + } + } + x->x_argc = x->x_nwords; + return (1); +evalfailed: + x->x_argc = i; + plustot_resetargs(x); + } + return (0); /* LATER find a proper way for passing a result */ +} + +static int plustot_argsfromtokens(t_plustot *x, Tcl_Interp *interp) +{ + if (plustot_resetargs(x)) + { + int i, nwords = x->x_tailparse.numWords + 1; + Tcl_Token *tp; +#ifdef PLUSTOT_DEBUG + post("arguments:"); +#endif + for (i = 1, tp = x->x_tailparse.tokenPtr; + i < nwords; i++, tp += (tp->numComponents + 1)) + { + int result; +#ifdef PLUSTOT_DEBUG + startpost(" %s token: type %d[%d], having %d component%s", + loud_ordinal(i), tp->type, tp[1].type, + tp->numComponents, (tp->numComponents > 1 ? "s" : "")); +#endif + result = Tcl_EvalTokensStandard(interp, tp + 1, tp->numComponents); + if (result == TCL_OK) + { + if (x->x_argv[i] = Tcl_GetObjResult(interp)) + { + PLUSDEBUG_INCRREFCOUNT(x->x_argv[i], + "plustot_argsfromwords"); + Tcl_ResetResult(interp); +#ifdef PLUSTOT_DEBUG + post(", %sshared: '%s'", + (Tcl_IsShared(x->x_argv[i]) ? "" : "not "), + Tcl_GetString(x->x_argv[i])); +#endif + } + else + { + PLUSDEBUG_ENDPOST("plustot_argsfromtokens"); + plusloud_tcldirty((t_pd *)x, "plustot_argsfromtokens"); + } + } + else + { + PLUSDEBUG_ENDPOST("plustot_argsfromtokens"); + plusloud_tclerror((t_pd *)x, interp, "bad token"); + while (--i) + PLUSDEBUG_DECRREFCOUNT(x->x_argv[i], + "plustot_argsfromtokens"); + return (0); /* LATER find a proper way for passing a result */ + } + } + x->x_argc = nwords; + return (1); + } + else return (0); +} + +/* not used yet */ +static int plustot_ifgrabshared(t_plustot *x, Tcl_Obj *ob) +{ + if (!x->x_grabwarned) + { + x->x_grabwarned = 1; + loud_warning((t_pd *)x, "shared result of a command '%s'", + (x->x_cname ? Tcl_GetString(x->x_cname) : "???")); + } + return (1); +} + +static int plustot_push(t_plustot *x) +{ + if (x->x_proxies) + { + int i; + for (i = 1; i < x->x_nproxies; i++) + if (x->x_proxies[i]->pp_var) + if (!plusvar_push(x->x_proxies[i]->pp_var)) + return (0); + } + return (1); +} + +static int plustot_doit(t_plustot *x) +{ + int result = 0; + Tcl_Interp *interp = x->x_tob->tob_tin->tin_interp; + if (x->x_cname && plustot_push(x) && + plustot_argsfromwords(x, interp)) + { + if ((*x->x_cinfo.objProc)(x->x_cinfo.objClientData, interp, + x->x_argc, x->x_argv) == TCL_OK) + { + if (plustob_grabresult(x->x_tob)) + result = 1; + } + else plusloud_tclerror((t_pd *)x, interp, "command failed"); + /* Although args are to be reset in the next call to + plustot_argsfromwords(), however, plusvar_preset() will be called + first, so, unless reset is done here, $ins would be shared there. + LATER rethink. */ + plustot_resetargs(x); + } + return (result); +} + +static void plustot_eval(t_plustot *x) +{ + plustot_doit(x); +} + +static void plustot_get(t_plustot *x) +{ + if (x->x_tob->tob_value) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob); +} + +/* set in(0), no evaluation */ +static void plustot_set(t_plustot *x, t_symbol *s, int ac, t_atom *av) +{ + if (x->x_mainproxy) + { + if (ac == 1) + { + if (av->a_type == A_FLOAT) + plusproxy_float(x->x_mainproxy, av->a_w.w_float); + else if (av->a_type == A_SYMBOL) + plusproxy_symbol(x->x_mainproxy, av->a_w.w_symbol); + } + else plusproxy_list(x->x_mainproxy, s, ac, av); + } +} + +static void plustot_bang(t_plustot *x) +{ + if (x->x_mainproxy) + plusproxy_bang(x->x_mainproxy); + if (plustot_doit(x)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob); +} + +static void plustot_float(t_plustot *x, t_float f) +{ + if (x->x_mainproxy) + plusproxy_float(x->x_mainproxy, f); + if (plustot_doit(x)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob); +} + +static void plustot_symbol(t_plustot *x, t_symbol *s) +{ + if (x->x_mainproxy) + plusproxy_symbol(x->x_mainproxy, s); + if (plustot_doit(x)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob); +} + +static void plustot_list(t_plustot *x, t_symbol *s, int ac, t_atom *av) +{ + if (x->x_mainproxy) + plusproxy_list(x->x_mainproxy, s, ac, av); + if (plustot_doit(x)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob); +} + +static void plustot_tot(t_plustot *x, t_symbol *s, int ac, t_atom *av) +{ + if (ac) + { + Tcl_Obj *ob; + char *start; + int len; + scriptlet_reset(x->x_script); + scriptlet_add(x->x_script, 1, 1, ac, av); + start = scriptlet_getcontents(x->x_script, &len); + if (len > 0 && (ob = Tcl_NewStringObj(start, len))) + { + /* LATER set a persistent ob, rather than create a new one */ + PLUSDEBUG_INCRREFCOUNT(ob, "plustot_tot"); + if (plustob_evalob(x->x_tob, ob) && s == totps_query) + outlet_plusbob(((t_object *)x)->ob_outlet, + (t_plusbob *)x->x_tob); + PLUSDEBUG_DECRREFCOUNT(ob, "plustot_tot"); + } + } +} + +#ifdef PLUSTOT_DEBUG +static void plustot_debug(t_plustot *x) +{ + t_plustin *tin = x->x_tob->tob_tin; + t_symbol *id = plusenv_getid((t_plusenv *)tin); + t_symbol *glname = plustin_getglistname(tin); + post("+tot, glist %x", (int)x->x_glist); + post(" plustin '%s' (%s) over %x", (id ? id->s_name : "default"), + (glname ? glname->s_name : ""), (int)tin->tin_interp); + if (x->x_mainproxy) + plusproxy_debug(x->x_mainproxy); +} +#endif + +static void plustot_free(t_plustot *x) +{ + int i; + plusbob_release((t_plusbob *)x->x_tob); + if (x->x_cname) PLUSDEBUG_DECRREFCOUNT(x->x_cname, "plustot_free"); + if (x->x_ctail) + { + for (i = 1; i < x->x_nwords; i++) + PLUSDEBUG_DECRREFCOUNT(x->x_words[i].pw_ob, "plustot_free"); + for (i = 1; i < x->x_argc; i++) + PLUSDEBUG_DECRREFCOUNT(x->x_argv[i], "plustot_free"); + if (x->x_words != x->x_wordsini) + freebytes(x->x_words, x->x_maxwords * sizeof(*x->x_words)); + if (x->x_argv != x->x_argvini) + freebytes(x->x_argv, x->x_maxwords * sizeof(*x->x_argv)); + Tcl_FreeParse(&x->x_tailparse); + plusstring_release(x->x_ctail); + } + if (x->x_mainproxy) pd_free((t_pd *)x->x_mainproxy); + if (x->x_proxies) + { + for (i = 1; i < x->x_nproxies; i++) + pd_free((t_pd *)x->x_proxies[i]); + freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies)); + } + if (x->x_script) scriptlet_free(x->x_script); +} + +static void *plustot_new(t_symbol *s, int ac, t_atom *av) +{ + t_plustot *x = 0; + t_plusstring *ctail = 0; + t_symbol *cmdname = 0; /* command name or +selector */ + t_glist *glist = canvas_getcurrent(); + t_plustin *tin = 0; + t_plustob *tob = 0; + t_scriptlet *script = scriptlet_new(0, 0, 0, 0, glist, 0); + if (ac && av->a_type == A_SYMBOL) + { + cmdname = av->a_w.w_symbol; + ac--; av++; + if (*cmdname->s_name == '+') + { + if (cmdname == plusps_env) + return (plustot_env_new(cmdname, ac, av)); + else if (cmdname == plusps_in) + return (plustot_in_new(cmdname, ac, av)); + else if (cmdname == plusps_var) + return (plustot_var_new(cmdname, ac, av)); + else if (cmdname == plusps_out) + return (plustot_out_new(cmdname, ac, av)); + else if (cmdname == plusps_qlist) + return (plustot_qlist_new(cmdname, ac, av)); + else if (cmdname == plusps_print) + return (plustot_print_new(cmdname, ac, av)); + else + { + loud_error(0, "unknown +tot's subclass"); + return (0); + } + } + if (ac) + { + ctail = plusstring_fromatoms(ac, av, script); + plusstring_preserve(ctail); + } + } + if ((tin = plustin_glistprovide(glist, PLUSTIN_GLIST_ANY, 0)) && + (tob = plustob_new(tin, 0))) + { + x = (t_plustot *)pd_new(plustot_class); + /* tin already preserved (plustob_new() did it) */ + plusbob_preserve((t_plusbob *)tob); + plusbob_setowner((t_plusbob *)tob, (t_pd *)x); + x->x_glist = glist; + x->x_tob = tob; + scriptlet_setowner(script, (t_pd *)x); + x->x_script = script; + x->x_cname = 0; + x->x_ctail = 0; + x->x_words = x->x_wordsini; + plustot_initwords(x); + x->x_argv = x->x_argvini; + plustot_initargs(x); + x->x_pseudoscalar = 0; + x->x_nproxies = 0; + x->x_proxies = 0; + x->x_mainproxy = 0; + x->x_grabwarned = 0; + if (cmdname && *cmdname->s_name) + { + Tcl_Interp *interp = tin->tin_interp; + if (interp) + { + if (Tcl_GetCommandInfo(interp, cmdname->s_name, &x->x_cinfo)) + { + if (x->x_cinfo.isNativeObjectProc) + { + x->x_cname = Tcl_NewStringObj(cmdname->s_name, -1); + PLUSDEBUG_INCRREFCOUNT(x->x_cname, "plustot_new"); + x->x_argv[0] = x->x_cname; + } + else loud_error((t_pd *)x, "'%s' is not an object command", + cmdname->s_name); + } + else loud_error((t_pd *)x, "command '%s' does not exist", + cmdname->s_name); + if (x->x_cname && ctail) + { + int nvars = + plustot_parsevariables(x, interp, + ctail->ps_buf, ctail->ps_len, + &x->x_tailparse, 0); + if (nvars >= 0) + { + int res = 1; + x->x_ctail = ctail; + if (x->x_nproxies) + res = plustot_makeproxies(x); + if (res) + res = plustot_makewords(x); + if (!res) + x->x_ctail = 0; + Tcl_FreeParse(&x->x_tailparse); + } + else + { + if (nvars == PLUSTOT_ERRUNKNOWN) + plusloud_tclerror((t_pd *)x, interp, + "parsing command arguments failed"); + else + Tcl_FreeParse(&x->x_tailparse); + PLUSDEBUG_DECRREFCOUNT(x->x_cname, "plustot_new"); + x->x_cname = 0; + } + } + } + } + outlet_new((t_object *)x, &s_symbol); + } + else + { + loud_error(0, "+tot: cannot initialize"); + if (tin) + { + plusbob_preserve((t_plusbob *)tin); + plusbob_release((t_plusbob *)tin); + } + if (script) scriptlet_free(script); + } + if (ctail && !(x && x->x_ctail)) + plusstring_release(ctail); + return (x); +} + +void plustot_setup(void) +{ + post("beware! this is plustot %s, %s %s build...", + TOXY_VERSION, loud_ordinal(TOXY_BUILD), TOXY_RELEASE); + plustot_class = class_new(gensym("+tot"), + (t_newmethod)plustot_new, + (t_method)plustot_free, + sizeof(t_plustot), 0, A_GIMME, 0); + class_addcreator((t_newmethod)plustot_new, + gensym("plustot"), A_GIMME, 0); + class_addbang(plustot_class, plustot_bang); + class_addfloat(plustot_class, plustot_float); + class_addsymbol(plustot_class, plustot_symbol); + class_addlist(plustot_class, plustot_list); + class_addmethod(plustot_class, (t_method)plustot_eval, + gensym("eval"), 0); + class_addmethod(plustot_class, (t_method)plustot_set, + gensym("set"), A_GIMME, 0); + class_addmethod(plustot_class, (t_method)plustot_get, + gensym("get"), 0); + class_addmethod(plustot_class, (t_method)plustot_tot, + gensym("tot"), A_GIMME, 0); + class_addmethod(plustot_class, (t_method)plustot_tot, + gensym("query"), A_GIMME, 0); +#ifdef PLUSTOT_DEBUG + class_addmethod(plustot_class, (t_method)plustot_debug, + gensym("debug"), 0); +#endif + + plusproxy_class = class_new(gensym("+tot proxy"), 0, + (t_method)plusproxy_free, + sizeof(t_plusproxy), CLASS_PD, 0); + class_addfloat(plusproxy_class, plusproxy_float); + class_addsymbol(plusproxy_class, plusproxy_symbol); + class_addlist(plusproxy_class, plusproxy_list); +#ifdef PLUSTOT_DEBUG + class_addmethod(plusproxy_class, (t_method)plusproxy_debug, + gensym("debug"), 0); +#endif + + plusps_tot = gensym("+tot"); + plusps_env = gensym("+env"); + plusps_in = gensym("+in"); + plusps_var = gensym("+var"); + plusps_out = gensym("+out"); + plusps_qlist = gensym("+qlist"); + plusps_print = gensym("+print"); + plusps_Ti = gensym("+Ti"); + plusps_To = gensym("+To"); + plusps_Tv = gensym("+Tv"); + totps_query = gensym("query"); + + plustin_basetype = plusenv_setup(); + plustin_type = plustype_new(plustin_basetype, plusps_Ti, + sizeof(t_plustin), + (t_plustypefn)plustin_delete, 0, 0, 0); + plustob_type = plustype_new(0, plusps_To, + sizeof(t_plustob), + (t_plustypefn)plustob_delete, 0, 0, + (t_plustypefn)plustob_attach); + plusvar_type = plustype_new(plustob_type, plusps_Tv, + sizeof(t_plusvar), + (t_plustypefn)plusvar_delete, 0, 0, 0); + + plustot_env_setup(); + plustot_in_setup(); + plustot_var_setup(); + plustot_out_setup(); + plustot_qlist_setup(); + plustot_print_setup(); +} diff --git a/toxy/plustot.env.c b/toxy/plustot.env.c new file mode 100644 index 0000000..c1dbfe2 --- /dev/null +++ b/toxy/plustot.env.c @@ -0,0 +1,150 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include +#include +#ifdef UNIX +#include +#endif +#ifdef NT +#include +#endif +#include "m_pd.h" +#include "g_canvas.h" +#include "common/loud.h" +#include "hammer/file.h" +#include "toxy/plusbob.h" +#include "plustot.h" + +typedef struct _plustot_env +{ + t_object x_ob; + t_plustin *x_tin; + t_glist *x_glist; + t_hammerfile *x_filehandle; +} t_plustot_env; + +static t_class *plustot_env_class; + +static void plustot_env_takeover(t_glist *glist, t_plusbob *defparent, + t_plusbob *newparent) +{ + t_gobj *g; + for (g = glist->gl_list; g; g = g->g_next) + { + if (pd_class(&g->g_pd) == canvas_class) + { + if (!plustin_glistfind((t_glist *)g, PLUSTIN_GLIST_THIS)) + plustot_env_takeover((t_glist *)g, defparent, newparent); + } + else plusbob_detachownedchildren(defparent, newparent, (t_pd *)g); + } +} + +static void plustot_env_evalfile(t_plustot_env *x, t_symbol *fname) +{ + char buf1[MAXPDSTRING], buf2[MAXPDSTRING], *nameptr, *dir; + int fd; + dir = canvas_getdir(x->x_glist)->s_name; + if ((fd = open_via_path(dir, fname->s_name, "", + buf1, &nameptr, MAXPDSTRING, 0)) < 0) + { + loud_error((t_pd *)x, "file '%s' not found", fname->s_name); + } + else + { + Tcl_Interp *interp = plustin_getinterp(x->x_tin); + FILE *fp; + close(fd); + strcpy(buf2, buf1); + strcat(buf2, "/"); + strcat(buf2, nameptr); + sys_bashfilename(buf2, buf2); + Tcl_Preserve(interp); + if (Tcl_EvalFile(interp, buf2) != TCL_OK) + { + strcpy(buf1, "evaluation failed ("); + strncat(buf1, buf2, MAXPDSTRING - strlen(buf1) - 2); + strcat(buf1, ")"); + plusloud_tclerror((t_pd *)x, interp, buf1); + } + Tcl_Release(interp); + } +} + +static void plustot_env_evalfilehook(t_pd *z, t_symbol *fn, int ac, t_atom *av) +{ + plustot_env_evalfile((t_plustot_env *)z, fn); +} + +static void plustot_env_bang(t_plustot_env *x) +{ + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tin); +} + +static void plustot_env_source(t_plustot_env *x, t_symbol *s) +{ + if (s && s != &s_) + plustot_env_evalfile(x, s); + else + hammerpanel_open(x->x_filehandle, 0); +} + +static void plustot_env_free(t_plustot_env *x) +{ + t_plustin *tin = plustin_glistprovide(x->x_glist, PLUSTIN_GLIST_UP, 0); + plusbob_detachchildren((t_plusbob *)x->x_tin, (t_plusbob *)tin); + plusbob_release((t_plusbob *)x->x_tin); + hammerfile_free(x->x_filehandle); +} + +void *plustot_env_new(t_symbol *s, int ac, t_atom *av) +{ + t_plustot_env *x = 0; + t_glist *gl = canvas_getcurrent(); + t_plustin *oldtin = plustin_glistfind(gl, PLUSTIN_GLIST_THIS); + t_plustin *deftin = (oldtin ? 0 : plustin_glistfind(gl, PLUSTIN_GLIST_ANY)); + t_plustin *tin = 0; + if ((tin = oldtin) + || (tin = plustin_glistprovide(gl, PLUSTIN_GLIST_THIS, 1))) + { + int warned = 0; + x = (t_plustot_env *)pd_new(plustot_env_class); + x->x_tin = tin; + plusbob_preserve((t_plusbob *)tin); + x->x_glist = gl; + outlet_new((t_object *)x, &s_symbol); + if (deftin) + /* true if both oldtin == 0 (we are first in this glist) + and plustin_default != 0 (bobs exist already) */ + plustot_env_takeover(x->x_glist, + (t_plusbob *)deftin, (t_plusbob *)tin); + x->x_filehandle = hammerfile_new((t_pd *)x, 0, + plustot_env_evalfilehook, 0, 0); + while (ac--) + { + if (av->a_type == A_SYMBOL) + plustot_env_evalfile(x, av->a_w.w_symbol); + else if (!warned) + { + loud_warning((t_pd *)x, "bad atom"); + warned = 1; + } + av++; + } + } + else loud_error(0, "+env: cannot initialize"); + return (x); +} + +void plustot_env_setup(void) +{ + plustot_env_class = class_new(gensym("+env"), 0, + (t_method)plustot_env_free, + sizeof(t_plustot_env), 0, 0); + class_addbang(plustot_env_class, plustot_env_bang); + class_addmethod(plustot_env_class, (t_method)plustot_env_source, + gensym("source"), A_DEFSYM, 0); + hammerfile_setup(plustot_env_class, 0); +} diff --git a/toxy/plustot.h b/toxy/plustot.h new file mode 100644 index 0000000..e08e7b0 --- /dev/null +++ b/toxy/plustot.h @@ -0,0 +1,81 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#ifndef __PLUSTOT_H__ +#define __PLUSTOT_H__ + +#define PD_EXTERN EXTERN +#undef EXTERN +#include +#undef EXTERN +#define EXTERN PD_EXTERN +#undef PD_EXTERN + +EXTERN_STRUCT _plustin; +#define t_plustin struct _plustin +EXTERN_STRUCT _plustob; +#define t_plustob struct _plustob +EXTERN_STRUCT _plusvar; +#define t_plusvar struct _plusvar + +t_symbol *plusps_Ti; +t_symbol *plusps_To; +t_symbol *plusps_Tv; + +#define PLUSTOB_MAKEIT ((Tcl_Obj *)-1) + +typedef int (*t_plusifsharedfn)(t_plusbob *, Tcl_Obj *); + +enum { PLUSTIN_GLIST_THIS, PLUSTIN_GLIST_ANY, PLUSTIN_GLIST_UP }; + +void plusloud_tclerror(t_pd *caller, Tcl_Interp *interp, char *msg); + +t_plustin *plustin_create(t_plustype *tp, t_plusbob *parent, t_symbol *id); +Tcl_Interp *plustin_getinterp(t_plustin *tin); +t_symbol *plustin_glistid(t_glist *gl); +t_plustin *plustin_glistfind(t_glist *gl, int mode); +t_plustin *plustin_glistprovide(t_glist *gl, int mode, int create); +t_symbol *plustin_getglistname(t_plustin *tin); + +t_plustob *plustob_create(t_plustype *tp, t_plustin *tin, Tcl_Obj *ob); +t_plustob *plustob_new(t_plustin *tin, Tcl_Obj *ob); +void plustob_setifshared(t_plustob *tob, t_plusifsharedfn ifsharedfn); +int plustob_isshared(t_plustob *tob); +Tcl_Obj *plustob_getvalue(t_plustob *tob); +t_plustin *plustag_tobtin(t_symbol *s, t_pd *caller); +Tcl_Obj *plustag_tobvalue(t_symbol *s, t_pd *caller); +Tcl_Obj *plusatom_tobvalue(t_atom *ap, t_pd *caller); +Tcl_Obj *plustob_set(t_plustob *tob, t_plustin *tin, Tcl_Obj *ob); +Tcl_Obj *plustob_setfloat(t_plustob *tob, t_float f); +Tcl_Obj *plustob_setsymbol(t_plustob *tob, t_symbol *s); +Tcl_Obj *plustob_setlist(t_plustob *tob, int ac, t_atom *av); +Tcl_Obj *plustob_setbinbuf(t_plustob *tob, t_binbuf *bb); +Tcl_Obj *plustob_grabresult(t_plustob *tob); +Tcl_Obj *plustob_evalob(t_plustob *tob, Tcl_Obj *ob); + +t_plusvar *plusvar_create(t_plustype *tp, t_plustin *tin, Tcl_Obj *ob, + char *name, char *index); +t_plusvar *plusvar_new(char *name, char *index, t_plustin *tin); +Tcl_Obj *plusvar_push(t_plusvar *var); +Tcl_Obj *plusvar_pull(t_plusvar *var); +Tcl_Obj *plusvar_set(t_plusvar *var, Tcl_Obj *ob, int doit); +Tcl_Obj *plusvar_setfloat(t_plusvar *var, t_float f, int doit); +Tcl_Obj *plusvar_setsymbol(t_plusvar *var, t_symbol *s, int doit); +Tcl_Obj *plusvar_setlist(t_plusvar *var, int ac, t_atom *av, int doit); + +void plustot_env_setup(void); +void plustot_in_setup(void); +void plustot_var_setup(void); +void plustot_out_setup(void); +void plustot_qlist_setup(void); +void plustot_print_setup(void); + +void *plustot_env_new(t_symbol *s, int ac, t_atom *av); +void *plustot_in_new(t_symbol *s, int ac, t_atom *av); +void *plustot_var_new(t_symbol *s, int ac, t_atom *av); +void *plustot_out_new(t_symbol *s, int ac, t_atom *av); +void *plustot_qlist_new(t_symbol *s, int ac, t_atom *av); +void *plustot_print_new(t_symbol *s, int ac, t_atom *av); + +#endif diff --git a/toxy/plustot.in.c b/toxy/plustot.in.c new file mode 100644 index 0000000..206b8b0 --- /dev/null +++ b/toxy/plustot.in.c @@ -0,0 +1,126 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include "m_pd.h" +#include "common/loud.h" +#include "toxy/plusbob.h" +#include "plustot.h" + +typedef struct _plusproxy_in +{ + t_pd pp_pd; + t_plustob *pp_tob; +} t_plusproxy_in; + +typedef struct _plustot_in +{ + t_object x_ob; + t_glist *x_glist; + t_plustob *x_tob; + t_plusproxy_in *x_proxy; +} t_plustot_in; + +static t_class *plusproxy_in_class; +static t_class *plustot_in_class; + +static t_plusproxy_in *plusproxy_in_new(t_pd *master) +{ + t_plusproxy_in *pp = (t_plusproxy_in *)pd_new(plusproxy_in_class); + pp->pp_tob = ((t_plustot_in *)master)->x_tob; + return (pp); +} + +static void plusproxy_in_float(t_plusproxy_in *pp, t_float f) +{ + plustob_setfloat(pp->pp_tob, f); +} + +static void plusproxy_in_symbol(t_plusproxy_in *pp, t_symbol *s) +{ + plustob_setsymbol(pp->pp_tob, s); +} + +static void plusproxy_in_list(t_plusproxy_in *pp, + t_symbol *s, int ac, t_atom *av) +{ + plustob_setlist(pp->pp_tob, ac, av); +} + +static void plustot_in_bang(t_plustot_in *x) +{ + if (plustob_getvalue(x->x_tob)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob); +} + +static void plustot_in_float(t_plustot_in *x, t_float f) +{ + if (plustob_setfloat(x->x_tob, f)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob); +} + +static void plustot_in_symbol(t_plustot_in *x, t_symbol *s) +{ + if (plustob_setsymbol(x->x_tob, s)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob); +} + +static void plustot_in_list(t_plustot_in *x, t_symbol *s, int ac, t_atom *av) +{ + if (plustob_setlist(x->x_tob, ac, av)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob); +} + +static void plustot_in_free(t_plustot_in *x) +{ + plusbob_release((t_plusbob *)x->x_tob); + if (x->x_proxy) pd_free((t_pd *)x->x_proxy); +} + +void *plustot_in_new(t_symbol *s, int ac, t_atom *av) +{ + t_plustot_in *x = 0; + t_glist *glist = canvas_getcurrent(); + t_plustin *tin = 0; + t_plustob *tob = 0; + if ((tin = plustin_glistprovide(glist, PLUSTIN_GLIST_ANY, 0)) && + (tob = plustob_new(tin, 0))) + { + x = (t_plustot_in *)pd_new(plustot_in_class); + plusbob_preserve((t_plusbob *)tob); + plusbob_setowner((t_plusbob *)tob, (t_pd *)x); + plustob_setlist(tob, ac, av); + x->x_glist = glist; + x->x_tob = tob; + x->x_proxy = plusproxy_in_new((t_pd *)x); + inlet_new((t_object *)x, (t_pd *)x->x_proxy, 0, 0); + outlet_new((t_object *)x, &s_symbol); + } + else + { + loud_error(0, "+in: cannot initialize"); + if (tin) + { + plusbob_preserve((t_plusbob *)tin); + plusbob_release((t_plusbob *)tin); + } + } + return (x); +} + +void plustot_in_setup(void) +{ + plustot_in_class = class_new(gensym("+in"), 0, + (t_method)plustot_in_free, + sizeof(t_plustot_in), 0, 0); + class_addbang(plustot_in_class, plustot_in_bang); + class_addfloat(plustot_in_class, plustot_in_float); + class_addsymbol(plustot_in_class, plustot_in_symbol); + class_addlist(plustot_in_class, plustot_in_list); + + plusproxy_in_class = class_new(gensym("+in proxy"), 0, 0, + sizeof(t_plusproxy_in), CLASS_PD, 0); + class_addfloat(plusproxy_in_class, plusproxy_in_float); + class_addsymbol(plusproxy_in_class, plusproxy_in_symbol); + class_addlist(plusproxy_in_class, plusproxy_in_list); +} diff --git a/toxy/plustot.out.c b/toxy/plustot.out.c new file mode 100644 index 0000000..9b70d55 --- /dev/null +++ b/toxy/plustot.out.c @@ -0,0 +1,71 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include "m_pd.h" +#include "common/loud.h" +#include "toxy/plusbob.h" +#include "plustot.h" + +typedef struct _plustot_out +{ + t_object x_ob; + t_binbuf *x_bb; +} t_plustot_out; + +static t_class *plustot_out_class; + +static void plustot_out_symbol(t_plustot_out *x, t_symbol *s) +{ + Tcl_Obj *ob = plustag_tobvalue(s, (t_pd *)x); + if (ob) + { + int len; + char *ptr; + Tcl_IncrRefCount(ob); + ptr = Tcl_GetStringFromObj(ob, &len); + if (ptr && len) + { + int ac; + binbuf_text(x->x_bb, ptr, len); + if (ac = binbuf_getnatom(x->x_bb)) + { + t_atom *av = binbuf_getvec(x->x_bb); + if (av->a_type == A_SYMBOL) + outlet_anything(((t_object *)x)->ob_outlet, + av->a_w.w_symbol, ac - 1, av + 1); + else if (av->a_type == A_FLOAT) + { + if (ac > 1) + outlet_list(((t_object *)x)->ob_outlet, + &s_list, ac, av); + else + outlet_float(((t_object *)x)->ob_outlet, + av->a_w.w_float); + } + } + } + Tcl_DecrRefCount(ob); + } +} + +static void plustot_out_free(t_plustot_out *x) +{ + binbuf_free(x->x_bb); +} + +void *plustot_out_new(t_symbol *s, int ac, t_atom *av) +{ + t_plustot_out *x = (t_plustot_out *)pd_new(plustot_out_class); + x->x_bb = binbuf_new(); + outlet_new((t_object *)x, &s_anything); + return (x); +} + +void plustot_out_setup(void) +{ + plustot_out_class = class_new(gensym("+out"), 0, + (t_method)plustot_out_free, + sizeof(t_plustot_out), 0, 0); + class_addsymbol(plustot_out_class, plustot_out_symbol); +} diff --git a/toxy/plustot.print.c b/toxy/plustot.print.c new file mode 100644 index 0000000..42ef385 --- /dev/null +++ b/toxy/plustot.print.c @@ -0,0 +1,90 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include "m_pd.h" +#include "common/loud.h" +#include "toxy/plusbob.h" +#include "plustot.h" + +typedef struct _plustot_print +{ + t_object x_ob; + t_symbol *x_label; + t_binbuf *x_bb; +} t_plustot_print; + +static t_class *plustot_print_class; + +static void plustot_print_symbol(t_plustot_print *x, t_symbol *s) +{ + Tcl_Obj *ob = plustag_tobvalue(s, (t_pd *)x); + if (ob) + { + int len; + char *ptr; + Tcl_IncrRefCount(ob); + ptr = Tcl_GetStringFromObj(ob, &len); + if (ptr && len) + { + int ac; + binbuf_text(x->x_bb, ptr, len); + if (ac = binbuf_getnatom(x->x_bb)) + { + t_plustin *tin = plustag_tobtin(s, (t_pd *)x); + t_symbol *glname = (tin ? plustin_getglistname(tin) : 0); + t_atom *av = binbuf_getvec(x->x_bb); + if (av->a_type == A_SYMBOL || av->a_type == A_FLOAT) + { + char *lstring = + (x->x_label ? x->x_label->s_name : + loud_symbolname(plustag_typename(s, 1, (t_pd *)x), + "???")); + if (glname) + startpost("%s (%s):", lstring, glname->s_name); + else + startpost("%s:", lstring); + } + /* FIXME {1.0, 1.0}, etc. */ + if (av->a_type == A_SYMBOL) + { + startpost(" %s", av->a_w.w_symbol->s_name); + postatom(ac - 1, av + 1); + endpost(); + } + else if (av->a_type == A_FLOAT) + { + if (ac > 1) + { + postatom(ac, av); + endpost(); + } + else post(" %g", av->a_w.w_float); + } + } + /* LATER consider printing empty list as 'bang' */ + } + Tcl_DecrRefCount(ob); + } +} + +static void plustot_print_free(t_plustot_print *x) +{ + binbuf_free(x->x_bb); +} + +void *plustot_print_new(t_symbol *s, int ac, t_atom *av) +{ + t_plustot_print *x = (t_plustot_print *)pd_new(plustot_print_class); + x->x_label = (ac && av->a_type == A_SYMBOL ? av->a_w.w_symbol : 0); + x->x_bb = binbuf_new(); + return (x); +} + +void plustot_print_setup(void) +{ + plustot_print_class = class_new(gensym("+print"), 0, + (t_method)plustot_print_free, + sizeof(t_plustot_print), 0, 0); + class_addsymbol(plustot_print_class, plustot_print_symbol); +} diff --git a/toxy/plustot.qlist.c b/toxy/plustot.qlist.c new file mode 100644 index 0000000..b49aeb1 --- /dev/null +++ b/toxy/plustot.qlist.c @@ -0,0 +1,212 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include +#include "m_pd.h" +#include "unstable/fragile.h" +#include "common/loud.h" +#include "toxy/plusbob.h" +#include "plustot.h" + +#define PLUSTOT_QLIST_DEBUG + +/* Need only an access to x_binbuf field. */ +typedef struct _qlist +{ + t_object x_ob; + t_outlet *x_bangout; + void *x_binbuf; +} t_qlist; + +typedef struct _plusproxy_qlist +{ + t_pd pp_pd; + struct _plustot_qlist *pp_master; +} t_plusproxy_qlist; + +typedef struct _plustot_qlist +{ + t_object x_ob; + t_glist *x_glist; + t_plustob *x_tob; + t_outlet *x_rightout; + t_plusproxy_qlist *x_proxy; +} t_plustot_qlist; + +static t_class *plusproxy_qlist_class; +static t_class *plustot_qlist_class; + +static t_binbuf *plustot_qlist_usurp(t_plustot_qlist *x) +{ + static t_symbol *types[2]; + static int ntypes = 0; + t_object *booty; + if (ntypes == 0) + { + types[0] = gensym("qlist"); + types[1] = gensym("textfile"); + ntypes = 2; + } + if (booty = fragile_outlet_destination( + ((t_object *)x)->ob_outlet, ntypes, types, + (t_pd *)x, "(connect left outlet to a qlist or textfile)")) + { + t_binbuf *bb = ((t_qlist *)booty)->x_binbuf; +#ifdef PLUSTOT_QLIST_DEBUG + post("booty '%s' at %x:", class_getname(*(t_pd *)booty), (int)booty); + binbuf_print(bb); +#endif + return (bb); + } + else return (0); +} + +static t_plusproxy_qlist *plusproxy_qlist_new(t_plustot_qlist *master) +{ + t_plusproxy_qlist *pp = (t_plusproxy_qlist *)pd_new(plusproxy_qlist_class); + pp->pp_master = master; + return (pp); +} + +static void plusproxy_qlist_symbol(t_plusproxy_qlist *pp, t_symbol *s) +{ + t_plustot_qlist *x = pp->pp_master; + Tcl_Interp *interp = 0; + if (plustag_isvalid(s, 0)) + { + t_plustin *tin; + Tcl_Obj *ob; + if ((tin = plustag_tobtin(s, PLUSBOB_OWNER)) && + (ob = plustob_getvalue((t_plustob *)s))) + { + t_binbuf *bb; + if (bb = plustot_qlist_usurp(x)) + { + int nlists; + Tcl_Obj **lists; + interp = plustin_getinterp(tin); + if (Tcl_ListObjGetElements(interp, ob, + &nlists, &lists) == TCL_OK) + { + int lc; + Tcl_Obj **lp; + binbuf_clear(bb); + for (lc = 0, lp = lists; lc < nlists; lc++, lp++) + { + int natoms; + Tcl_Obj **atoms; + if (Tcl_ListObjGetElements(interp, *lp, + &natoms, &atoms) == TCL_OK) + { + int ac; + Tcl_Obj **ap; + for (ac = 0, ap = atoms; ac < natoms; ac++, ap++) + { + double d; + int len; + char *ptr; + Tcl_IncrRefCount(*ap); + if (Tcl_GetDoubleFromObj(interp, + *ap, &d) == TCL_OK) + { + t_atom at; + SETFLOAT(&at, (float)d); + binbuf_add(bb, 1, &at); + } + else if ((ptr = Tcl_GetStringFromObj(*ap, &len)) + && len) + { + t_atom at; + if (ptr[len - 1]) + { + char buf[MAXPDSTRING]; + if (len > MAXPDSTRING - 1) + len = MAXPDSTRING - 1; + strncpy(buf, ptr, len); + buf[len] = 0; + ptr = buf; + } + SETSYMBOL(&at, gensym(ptr)); + binbuf_add(bb, 1, &at); + } + /* FIXME else */ + Tcl_DecrRefCount(*ap); + } + binbuf_addsemi(bb); + } + else + { + binbuf_clear(bb); + goto notalist; + } + } + } + else goto notalist; + } + } + } + return; +notalist: + if (interp) plusloud_tclerror((t_pd *)x, interp, "not a list"); +} + +static void plustot_qlist_bang(t_plustot_qlist *x) +{ + t_binbuf *bb; + if (bb = plustot_qlist_usurp(x)) + { + if (plustob_setbinbuf(x->x_tob, bb)) + outlet_plusbob(x->x_rightout, (t_plusbob *)x->x_tob); + } +} + +static void plustot_qlist_free(t_plustot_qlist *x) +{ + plusbob_release((t_plusbob *)x->x_tob); + if (x->x_proxy) pd_free((t_pd *)x->x_proxy); +} + +void *plustot_qlist_new(t_symbol *s, int ac, t_atom *av) +{ + t_plustot_qlist *x = 0; + t_glist *glist = canvas_getcurrent(); + t_plustin *tin = 0; + t_plustob *tob = 0; + if ((tin = plustin_glistprovide(glist, PLUSTIN_GLIST_ANY, 0)) && + (tob = plustob_new(tin, 0))) + { + x = (t_plustot_qlist *)pd_new(plustot_qlist_class); + plusbob_preserve((t_plusbob *)tob); + plusbob_setowner((t_plusbob *)tob, (t_pd *)x); + plustob_setlist(tob, ac, av); + x->x_glist = glist; + x->x_tob = tob; + x->x_proxy = plusproxy_qlist_new(x); + inlet_new((t_object *)x, (t_pd *)x->x_proxy, 0, 0); + outlet_new((t_object *)x, &s_anything); + x->x_rightout = outlet_new((t_object *)x, &s_symbol); + } + else + { + loud_error(0, "+qlist: cannot initialize"); + if (tin) + { + plusbob_preserve((t_plusbob *)tin); + plusbob_release((t_plusbob *)tin); + } + } + return (x); +} + +void plustot_qlist_setup(void) +{ + plustot_qlist_class = class_new(gensym("+qlist"), 0, + (t_method)plustot_qlist_free, + sizeof(t_plustot_qlist), 0, 0); + class_addbang(plustot_qlist_class, plustot_qlist_bang); + + plusproxy_qlist_class = class_new(gensym("+qlist proxy"), 0, 0, + sizeof(t_plusproxy_qlist), CLASS_PD, 0); + class_addsymbol(plusproxy_qlist_class, plusproxy_qlist_symbol); +} diff --git a/toxy/plustot.var.c b/toxy/plustot.var.c new file mode 100644 index 0000000..a5f36a7 --- /dev/null +++ b/toxy/plustot.var.c @@ -0,0 +1,130 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include "m_pd.h" +#include "common/loud.h" +#include "toxy/plusbob.h" +#include "plustot.h" + +typedef struct _plusproxy_var +{ + t_pd pp_pd; + t_plusvar *pp_var; +} t_plusproxy_var; + +typedef struct _plustot_var +{ + t_object x_ob; + t_glist *x_glist; + t_plusvar *x_var; + t_plusproxy_var *x_proxy; +} t_plustot_var; + +static t_class *plusproxy_var_class; +static t_class *plustot_var_class; + +static t_plusproxy_var *plusproxy_var_new(t_pd *master) +{ + t_plusproxy_var *pp = (t_plusproxy_var *)pd_new(plusproxy_var_class); + pp->pp_var = ((t_plustot_var *)master)->x_var; + return (pp); +} + +static void plusproxy_var_float(t_plusproxy_var *pp, t_float f) +{ + plusvar_setfloat(pp->pp_var, f, 1); +} + +static void plusproxy_var_symbol(t_plusproxy_var *pp, t_symbol *s) +{ + plusvar_setsymbol(pp->pp_var, s, 1); +} + +static void plusproxy_var_list(t_plusproxy_var *pp, + t_symbol *s, int ac, t_atom *av) +{ + plusvar_setlist(pp->pp_var, ac, av, 1); +} + +static void plustot_var_bang(t_plustot_var *x) +{ + if (plusvar_pull(x->x_var)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_var); +} + +static void plustot_var_float(t_plustot_var *x, t_float f) +{ + if (plusvar_setfloat(x->x_var, f, 1)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_var); +} + +static void plustot_var_symbol(t_plustot_var *x, t_symbol *s) +{ + if (plusvar_setsymbol(x->x_var, s, 1)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_var); +} + +static void plustot_var_list(t_plustot_var *x, t_symbol *s, int ac, t_atom *av) +{ + if (plusvar_setlist(x->x_var, ac, av, 1)) + outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_var); +} + +static void plustot_var_free(t_plustot_var *x) +{ + plusbob_release((t_plusbob *)x->x_var); + if (x->x_proxy) pd_free((t_pd *)x->x_proxy); +} + +void *plustot_var_new(t_symbol *s, int ac, t_atom *av) +{ + t_plustot_var *x = 0; + t_glist *glist = canvas_getcurrent(); + t_plustin *tin = 0; + t_plusvar *var = 0; + if (ac && av->a_type == A_SYMBOL && + (tin = plustin_glistprovide(glist, PLUSTIN_GLIST_ANY, 0)) && + (var = plusvar_new(av->a_w.w_symbol->s_name, 0, tin))) + { + x = (t_plustot_var *)pd_new(plustot_var_class); + plusbob_preserve((t_plusbob *)var); + plusbob_setowner((t_plusbob *)var, (t_pd *)x); + plusvar_setlist(var, ac - 1, av + 1, 1); + x->x_glist = glist; + x->x_var = var; + x->x_proxy = plusproxy_var_new((t_pd *)x); + inlet_new((t_object *)x, (t_pd *)x->x_proxy, 0, 0); + outlet_new((t_object *)x, &s_symbol); + } + else + { + if (!ac || av->a_type != A_SYMBOL) + loud_error(0, "+var: missing name of a variable"); + else + loud_error(0, "+var: cannot initialize"); + if (tin) + { + plusbob_preserve((t_plusbob *)tin); + plusbob_release((t_plusbob *)tin); + } + } + return (x); +} + +void plustot_var_setup(void) +{ + plustot_var_class = class_new(gensym("+var"), 0, + (t_method)plustot_var_free, + sizeof(t_plustot_var), 0, 0); + class_addbang(plustot_var_class, plustot_var_bang); + class_addfloat(plustot_var_class, plustot_var_float); + class_addsymbol(plustot_var_class, plustot_var_symbol); + class_addlist(plustot_var_class, plustot_var_list); + + plusproxy_var_class = class_new(gensym("+var proxy"), 0, 0, + sizeof(t_plusproxy_var), CLASS_PD, 0); + class_addfloat(plusproxy_var_class, plusproxy_var_float); + class_addsymbol(plusproxy_var_class, plusproxy_var_symbol); + class_addlist(plusproxy_var_class, plusproxy_var_list); +} diff --git a/toxy/tot.c b/toxy/tot.c index 0bddfc3..385618c 100644 --- a/toxy/tot.c +++ b/toxy/tot.c @@ -456,11 +456,11 @@ static void *tot_new(t_symbol *s1, t_symbol *s2) char buf[64]; sprintf(buf, "tot%x", (int)x); pd_bind((t_pd *)x, x->x_target = gensym(buf)); - x->x_transient = - scriptlet_new((t_pd *)x, x->x_target, x->x_target, 0, tot_cvhook); - x->x_persistent = - scriptlet_new((t_pd *)x, x->x_target, x->x_target, 0, tot_cvhook); x->x_glist = canvas_getcurrent(); + x->x_transient = scriptlet_new((t_pd *)x, x->x_target, x->x_target, + 0, x->x_glist, tot_cvhook); + x->x_persistent = scriptlet_new((t_pd *)x, x->x_target, x->x_target, + 0, x->x_glist, tot_cvhook); if (s1 && s1 != &s_ && strcmp(s1->s_name, ".")) { x->x_cvremote = canvas_makebindsym(x->x_cvname = s1); diff --git a/toxy/toxy-shared.include b/toxy/toxy-shared.include index e831217..ec6c42c 100644 --- a/toxy/toxy-shared.include +++ b/toxy/toxy-shared.include @@ -9,6 +9,8 @@ shared/hammer/file.c shared/hammer/file.h shared/hammer/gui.c shared/hammer/gui.h +shared/unstable/fragile.c +shared/unstable/fragile.h shared/unstable/forky.c shared/unstable/forky.h shared/unstable/loader.c @@ -16,5 +18,7 @@ shared/unstable/loader.h shared/unstable/pd_imp.h shared/common/props.c shared/common/props.h +shared/toxy/plusbob.c +shared/toxy/plusbob.h shared/toxy/scriptlet.c shared/toxy/scriptlet.h diff --git a/toxy/widget.c b/toxy/widget.c index 253b649..a7a983a 100644 --- a/toxy/widget.c +++ b/toxy/widget.c @@ -23,7 +23,7 @@ static t_class *makeshift_class; //#define WIDGET_DEBUG //#define TOW_DEBUG -enum { WIDGET_NOUPDATE = 0, WIDGET_RECONFIG, WIDGET_REVIS }; +enum { WIDGET_NOVIS = 0, WIDGET_PUSHVIS, WIDGET_REVIS }; typedef struct _towentry { @@ -62,9 +62,9 @@ typedef struct _widget int x_height; t_symbol *x_background; int x_hasstate; - int x_update; /* see widget_update() */ - int x_selected; int x_disabled; + int x_selected; + int x_update; /* see widget_update() */ int x_vised; t_clock *x_transclock; t_towentry *x_towlist; @@ -95,10 +95,12 @@ static t_symbol *widgetps_motion; static t_symbol *widgetps_atbang; static t_symbol *widgetps_atfloat; static t_symbol *widgetps_atsymbol; +static t_symbol *widgetps_atstore; +static t_symbol *widgetps_atrestore; -static char *widget_propsresolver(t_pd *z, int ac, t_atom *av) +static char *widget_propsresolver(t_pd *owner, int ac, t_atom *av) { - t_widget *x = (t_widget *)z; + t_widget *x = (t_widget *)owner; int len; scriptlet_reset(x->x_auxscript); if (scriptlet_add(x->x_auxscript, 1, 0, ac, av)) @@ -107,9 +109,9 @@ static char *widget_propsresolver(t_pd *z, int ac, t_atom *av) return (0); } -static t_canvas *widget_cvhook(t_pd *z) +static t_canvas *widget_cvhook(t_pd *caller) { - return (glist_getcanvas(((t_widget *)z)->x_glist)); + return (glist_getcanvas(((t_widget *)caller)->x_glist)); } /* LATER move to scriptlet.c, use the scriptlet interface (.^) */ @@ -165,14 +167,14 @@ static void widget_transedit(t_widget *x) { t_text *newt, *oldt = (t_text *)x; t_binbuf *bb = binbuf_new(); - int nopt, nbnd, narg; + int nopt, nhnd, narg; t_atom *opt = props_getall(x->x_options, &nopt); - t_atom *bnd = props_getall(x->x_handlers, &nbnd); + t_atom *hnd = props_getall(x->x_handlers, &nhnd); t_atom *arg = props_getall(x->x_arguments, &narg); binbuf_addv(bb, "sss", gensym("widget"), x->x_type, x->x_name); if (narg) binbuf_add(bb, narg, arg); if (nopt) binbuf_add(bb, nopt, opt); - if (nbnd) binbuf_add(bb, nbnd, bnd); + if (nhnd) binbuf_add(bb, nhnd, hnd); canvas_setcurrent(x->x_glist); newt = (t_text *)pd_new(makeshift_class); newt->te_width = 0; @@ -211,6 +213,10 @@ static void widget_displace(t_gobj *z, t_glist *glist, int dx, int dy) { t_widget *x = (t_widget *)z; t_text *t = (t_text *)z; +#if 0 + post("displace %d %d (%d %d -> %d %d)", + dx, dy, t->te_xpix, t->te_ypix, t->te_xpix + dx, t->te_ypix + dy); +#endif t->te_xpix += dx; t->te_ypix += dy; if (glist_isvisible(glist)) @@ -219,11 +225,11 @@ static void widget_displace(t_gobj *z, t_glist *glist, int dx, int dy) canvas_fixlinesfor(glist_getcanvas(glist), t); } -static void widget_select(t_gobj *z, t_glist *glist, int state) +static void widget_select(t_gobj *z, t_glist *glist, int flag) { t_widget *x = (t_widget *)z; char *mypathname = widget_getmypathname(x, glist)->s_name; - if (state) + if (flag) { sys_vgui("%s config -bg blue %s\n", mypathname, (x->x_hasstate ? "-state disabled" : "")); @@ -235,7 +241,7 @@ static void widget_select(t_gobj *z, t_glist *glist, int state) sys_vgui("%s config -bg %s\n", mypathname, (x->x_background ? x->x_background->s_name : "gray")); else - sys_vgui("%s config -bg %s\n", mypathname, + sys_vgui("%s config -bg %s %s\n", mypathname, (x->x_background ? x->x_background->s_name : "gray"), (x->x_hasstate ? "-state normal" : "")); x->x_selected = 0; @@ -290,13 +296,20 @@ static void widget_pushinits(t_widget *x) bug("widget_pushinits (instance)"); } +static void widget_getconfig(t_widget *x) +{ + sys_vgui("::toxy::itemgetconfig %s %s\n", + widget_getmypathname(x, x->x_glist)->s_name, + x->x_cbtarget->s_name); +} + static void widget_vis(t_gobj *z, t_glist *glist, int vis) { t_widget *x = (t_widget *)z; t_text *t = (t_text *)z; char *cvpathname = widget_getcvpathname(x, glist)->s_name; char *mypathname = widget_getmypathname(x, glist)->s_name; - x->x_update = WIDGET_NOUPDATE; + x->x_update = WIDGET_NOVIS; if (vis) { float px1 = text_xpix((t_text *)x, glist); @@ -318,11 +331,7 @@ static void widget_vis(t_gobj *z, t_glist *glist, int vis) t_rtext *rt = glist_findrtext(glist, t); if (rt) rtext_free(rt); #endif - if (x->x_vised) - { - sys_vgui("destroy %s\n", mypathname); - x->x_vised = 0; - } + x->x_vised = 0; } } @@ -330,16 +339,16 @@ static void widget_save(t_gobj *z, t_binbuf *bb) { t_widget *x = (t_widget *)z; t_text *t = (t_text *)x; - int nopt, nbnd, narg; + int nopt, nhnd, narg; t_atom *opt = props_getall(x->x_options, &nopt); - t_atom *bnd = props_getall(x->x_handlers, &nbnd); + t_atom *hnd = props_getall(x->x_handlers, &nhnd); t_atom *arg = props_getall(x->x_arguments, &narg); binbuf_addv(bb, "ssiisss", gensym("#X"), gensym("obj"), (int)t->te_xpix, (int)t->te_ypix, gensym("widget"), x->x_type, x->x_name); if (narg) binbuf_add(bb, narg, arg); if (nopt) binbuf_add(bb, nopt, opt); - if (nbnd) binbuf_add(bb, nbnd, bnd); + if (nhnd) binbuf_add(bb, nhnd, hnd); binbuf_addsemi(bb); } @@ -405,27 +414,37 @@ static t_widgetbehavior widget_behavior = FORKY_WIDGETPADDING }; -static void widget_update(t_widget *x) +static void widget_update(t_widget *x, t_props *op) { - t_atom *ap; - int ac; - scriptlet_reset(x->x_optscript); - ap = props_getall(widgettype_getoptions(x->x_typedef), &ac); - if (ac) scriptlet_add(x->x_optscript, 0, 0, ac, ap); - ap = props_getall(x->x_options, &ac); - if (ac) scriptlet_add(x->x_optscript, 0, 0, ac, ap); - if (x->x_update && - glist_isvisible(x->x_glist)) /* FIXME the condition */ + if (op == x->x_options) { - if (x->x_update == WIDGET_REVIS) + t_atom *ap; + int ac; + scriptlet_reset(x->x_optscript); + ap = props_getall(widgettype_getoptions(x->x_typedef), &ac); + if (ac) scriptlet_add(x->x_optscript, 0, 0, ac, ap); + ap = props_getall(x->x_options, &ac); + if (ac) scriptlet_add(x->x_optscript, 0, 0, ac, ap); + if (x->x_update && + glist_isvisible(x->x_glist)) /* FIXME the condition */ { - widget_vis((t_gobj *)x, x->x_glist, 0); - widget_vis((t_gobj *)x, x->x_glist, 1); + if (x->x_update == WIDGET_REVIS) + { + widget_vis((t_gobj *)x, x->x_glist, 0); + widget_vis((t_gobj *)x, x->x_glist, 1); + } + else if (x->x_update == WIDGET_PUSHVIS) + { + widget_pushoptions(x, 1); + widget_getconfig(x); + } + x->x_update = WIDGET_NOVIS; } - else widget_pushoptions(x, 1); - x->x_update = WIDGET_NOUPDATE; } - /* LATER cache handlers */ + else + { + /* LATER cache handlers */ + } } static t_symbol *widget_addprops(t_widget *x, t_props *op, int single, @@ -438,7 +457,7 @@ static t_symbol *widget_addprops(t_widget *x, t_props *op, int single, if (empty) loud_error((t_pd *)x, "no value given for %s '%s'", props_getname(op), empty->s_name); - widget_update(x); + widget_update(x, op); return (empty); } else @@ -464,7 +483,7 @@ static void widget_anything(t_widget *x, t_symbol *s, int ac, t_atom *av) if (*s->s_name == '-' || *s->s_name == '@' || *s->s_name == '#') { t_symbol *empty; - x->x_update = WIDGET_RECONFIG; + x->x_update = WIDGET_PUSHVIS; if (empty = widget_addmessage(x, s, ac, av)) loud_errand((t_pd *)x, "(use 'remove %s' if that is what you want).", @@ -558,16 +577,32 @@ static void widget_symbol(t_widget *x, t_symbol *s) } } +static void widget_store(t_widget *x, t_symbol *s) +{ + if (s == &s_) + s = x->x_varname; + /* FIXME */ +} + +static void widget_restore(t_widget *x, t_symbol *s) +{ + if (s == &s_) + s = x->x_varname; + /* FIXME */ +} + static void widget_set(t_widget *x, t_symbol *s, int ac, t_atom *av) { t_symbol *prp; if (ac && av->a_type == A_SYMBOL && (prp = av->a_w.w_symbol)) { t_symbol *empty = 0; - x->x_update = WIDGET_RECONFIG; ac--; av++; if (*prp->s_name == '-') + { + x->x_update = WIDGET_PUSHVIS; empty = widget_addprops(x, x->x_options, 1, prp, ac, av); + } else if (*prp->s_name == '@') empty = widget_addprops(x, x->x_handlers, 1, prp, ac, av); else if (*prp->s_name == '#') @@ -595,8 +630,8 @@ static void widget_remove(t_widget *x, t_symbol *s) op = 0; if (op && props_remove(op, s)) { - x->x_update = WIDGET_REVIS; - widget_update(x); + if (op == x->x_options) x->x_update = WIDGET_REVIS; + widget_update(x, op); } else loud_warning((t_pd *)x, "%s %s has not been specified", props_getname(op), s->s_name); @@ -625,7 +660,9 @@ static void widget_tot(t_widget *x, t_symbol *s, int ac, t_atom *av) static void widget_refresh(t_widget *x) { x->x_update = WIDGET_REVIS; - widget_update(x); + widget_update(x, x->x_options); + widget_update(x, x->x_handlers); + widget_update(x, x->x_arguments); } static void widget__failure(t_widget *x, t_symbol *s, int ac, t_atom *av) @@ -682,13 +719,13 @@ static void widget__callback(t_widget *x, t_symbol *s, int ac, t_atom *av) else outlet_bang(((t_object *)x)->ob_outlet); } -/* FIXME this is a hack (see also widget_select) */ -/* FIXME why is being issued on button press? */ +/* see also widget_select() */ static void widget__inout(t_widget *x, t_floatarg f) { + int disable = (int)f && x->x_glist->gl_edit; if (x->x_disabled) { - if (!x->x_glist->gl_edit) + if (!disable) { if (!x->x_selected) { @@ -699,54 +736,54 @@ static void widget__inout(t_widget *x, t_floatarg f) x->x_disabled = 0; } } - else if ((int)f && x->x_glist->gl_edit) + else if (disable) { - char *mypathname = widget_getmypathname(x, x->x_glist)->s_name; - if (x->x_hasstate) - sys_vgui("%s config -state disabled\n", mypathname); + if (!x->x_selected) + { + char *mypathname = widget_getmypathname(x, x->x_glist)->s_name; + if (x->x_hasstate) + sys_vgui("%s config -state disabled\n", mypathname); + } x->x_disabled = 1; } } -static void widget__click(t_widget *x, t_floatarg fx, t_floatarg fy, - t_floatarg fb, t_floatarg fm) +static void widget__click(t_widget *x, t_symbol *s, int ac, t_atom *av) { + if (ac != 4) + { + loud_error((t_pd *)x, "bad arguments to the '%s' method", s->s_name); + return; + } if (x->x_glist->gl_havewindow) /* LATER calculate on-parent coords */ { - t_text *t = (t_text *)x; - t_atom at[4]; - fx += t->te_xpix; - fy += t->te_ypix; - SETFLOAT(&at[0], fx); - SETFLOAT(&at[1], fy); - SETFLOAT(&at[2], fb); - SETFLOAT(&at[3], fm); if (x->x_cvtarget->s_thing) /* LATER rethink */ - typedmess(x->x_cvtarget->s_thing, widgetps_mouse, 4, at); + typedmess(x->x_cvtarget->s_thing, widgetps_mouse, ac, av); else - typedmess((t_pd *)x->x_glist, widgetps_mouse, 4, at); - widget__inout(x, 1.); + typedmess((t_pd *)x->x_glist, widgetps_mouse, ac, av); + widget__inout(x, 2.); } } /* LATER think how to grab the mouse when dragging */ -static void widget__motion(t_widget *x, t_floatarg fx, t_floatarg fy) +static void widget__motion(t_widget *x, t_symbol *s, int ac, t_atom *av) { + if (ac != 3) + { + loud_error((t_pd *)x, "bad arguments to the '%s' method", s->s_name); + return; + } if (x->x_glist->gl_havewindow) /* LATER calculate on-parent coords */ { - t_text *t = (t_text *)x; - t_atom at[3]; - fx += t->te_xpix; - fy += t->te_ypix; - SETFLOAT(&at[0], fx); - SETFLOAT(&at[1], fy); - SETFLOAT(&at[2], 0); +#if 0 + post("motion %g %g", av[0].a_w.w_float, av[1].a_w.w_float); +#endif if (x->x_cvtarget->s_thing) /* LATER rethink */ - typedmess(x->x_cvtarget->s_thing, widgetps_motion, 3, at); + typedmess(x->x_cvtarget->s_thing, widgetps_motion, ac, av); else - typedmess((t_pd *)x->x_glist, widgetps_motion, 3, at); + typedmess((t_pd *)x->x_glist, widgetps_motion, ac, av); } } @@ -799,6 +836,8 @@ static void widget_debug(t_widget *x) post("type initializer (size %d):\n\"%s\"", sz, bp); bp = scriptlet_getcontents(x->x_iniscript, &sz); post("instance initializer (size %d):\n\"%s\"", sz, bp); + bp = masterwidget_getcontents(&sz); + post("setup definitions (size %d):\n\"%s\"", sz, bp); } #endif @@ -815,6 +854,8 @@ static void gui_unbind(t_pd *x, t_symbol *s) static void widget_free(t_widget *x) { + sys_vgui("::toxy::itemdestroy %s %s\n", + widget_getmypathname(x, x->x_glist)->s_name, x->x_varname->s_name); gui_unbind((t_pd *)x, x->x_cbtarget); gui_unbind((t_pd *)x, x->x_rptarget); props_freeall(x->x_options); @@ -862,28 +903,28 @@ static void *widget_new(t_symbol *s, int ac, t_atom *av) if (!(x->x_tkclass = widgettype_tkclass(x->x_typedef))) x->x_tkclass = x->x_type; + x->x_glist = canvas_getcurrent(); + sprintf(buf, ".x%x.c", (int)x->x_glist); + x->x_cvpathname = gensym(buf); + sprintf(buf, ".x%x", (int)x->x_glist); + x->x_cvtarget = gensym(buf); + sprintf(buf, "::toxy::v%x", (int)x); + x->x_varname = gensym(buf); + x->x_iniscript = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget, - x->x_name, widget_cvhook); + x->x_name, x->x_glist, widget_cvhook); x->x_optscript = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget, - x->x_name, widget_cvhook); + x->x_name, x->x_glist, widget_cvhook); x->x_auxscript = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget, - x->x_name, widget_cvhook); + x->x_name, x->x_glist, widget_cvhook); x->x_transient = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget, - x->x_name, widget_cvhook); + x->x_name, x->x_glist, widget_cvhook); x->x_options = props_new((t_pd *)x, "option", "-", 0, 0); x->x_handlers = props_new((t_pd *)x, "handler", "@", x->x_options, 0); x->x_arguments = props_new((t_pd *)x, "argument", "#", x->x_options, widget_propsresolver); - sprintf(buf, ".^.c.%s%x", x->x_name->s_name, (int)x); - x->x_glist = canvas_getcurrent(); - sprintf(buf, ".x%x.c", (int)x->x_glist); - x->x_cvpathname = gensym(buf); - sprintf(buf, ".x%x", (int)x->x_glist); - x->x_cvtarget = gensym(buf); - sprintf(buf, "::toxy::v%x", (int)x); - x->x_varname = gensym(buf); outlet_new((t_object *)x, &s_anything); /* LATER consider estimating these, based on widget class and options */ x->x_width = 50; @@ -894,7 +935,7 @@ static void *widget_new(t_symbol *s, int ac, t_atom *av) x->x_transclock = clock_new(x, (t_method)widget_transtick); x->x_background = 0; x->x_hasstate = 0; - x->x_update = WIDGET_NOUPDATE; + x->x_update = WIDGET_NOVIS; x->x_disabled = 0; x->x_vised = 0; widget_attach(x); @@ -1153,6 +1194,8 @@ void widget_setup(void) widgetps_atbang = gensym("@bang"); widgetps_atfloat = gensym("@float"); widgetps_atsymbol = gensym("@symbol"); + widgetps_atstore = gensym("@store"); + widgetps_atrestore = gensym("@restore"); widgettype_setup(); widget_class = class_new(gensym("widget"), (t_newmethod)widget_new, @@ -1165,6 +1208,10 @@ void widget_setup(void) class_addfloat(widget_class, widget_float); class_addsymbol(widget_class, widget_symbol); class_addanything(widget_class, widget_anything); + class_addmethod(widget_class, (t_method)widget_store, + gensym("store"), A_DEFSYMBOL, 0); + class_addmethod(widget_class, (t_method)widget_restore, + gensym("restore"), A_DEFSYMBOL, 0); class_addmethod(widget_class, (t_method)widget_set, gensym("set"), A_GIMME, 0); class_addmethod(widget_class, (t_method)widget_remove, @@ -1187,9 +1234,9 @@ void widget_setup(void) class_addmethod(widget_class, (t_method)widget__inout, gensym("_inout"), A_FLOAT, 0); class_addmethod(widget_class, (t_method)widget__click, - gensym("_click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); + gensym("_click"), A_GIMME, 0); class_addmethod(widget_class, (t_method)widget__motion, - gensym("_motion"), A_FLOAT, A_FLOAT, 0); + gensym("_motion"), A_GIMME, 0); #ifdef WIDGET_DEBUG class_addmethod(widget_class, (t_method)widget_debug, gensym("debug"), 0); diff --git a/toxy/widgettype.c b/toxy/widgettype.c index 5a5684f..3e04824 100644 --- a/toxy/widgettype.c +++ b/toxy/widgettype.c @@ -11,6 +11,10 @@ #include "toxy/scriptlet.h" #include "widgettype.h" +static char masterwidget_builtin[] = +#include "default.wiq" +; + #define WIDGETTYPE_VERBOSE //#define WIDGETTYPE_DEBUG @@ -42,7 +46,7 @@ static t_class *masterwidget_class; static t_masterwidget *masterwidget = 0; -static t_canvas *widgettype_cvhook(t_pd *z) +static t_canvas *widgettype_cvhook(t_pd *caller) { return (0); } @@ -63,22 +67,22 @@ static t_widgettype *widgettype_new(t_masterwidget *mw, wt->wt_handlers = props_new(0, "handler", "@", wt->wt_options, 0); wt->wt_arguments = props_new(0, "argument", "#", wt->wt_options, 0); wt->wt_iniscript = scriptlet_new((t_pd *)wt, mw->mw_target, mw->mw_target, - 0, widgettype_cvhook); + 0, 0, widgettype_cvhook); dict_bind(mw->mw_typemap, (t_pd *)wt, wt->wt_typekey); return (wt); } -static t_canvas *masterwidget_cvhook(t_pd *z) +static t_canvas *masterwidget_cvhook(t_pd *caller) { return (0); } -static t_scriptlet *masterwidget_cmnthook(t_pd *z, char *rc, +static t_scriptlet *masterwidget_cmnthook(t_pd *caller, char *rc, char sel, char *buf) { t_masterwidget *mw = masterwidget; if (!*buf) - return (0); + return (SCRIPTLET_UNLOCK); if (sel == '>') { t_symbol *typekey; @@ -90,23 +94,31 @@ static t_scriptlet *masterwidget_cmnthook(t_pd *z, char *rc, cls = buf; typekey = dict_key(mw->mw_typemap, buf); typeval = (t_widgettype *)dict_value(mw->mw_typemap, typekey); - if (z == (t_pd *)mw) - { /* default.wid */ - if (typeval) + if (caller == (t_pd *)mw) + { /* default.wid or built-in defaults */ + if (mw->mw_defaulttype) + { /* no default type in default.wid, extracting built-in one */ + if (typeval != mw->mw_defaulttype) + return (SCRIPTLET_LOCK); + } + else { - /* LATER rethink */ - loud_warning((t_pd *)mw, "redefinition of '%s'\ + if (typeval) + { + /* LATER rethink */ + loud_warning((t_pd *)mw, "redefinition of '%s'\ in \"%s.wid\" file, ignored", buf, rc); - return (0); + return (SCRIPTLET_LOCK); + } } } else { /* .wid */ - if (z != (t_pd *)typeval) + if (caller != (t_pd *)typeval) { loud_warning((t_pd *)mw, "alien definition of '%s'\ in \"%s.wid\" file, ignored", buf, rc); - return (0); + return (SCRIPTLET_LOCK); } } if (pkg) @@ -150,7 +162,7 @@ static t_scriptlet *masterwidget_cmnthook(t_pd *z, char *rc, } } } - return (0); + return (SCRIPTLET_UNLOCK); } t_widgettype *widgettype_get(t_symbol *s) @@ -170,13 +182,31 @@ t_widgettype *widgettype_get(t_symbol *s) } if (masterwidget->mw_parsedtype) { - if (scriptlet_rcload(wt->wt_iniscript, s->s_name, ".wid", - masterwidget_cmnthook) == SCRIPTLET_OK) + t_scriptlet *mwsp = + scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target, + masterwidget->mw_target, 0, 0, 0); + if (scriptlet_rcload(mwsp, (t_pd *)wt, + s->s_name, ".wid", 0, masterwidget_cmnthook) + == SCRIPTLET_OK) { #ifdef WIDGETTYPE_VERBOSE post("using %s's initializer", s->s_name); #endif + if (!scriptlet_isempty(mwsp)) + { + t_scriptlet *sp = + scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target, + masterwidget->mw_target, 0, 0, 0); + if (scriptlet_evaluate(mwsp, sp, 0, 0, 0, 0)) + { + scriptlet_push(sp); + scriptlet_append(masterwidget->mw_setupscript, mwsp); + } + else bug("widgettype_get"); + scriptlet_free(sp); + } } + scriptlet_free(mwsp); } return (wt); } @@ -218,13 +248,6 @@ int widgettype_evaluate(t_widgettype *wt, t_scriptlet *outsp, visedonly, ac, av, argprops)); } -int masterwidget_evaluate(t_scriptlet *outsp, int visedonly, - int ac, t_atom *av, t_props *argprops) -{ - return (scriptlet_evaluate(masterwidget->mw_defaulttype->wt_iniscript, - outsp, visedonly, ac, av, argprops)); -} - void widgettype_setup(void) { static int done = 0; @@ -238,9 +261,21 @@ void widgettype_setup(void) } } +int masterwidget_evaluate(t_scriptlet *outsp, int visedonly, + int ac, t_atom *av, t_props *argprops) +{ + return (scriptlet_evaluate(masterwidget->mw_defaulttype->wt_iniscript, + outsp, visedonly, ac, av, argprops)); +} + +char *masterwidget_getcontents(int *szp) +{ + return (scriptlet_getcontents(masterwidget->mw_setupscript, szp)); +} + void masterwidget_initialize(void) { - t_scriptlet *sp; + int rcresult; t_symbol *typekey; t_widgettype *typeval; char buf[MAXPDSTRING]; @@ -253,14 +288,17 @@ void masterwidget_initialize(void) masterwidget->mw_typemap = dict_new(0); - sp = masterwidget->mw_setupscript = + masterwidget->mw_setupscript = scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target, - masterwidget->mw_target, 0, 0); - masterwidget->mw_parsedtype = 0; + masterwidget->mw_target, 0, 0, 0); masterwidget->mw_bb = binbuf_new(); + masterwidget->mw_parsedtype = 0; + masterwidget->mw_defaulttype = 0; - if (scriptlet_rcload(sp, "default", ".wid", - masterwidget_cmnthook) == SCRIPTLET_OK) + rcresult = + scriptlet_rcload(masterwidget->mw_setupscript, 0, "default", ".wid", + masterwidget_builtin, masterwidget_cmnthook); + if (rcresult == SCRIPTLET_OK) { #ifdef WIDGETTYPE_VERBOSE post("using file 'default.wid'"); @@ -268,33 +306,42 @@ void masterwidget_initialize(void) } else { - loud_warning((t_pd *)masterwidget, "missing file 'default.wid'"); - - /* no setup scriptlet, LATER use built-in default */ -#if 0 - scriptlet_reset(sp); - scriptlet_addstring(sp, ... -#endif + loud_warning((t_pd *)masterwidget, + "no file 'default.wid'... using built-in defaults"); } typekey = dict_key(masterwidget->mw_typemap, "default"); - if (typeval = (t_widgettype *)dict_value(masterwidget->mw_typemap, typekey)) + if ((typeval = (t_widgettype *)dict_value(masterwidget->mw_typemap, typekey)) + && !scriptlet_isempty(masterwidget->mw_setupscript)) + { masterwidget->mw_defaulttype = typeval; - else + rcresult = SCRIPTLET_OK; + } + else if (rcresult == SCRIPTLET_OK) { - /* no master initializer, LATER use built-in default */ + /* LATER think about adding only missing part to existing local defs */ + loud_warning((t_pd *)masterwidget, "%s missing in file 'default.wid'", + (typeval ? "setup definitions" : "master initializer")); masterwidget->mw_defaulttype = widgettype_new(masterwidget, "default", 0, 0); - sp = masterwidget->mw_defaulttype->wt_iniscript; -#if 0 - scriptlet_reset(sp); - scriptlet_addstring(sp, ... -#endif + scriptlet_reset(masterwidget->mw_setupscript); + rcresult = + scriptlet_rcparse(masterwidget->mw_setupscript, 0, "default", + masterwidget_builtin, masterwidget_cmnthook); } - sp = scriptlet_new((t_pd *)masterwidget, - masterwidget->mw_target, masterwidget->mw_target, 0, 0); - if (scriptlet_evaluate(masterwidget->mw_setupscript, sp, 0, 0, 0, 0)) - scriptlet_push(sp); else - bug("masterwidget_initialize"); - scriptlet_free(sp); + { + bug("masterwidget_initialize 1"); + rcresult = SCRIPTLET_BADFILE; + } + if (rcresult == SCRIPTLET_OK) + { + t_scriptlet *sp = + scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target, + masterwidget->mw_target, 0, 0, 0); + if (scriptlet_evaluate(masterwidget->mw_setupscript, sp, 0, 0, 0, 0)) + scriptlet_push(sp); + else + bug("masterwidget_initialize 2"); + scriptlet_free(sp); + } } diff --git a/toxy/widgettype.h b/toxy/widgettype.h index 55c8e9d..d0df8c6 100644 --- a/toxy/widgettype.h +++ b/toxy/widgettype.h @@ -21,10 +21,11 @@ char *widgettype_propname(t_symbol *s); char *widgettype_getcontents(t_widgettype *wt, int *szp); int widgettype_evaluate(t_widgettype *wt, t_scriptlet *outsp, int visedonly, int ac, t_atom *av, t_props *argprops); +void widgettype_setup(void); + +char *masterwidget_getcontents(int *szp); int masterwidget_evaluate(t_scriptlet *outsp, int visedonly, int ac, t_atom *av, t_props *argprops); void masterwidget_initialize(void); -void widgettype_setup(void); - #endif -- cgit v1.2.1