aboutsummaryrefslogtreecommitdiff
path: root/cyclone/hammer/substitute.c
diff options
context:
space:
mode:
Diffstat (limited to 'cyclone/hammer/substitute.c')
-rw-r--r--cyclone/hammer/substitute.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/cyclone/hammer/substitute.c b/cyclone/hammer/substitute.c
new file mode 100644
index 0000000..48a9b9d
--- /dev/null
+++ b/cyclone/hammer/substitute.c
@@ -0,0 +1,340 @@
+/* Copyright (c) 2002-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/grow.h"
+
+#define SUBSTITUTE_INISIZE 32 /* LATER rethink */
+#define SUBSTITUTE_MAXSIZE 256
+
+typedef struct _substitute
+{
+ t_object x_ob;
+ t_pd *x_proxy;
+ t_atom x_match;
+ t_atom x_repl;
+ int x_size; /* as allocated */
+ t_atom *x_message;
+ t_atom x_messini[SUBSTITUTE_INISIZE];
+ int x_entered;
+ t_atom x_auxmatch;
+ t_atom x_auxrepl;
+ t_outlet *x_passout;
+} t_substitute;
+
+typedef struct _substitute_proxy
+{
+ t_object p_ob;
+ t_atom *p_match; /* pointing to parent's (aux)match */
+ t_atom *p_repl;
+} t_substitute_proxy;
+
+static t_class *substitute_class;
+static t_class *substitute_proxy_class;
+
+/* LATER rethink */
+static void substitute_dooutput(t_substitute *x,
+ t_symbol *s, int ac, t_atom *av, int pass)
+{
+ t_outlet *out = (pass ? x->x_passout : ((t_object *)x)->ob_outlet);
+ if (s == &s_float)
+ {
+ if (ac > 1)
+ outlet_list(out, &s_list, ac, av);
+ else
+ outlet_float(out, av->a_w.w_float);
+ }
+ else if (s == &s_bang && !ac) /* CHECKED */
+ outlet_bang(out);
+ else if (s == &s_symbol && ac == 1 && av->a_type == A_SYMBOL)
+ outlet_symbol(out, av->a_w.w_symbol);
+ else if (s)
+ outlet_anything(out, s, ac, av);
+ else if (ac)
+ outlet_list(out, &s_list, ac, av);
+}
+
+static int substitute_check(t_substitute *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_repl.a_type == A_NULL)
+ return (-2);
+ /* see substitute_proxy_validate() for possible types and values */
+ if (x->x_match.a_type == A_FLOAT)
+ {
+ t_float f = x->x_match.a_w.w_float;
+ int i;
+ for (i = 0; i < ac; i++, av++)
+ if (av->a_type == A_FLOAT && av->a_w.w_float == f)
+ return (i);
+ }
+ else if (x->x_match.a_type == A_SYMBOL)
+ {
+ /* match symbol is validated -- never null */
+ t_symbol *match = x->x_match.a_w.w_symbol;
+ int i;
+ if (s == match)
+ return (-1);
+ for (i = 0; i < ac; i++, av++)
+ if (av->a_type == A_SYMBOL && av->a_w.w_symbol == match)
+ return (i);
+ }
+ return (-2);
+}
+
+static void substitute_doit(t_substitute *x,
+ t_symbol *s, int ac, t_atom *av, int startndx)
+{
+ int cnt = ac - startndx;
+ if (cnt > 0)
+ {
+ t_atom *ap = av + startndx;
+ if (x->x_match.a_type == A_FLOAT)
+ {
+ t_float f = x->x_match.a_w.w_float;
+ while (cnt--)
+ {
+ if (ap->a_type == A_FLOAT && ap->a_w.w_float == f)
+ *ap = x->x_repl;
+ ap++;
+ }
+ }
+ else if (x->x_match.a_type == A_SYMBOL)
+ {
+ t_symbol *match = x->x_match.a_w.w_symbol;
+ while (cnt--)
+ {
+ if (ap->a_type == A_SYMBOL && ap->a_w.w_symbol == match)
+ *ap = x->x_repl;
+ ap++;
+ }
+ }
+ }
+ substitute_dooutput(x, s, ac, av, 0);
+}
+
+static void substitute_anything(t_substitute *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ int matchndx = substitute_check(x, s, ac, av);
+ if (matchndx < -1)
+ substitute_dooutput(x, s, ac, av, 1);
+ else
+ {
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ int ntotal = ac;
+ t_atom *buf;
+ t_substitute_proxy *proxy = (t_substitute_proxy *)x->x_proxy;
+ x->x_entered = 1;
+ proxy->p_match = &x->x_auxmatch;
+ proxy->p_repl = &x->x_auxrepl;
+ if (s == &s_) s = 0;
+ if (matchndx == -1)
+ {
+ if (x->x_repl.a_type == A_FLOAT)
+ {
+ ntotal++;
+ if (ac) s = &s_list;
+ else s = &s_float;
+ }
+ else if (x->x_repl.a_type == A_SYMBOL)
+ {
+ s = x->x_repl.a_w.w_symbol;
+ matchndx = 0;
+ }
+ }
+ else if (matchndx == 0
+ && (!s || s == &s_list || s == &s_float)
+ && av->a_type == A_FLOAT
+ && x->x_repl.a_type == A_SYMBOL)
+ {
+ s = x->x_repl.a_w.w_symbol;
+ ac--;
+ av++;
+ ntotal = ac;
+ }
+ if (prealloc && ac > x->x_size)
+ {
+ if (ntotal > SUBSTITUTE_MAXSIZE)
+ prealloc = 0;
+ else
+ x->x_message = grow_nodata(&ntotal, &x->x_size, x->x_message,
+ SUBSTITUTE_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ }
+ if (prealloc) buf = x->x_message;
+ else
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ buf = getbytes(ntotal * sizeof(*buf));
+ if (buf)
+ {
+ int ncopy = ntotal;
+ t_atom *bp = buf;
+ if (matchndx == -1)
+ {
+ SETFLOAT(bp++, x->x_repl.a_w.w_float);
+ ncopy--;
+ }
+ if (ncopy)
+ memcpy(bp, av, ncopy * sizeof(*buf));
+ substitute_doit(x, s, ntotal, buf, matchndx);
+ if (buf != x->x_message)
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+ if (!reentered)
+ {
+ x->x_entered = 0;
+ if (x->x_auxmatch.a_type != A_NULL)
+ {
+ x->x_match = x->x_auxmatch;
+ x->x_auxmatch.a_type = A_NULL;
+ }
+ if (x->x_auxrepl.a_type != A_NULL)
+ {
+ x->x_repl = x->x_auxrepl;
+ x->x_auxrepl.a_type = A_NULL;
+ }
+ proxy->p_match = &x->x_match;
+ proxy->p_repl = &x->x_repl;
+ }
+ }
+}
+
+static void substitute_bang(t_substitute *x)
+{
+ substitute_anything(x, &s_bang, 0, 0);
+}
+
+static void substitute_float(t_substitute *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ substitute_anything(x, 0, 1, &at);
+}
+
+/* CHECKED (but LATER rethink) */
+static void substitute_symbol(t_substitute *x, t_symbol *s)
+{
+ t_atom at;
+ SETSYMBOL(&at, s);
+ substitute_anything(x, &s_symbol, 1, &at);
+}
+
+/* LATER gpointer */
+
+static void substitute_list(t_substitute *x, t_symbol *s, int ac, t_atom *av)
+{
+ substitute_anything(x, 0, ac, av);
+}
+
+static int substitute_atomvalidate(t_atom *ap)
+{
+ return (ap->a_type == A_FLOAT
+ || (ap->a_type == A_SYMBOL
+ && ap->a_w.w_symbol && ap->a_w.w_symbol != &s_));
+}
+
+/* CHECKED: 'set' is ignored, single '<atom>' does not modify a replacement */
+static void substitute_proxy_anything(t_substitute_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (s == &s_) s = 0;
+ if (s)
+ {
+ SETSYMBOL(x->p_match, s);
+ if (ac && substitute_atomvalidate(av))
+ *x->p_repl = *av;
+ }
+ else if (ac && substitute_atomvalidate(av))
+ {
+ *x->p_match = *av++;
+ if (ac > 1 && substitute_atomvalidate(av))
+ *x->p_repl = *av;
+ }
+}
+
+static void substitute_proxy_bang(t_substitute_proxy *x)
+{
+ SETSYMBOL(x->p_match, &s_bang);
+}
+
+static void substitute_proxy_float(t_substitute_proxy *x, t_float f)
+{
+ SETFLOAT(x->p_match, f);
+}
+
+/* CHECKED (but LATER rethink) */
+static void substitute_proxy_symbol(t_substitute_proxy *x, t_symbol *s)
+{
+ SETSYMBOL(x->p_match, &s_symbol);
+ SETSYMBOL(x->p_repl, s);
+}
+
+/* LATER gpointer */
+
+static void substitute_proxy_list(t_substitute_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ substitute_proxy_anything(x, 0, ac, av);
+}
+
+static void substitute_free(t_substitute *x)
+{
+ if (x->x_proxy) pd_free(x->x_proxy);
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+}
+
+static void *substitute_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_substitute *x = 0;
+ t_substitute_proxy *proxy =
+ (t_substitute_proxy *)pd_new(substitute_proxy_class);
+ if (proxy)
+ {
+ x = (t_substitute *)pd_new(substitute_class);
+ proxy->p_match = &x->x_match;
+ proxy->p_repl = &x->x_repl;
+ x->x_proxy = (t_pd *)proxy;
+ x->x_size = SUBSTITUTE_INISIZE;
+ x->x_message = x->x_messini;
+ x->x_entered = 0;
+ /* CHECKED: everything is to be passed unchanged, until both are set */
+ /* CHECKED: max crashes if a match has been set, but not a replacement,
+ and there is a match */
+ x->x_match.a_type = x->x_repl.a_type = A_NULL;
+ x->x_auxmatch.a_type = x->x_auxrepl.a_type = A_NULL;
+ inlet_new((t_object *)x, (t_pd *)proxy, 0, 0);
+ outlet_new((t_object *)x, &s_anything);
+ /* CHECKED (refman error: 'a bang is sent') */
+ x->x_passout = outlet_new((t_object *)x, &s_anything);
+ substitute_proxy_anything(proxy, 0, ac, av);
+ }
+ return (x);
+}
+
+void substitute_setup(void)
+{
+ substitute_class = class_new(gensym("substitute"),
+ (t_newmethod)substitute_new,
+ (t_method)substitute_free,
+ sizeof(t_substitute), 0,
+ A_GIMME, 0);
+ class_addbang(substitute_class, substitute_bang);
+ class_addfloat(substitute_class, substitute_float);
+ class_addsymbol(substitute_class, substitute_symbol);
+ class_addlist(substitute_class, substitute_list);
+ class_addanything(substitute_class, substitute_anything);
+ substitute_proxy_class = class_new(gensym("_substitute_proxy"), 0, 0,
+ sizeof(t_substitute_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(substitute_proxy_class, substitute_proxy_bang);
+ class_addfloat(substitute_proxy_class, substitute_proxy_float);
+ class_addsymbol(substitute_proxy_class, substitute_proxy_symbol);
+ class_addlist(substitute_proxy_class, substitute_proxy_list);
+ class_addanything(substitute_proxy_class, substitute_proxy_anything);
+ class_addmethod(substitute_proxy_class, (t_method)substitute_proxy_list,
+ gensym("set"), A_GIMME, 0);
+}