aboutsummaryrefslogtreecommitdiff
path: root/shared/common/patchvalue.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared/common/patchvalue.c')
-rw-r--r--shared/common/patchvalue.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/shared/common/patchvalue.c b/shared/common/patchvalue.c
new file mode 100644
index 0000000..b75b565
--- /dev/null
+++ b/shared/common/patchvalue.c
@@ -0,0 +1,265 @@
+/* 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 <stdio.h>
+#include <string.h>
+#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);
+}