diff options
Diffstat (limited to 'shared/toxy/plusbob.c')
-rw-r--r-- | shared/toxy/plusbob.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/shared/toxy/plusbob.c b/shared/toxy/plusbob.c new file mode 100644 index 0000000..fb587cc --- /dev/null +++ b/shared/toxy/plusbob.c @@ -0,0 +1,371 @@ +/* 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 <string.h> +#include "m_pd.h" +#include "common/loud.h" +#include "plusbob.h" + +//#define PLUSBOB_DEBUG + +/* LATER let there be a choice of using either fake-symbols, or gpointers. + The gpointer layout would be such: gs_un points to a plusbob-like + structure (without the bob_tag field), a unique integer code has to be + reserved for gs_which, the fields gp_un and gp_valid are ignored. + Using bob_refcount instead of gs_refcount is likely to simplify code. */ + +/* Currently, objects of all +bob types are tagged with the same name: */ +static char plustag_name[] = "+bob"; + +static void plustag_init(t_symbol *tag) +{ + tag->s_name = plustag_name; + tag->s_thing = 0; + tag->s_next = 0; +} + +/* silent if caller is empty */ +int plustag_isvalid(t_symbol *tag, t_pd *caller) +{ + if (tag->s_name == plustag_name) + return (1); + else if (caller) + { + if (strcmp(tag->s_name, plustag_name)) + loud_error((caller == PLUSBOB_OWNER ? 0 : caller), + "does not understand '%s' (check object connections)", tag->s_name); + else + loud_error((caller == PLUSBOB_OWNER ? 0 : caller), "confused..."); + } + return (0); +} + +/* +bob is an object tossed around, a bobbing object. Currently, this is + a wrapping for Tcl_Interp, Tcl_Obj, or a tcl variable, but the +bob + interface is abstract enough to be suitable for other types of objects. + The t_plusbob is kind of a virtual base. */ + +struct _plustype +{ + t_plustype *tp_base; /* empty, if directly derived from t_plusbob */ + t_symbol *tp_name; + size_t tp_size; + /* constructor is to be called explicitly, from derived constructors, + or from a public wrapper. */ + t_plustypefn tp_deletefn; /* destructor */ + t_plustypefn tp_preservefn; + t_plustypefn tp_releasefn; + t_plustypefn tp_attachfn; +}; + +static t_plustype *plustype_default = 0; + +t_plustype *plustype_new(t_plustype *base, t_symbol *name, size_t sz, + t_plustypefn deletefn, + t_plustypefn preservefn, t_plustypefn releasefn, + t_plustypefn attachfn) +{ + t_plustype *tp = getbytes(sizeof(*tp)); + tp->tp_base = base; + tp->tp_name = name; + tp->tp_size = sz; + tp->tp_deletefn = deletefn; + tp->tp_preservefn = preservefn; + tp->tp_releasefn = releasefn; + tp->tp_attachfn = attachfn; + return (tp); +} + +static void plusbob_doattach(t_plusbob *bob, t_plusbob *parent) +{ + if (bob->bob_parent = parent) + { + /* become the youngest child: */ + bob->bob_prev = 0; + if (bob->bob_next = parent->bob_children) + { + if (parent->bob_children->bob_prev) + bug("plusbob_doattach 1"); + parent->bob_children->bob_prev = bob; + } + parent->bob_children = bob; + } + else bug("plusbob_doattach 2"); +} + +static void plusbob_dodetach(t_plusbob *bob) +{ + if (bob->bob_parent) + { + if (bob->bob_prev) + { + if (bob == bob->bob_parent->bob_children) + bug("plusbob_dodetach 1"); + bob->bob_prev->bob_next = bob->bob_next; + } + if (bob->bob_next) + bob->bob_next->bob_prev = bob->bob_prev; + if (bob == bob->bob_parent->bob_children) + bob->bob_parent->bob_children = bob->bob_next; + } + else bug("plusbob_dodetach 2"); +} + +/* To be called from derived constructors. + Preserving is caller's responsibility. */ +t_plusbob *plusbob_create(t_plustype *tp, t_plusbob *parent) +{ + t_plusbob *bob; + if (!tp) + { + if (!plustype_default) + plustype_default = plustype_new(0, 0, sizeof(t_plusbob), + 0, 0, 0, 0); + tp = plustype_default; + } + if (bob = getbytes(tp->tp_size)) + { + plustag_init(&bob->bob_tag); + bob->bob_type = tp; + while (tp->tp_base) tp = tp->tp_base; + bob->bob_root = tp; + bob->bob_owner = 0; + bob->bob_refcount = 0; + bob->bob_dorefcount = 1; + bob->bob_children = 0; + if (parent) + plusbob_doattach(bob, parent); + else + bob->bob_parent = 0; + } + return (bob); +} + +/* Should never be called, but from plusbob_release(). + Calling from a derived destructor is illegal. */ +static void plusbob_free(t_plusbob *bob) +{ + t_plustype *tp; + if (bob->bob_parent) + plusbob_dodetach(bob); + for (tp = bob->bob_type; tp; tp = tp->tp_base) + if (tp->tp_deletefn) (*tp->tp_deletefn)(bob); + freebytes(bob, (bob->bob_type ? bob->bob_type->tp_size : sizeof(*bob))); +} + +void plusbob_preserve(t_plusbob *bob) +{ + if (bob->bob_dorefcount) + { + t_plustype *tp; + for (tp = bob->bob_type; tp; tp = tp->tp_base) + if (tp->tp_preservefn) (*tp->tp_preservefn)(bob); + bob->bob_refcount++; + } +} + +void plusbob_release(t_plusbob *bob) +{ + if (bob->bob_dorefcount) + { + t_plustype *tp; + for (tp = bob->bob_type; tp; tp = tp->tp_base) + if (tp->tp_releasefn) (*tp->tp_releasefn)(bob); + if (--bob->bob_refcount <= 0) + { + if (bob->bob_refcount == 0) + plusbob_free(bob); + else + bug("plusbob_release"); + } + } +} + +t_plusbob *plusbob_getparent(t_plusbob *bob) +{ + return (bob->bob_parent); +} + +/* To be called for redirection only. Bobs created as orphans are a special + case, and cannot be attached later on. Likewise, changing non-orphan bobs + to orphans is illegal. */ +void plusbob_attach(t_plusbob *bob, t_plusbob *newparent) +{ + if (bob->bob_parent && newparent) + { + t_plustype *tp; + plusbob_dodetach(bob); + plusbob_doattach(bob, newparent); + for (tp = bob->bob_type; tp; tp = tp->tp_base) + if (tp->tp_attachfn) (*tp->tp_attachfn)(bob); + } + else if (newparent) + bug("plusbob_attach 1"); + else + bug("plusbob_attach 2"); +} + +t_plusbob *plusbob_getnext(t_plusbob *bob) +{ + return (bob->bob_next); +} + +t_plusbob *plusbob_getchildren(t_plusbob *bob) +{ + return (bob->bob_children); +} + +/* Redirect all bobs to a replacement parent. + Assuming replacement exists. */ +void plusbob_detachchildren(t_plusbob *bob, t_plusbob *newparent) +{ + while (bob->bob_children) + plusbob_attach(bob->bob_children, newparent); +} + +void plusbob_detachownedchildren(t_plusbob *bob, t_plusbob *newparent, + t_pd *owner) +{ + t_plusbob *child = bob->bob_children, *next; + while (child) + { + next = child->bob_next; + if (child->bob_owner == owner) + plusbob_attach(child, newparent); + child = next; + } +} + +void plusbob_setowner(t_plusbob *bob, t_pd *owner) +{ + bob->bob_owner = owner; +} + +t_pd *plusbob_getowner(t_plusbob *bob) +{ + return (bob->bob_owner); +} + +void outlet_plusbob(t_outlet *o, t_plusbob *bob) +{ + outlet_symbol(o, (t_symbol *)bob); +} + +/* silent if caller is empty */ +int plustag_validtype(t_symbol *tag, t_symbol *tname, t_pd *caller) +{ + if (tag->s_name == plustag_name) + { + if (((t_plusbob *)tag)->bob_type->tp_name == tname) + return (1); + else if (caller) + { + t_symbol *s = ((t_plusbob *)tag)->bob_type->tp_name; + loud_error((caller == PLUSBOB_OWNER ? + ((t_plusbob *)tag)->bob_owner : caller), + "invalid type '%s' ('%s' expected)", + (s ? s->s_name : "<unknown>"), + (tname ? tname->s_name : "<unknown>")); + } + } + else if (plustag_isvalid(tag, caller)) /* print the error there */ + bug("plustag_validtype"); + return (0); +} + +/* silent if caller is empty */ +int plustag_validroot(t_symbol *tag, t_symbol *rname, t_pd *caller) +{ + if (tag->s_name == plustag_name) + { + if (((t_plusbob *)tag)->bob_root->tp_name == rname) + return (1); + else if (caller) + { + t_symbol *s = ((t_plusbob *)tag)->bob_root->tp_name; + loud_error((caller == PLUSBOB_OWNER ? + ((t_plusbob *)tag)->bob_owner : caller), + "invalid base type '%s' ('%s' expected)", + (s ? s->s_name : "<unknown>"), + (rname ? rname->s_name : "<unknown>")); + } + } + else if (plustag_isvalid(tag, caller)) /* print the error there */ + bug("plustag_validroot"); + return (0); +} + +t_symbol *plustag_typename(t_symbol *tag, int validate, t_pd *caller) +{ + if (!validate || tag->s_name == plustag_name) + return (((t_plusbob *)tag)->bob_type->tp_name); + else if (plustag_isvalid(tag, caller)) /* print the error there */ + bug("plustag_typename"); + return (0); +} + +t_symbol *plustag_rootname(t_symbol *tag, int validate, t_pd *caller) +{ + if (!validate || tag->s_name == plustag_name) + return (((t_plusbob *)tag)->bob_root->tp_name); + else if (plustag_isvalid(tag, caller)) /* print the error there */ + bug("plustag_rootname"); + return (0); +} + +/* Plusenv (aka +env) is the base for an `environment' +bob. Environment + encapsulates data common for a collection of +bobs. This is the standard + way of grouping +bobs, according to a parent/children relationship. */ + +static t_plustype *plusenv_type = 0; +static t_plusbob *plusenv_parent = 0; /* the parent of all environments */ + +/* To be called from derived constructors (or, LATER, plusenv's provider). */ +t_plusenv *plusenv_create(t_plustype *tp, t_plusbob *parent, t_symbol *id) +{ + t_plusenv *env = 0; + if (env = (t_plusenv *)plusbob_create(tp, parent)) + { + if (!id) + /* LATER design a public interface for bob_dorefcount */ + ((t_plusbob *)env)->bob_dorefcount = 0; + env->env_id = id; /* LATER rethink */ + } + return (env); +} + +t_plusenv *plusenv_find(t_symbol *id, t_plusenv *defenv) +{ + if (plusenv_parent && id) + { + t_plusbob *bob; + for (bob = plusenv_parent->bob_children; bob; bob = bob->bob_next) + if (((t_plusenv *)bob)->env_id == id) + break; + return ((t_plusenv *)bob); + } + else return (defenv); +} + +t_symbol *plusenv_getid(t_plusenv *env) +{ + return (env->env_id); +} + +/* Type ignored, LATER rethink. */ +t_plusbob *plusenv_getparent(t_plustype *tp) +{ + if (!plusenv_parent) plusenv_parent = plusbob_create(0, 0); + return (plusenv_parent); +} + +t_plustype *plusenv_setup(void) +{ + if (!plusenv_type) + { + plusenv_type = plustype_new(0, gensym("+env"), + sizeof(t_plusenv), 0, 0, 0, 0); + } + return (plusenv_type); +} |