/* Copyright (c) 2005 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 #include "m_pd.h" #include "g_canvas.h" #include "patchvalue.h" #ifdef KRZYSZCZ # include "loud.h" # define PATCHVALUE_DEBUG #else # define loudbug_bug(msg) fprintf(stderr, "BUG: %s\n", msg), bug(msg) #endif typedef struct _patchstorage { t_glist *ps_glist; t_patchvalue *ps_values; struct _patchstorage *ps_next; } t_patchstorage; typedef struct _patchboard { t_pd pb_pd; t_symbol *pb_category; t_patchstorage *pb_contents; } t_patchboard; static t_class *patchboard_class = 0; /* assuming there is no 'name' in the storage */ static t_patchvalue *patchstorage_addvalue( t_patchstorage *ps, t_patchvalue *prv, t_class *cls, t_symbol *name) { t_patchvalue *pv = (t_patchvalue *)pd_new(cls); pv->pv_name = name; pv->pv_refcount = 0; if (prv) { pv->pv_next = prv->pv_next; prv->pv_next = pv; } else { pv->pv_next = ps->ps_values; ps->ps_values = pv; } return (pv); } /* assuming there is no 'glist' on the board */ static t_patchstorage *patchboard_addstorage( t_patchboard *pb, t_patchstorage *prv, t_glist *glist) { t_patchstorage *ps = getbytes(sizeof(*ps)); ps->ps_glist = glist; ps->ps_values = 0; if (prv) { ps->ps_next = prv->ps_next; prv->ps_next = ps; } else { ps->ps_next = pb->pb_contents; pb->pb_contents = ps; } return (ps); } /* not used (LATER find a gc scheme) */ static void patchstorage_removevalue( t_patchstorage *ps, t_patchvalue *prv, t_patchvalue *pv, int force) { if (force || pv->pv_refcount < 1) { if (prv) prv->pv_next = pv->pv_next; else ps->ps_values = pv->pv_next; pd_free((t_pd *)pv); } } /* not used (LATER find a gc scheme) */ static void patchboard_removestorage( t_patchboard *pb, t_patchstorage *prv, t_patchstorage *ps, int force) { if (prv) prv->ps_next = ps->ps_next; else pb->pb_contents = ps->ps_next; if (force) { t_patchvalue *pv, *pvnext = ps->ps_values; while (pv = pvnext) { pvnext = pv->pv_next; pd_free((t_pd *)pv); } } else if (ps->ps_values) return; freebytes(ps, sizeof(*ps)); } static t_patchvalue *patchstorage_findvalue( t_patchstorage *ps, t_symbol *name) { t_patchvalue *pv; for (pv = ps->ps_values; pv; pv = pv->pv_next) if (pv->pv_name == name) break; return (pv); } static t_patchstorage *patchboard_findstorage( t_patchboard *pb, t_glist *glist) { t_patchstorage *ps; for (ps = pb->pb_contents; ps; ps = ps->ps_next) if (ps->ps_glist == glist) break; return (ps); } static t_patchboard *patchboard_find(t_symbol *category) { if (!patchboard_class) patchboard_class = patchvalue_classnew(gensym("_patchboard"), sizeof(t_patchboard)); return ((t_patchboard *)pd_findbyclass(category, patchboard_class)); } static t_patchboard *patchboard_use(t_symbol *category) { if (!patchboard_class) patchboard_class = patchvalue_classnew(gensym("_patchboard"), sizeof(t_patchboard)); if (category && *category->s_name == '#') { t_patchboard *pb; if (!(pb = (t_patchboard *)pd_findbyclass(category, patchboard_class))) { pb = (t_patchboard *)pd_new(patchboard_class); pb->pb_category = category; pd_bind((t_pd *)pb, category); /* never unbound */ pb->pb_contents = 0; } return (pb); } else { loudbug_bug("patchboard_use"); return (0); } } static t_patchstorage *patchstorage_use(t_symbol *category, t_glist *glist) { t_patchboard *pb; if (pb = patchboard_use(category)) { t_patchstorage *ps; if (!(ps = patchboard_findstorage(pb, glist))) ps = patchboard_addstorage(pb, 0, glist); return (ps); } else return (0); } /* The class might have been created by another dll... This is public, because apart from the "_patchboard" class above, it is called for the "_raftentry" class too. LATER rethink. */ t_class *patchvalue_classnew(t_symbol *cname, size_t size) { t_class *cls; t_symbol *bindsym; char buf[MAXPDSTRING]; sprintf(buf, "#%s", cname->s_name); bindsym = gensym(buf); if (bindsym->s_thing) { t_pd *pd = bindsym->s_thing; char *name = class_getname(*pd); if (strcmp(name, cname->s_name)) { /* FIXME handle this properly... */ loudbug_bug("patchvalue_classnew"); } else return (*pd); } cls = class_new(cname, 0, 0, size, CLASS_PD | CLASS_NOINLET, 0); pd_bind(pd_new(cls), bindsym); /* never unbound */ return (cls); } t_patchvalue *patchvalue_use(t_symbol *category, t_glist *glist, t_class *cls, t_symbol *name) { t_patchstorage *ps; if (ps = patchstorage_use(category, glist)) { t_patchvalue *pv; if (pv = patchstorage_findvalue(ps, name)) { if (*(t_pd *)pv != cls) { loudbug_bug("patchvalue_use"); return (0); } } else pv = patchstorage_addvalue(ps, 0, cls, name); return (pv); } else return (0); } t_patchvalue *patchvalue_get(t_symbol *category, t_glist *glist, t_class *cls, t_symbol *name) { t_patchboard *pb; t_patchstorage *ps; t_patchvalue *pv; if ((pb = patchboard_find(category)) && (ps = patchboard_findstorage(pb, glist)) && (pv = patchstorage_findvalue(ps, name))) { if (*(t_pd *)pv == cls) return (pv); else loudbug_bug("patchvalue_get"); } return (0); } t_patchvalue *patchvalue_resolve(t_symbol *category, t_glist *glist, t_class *cls, t_symbol *name) { t_patchboard *pb; if (pb = patchboard_find(category)) { t_patchstorage *ps; t_patchvalue *pv; while (glist) { if ((ps = patchboard_findstorage(pb, glist)) && (pv = patchstorage_findvalue(ps, name))) { if (*(t_pd *)pv == cls) return (pv); else loudbug_bug("patchvalue_resolve"); } else if (canvas_isabstraction(glist)) break; else glist = glist->gl_owner; } } return (0); }