aboutsummaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
Diffstat (limited to 'shared')
-rw-r--r--shared/Makefile.dirs2
-rw-r--r--shared/common/props.c518
-rw-r--r--shared/common/props.h26
-rw-r--r--shared/toxy/Makefile4
-rw-r--r--shared/toxy/Makefile.objects0
-rw-r--r--shared/toxy/Makefile.sources2
-rw-r--r--shared/toxy/scriptlet.c666
-rw-r--r--shared/toxy/scriptlet.h42
8 files changed, 1259 insertions, 1 deletions
diff --git a/shared/Makefile.dirs b/shared/Makefile.dirs
index d9be5aa..5764f41 100644
--- a/shared/Makefile.dirs
+++ b/shared/Makefile.dirs
@@ -1 +1 @@
-MIXED_DIRS = common hammer sickle toys unstable
+MIXED_DIRS = common hammer sickle toxy unstable
diff --git a/shared/common/props.c b/shared/common/props.c
new file mode 100644
index 0000000..6b6181a
--- /dev/null
+++ b/shared/common/props.c
@@ -0,0 +1,518 @@
+/* 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/grow.h"
+#include "common/props.h"
+
+//#define PROPS_DEBUG
+
+#define PROPS_INISIZE 32 /* LATER rethink */
+#define PROPS_MAXOTHERS 32
+
+enum { PROPS_NONE = 0, PROPS_THIS, PROPS_OTHER };
+
+typedef struct _propelem
+{
+ char *e_key;
+ char *e_value;
+ struct _propelem *e_next;
+} t_propelem;
+
+struct _props
+{
+ char p_thisescape;
+ char *p_thisinitial;
+ char *p_name;
+ int p_size; /* as allocated */
+ int p_natoms; /* as used */
+ t_atom *p_buffer;
+ t_atom p_bufini[PROPS_INISIZE];
+ t_pd *p_owner;
+ t_propsresolver p_resolver;
+ t_propelem *p_dict;
+ t_propelem *p_nextelem;
+ int p_badupdate;
+ char p_otherescapes[PROPS_MAXOTHERS];
+ t_props *p_otherprops; /* props list's head */
+ t_props *p_next;
+};
+
+/* Dictionary of properties, p_dict, meant to be nothing more, but an
+ optimalization detail, is handled implicitly, through its owning t_props.
+ This optimalization has to be enabled by passing a nonzero 'resolver'
+ argument to props_new().
+ Since p_dict stores resolved strings, it is a secondary, `shallow' storage,
+ which has to be synced to its master, p_buffer of atoms.
+ Currently, p_dict is implemented as an unsorted linked list, which should
+ be fine in most cases (but might need revisiting LATER). */
+
+static t_propelem *propelem_new(char *key, char *value)
+{
+ t_propelem *ep = (t_propelem *)getbytes(sizeof(*ep));
+ ep->e_key = getbytes(strlen(key) + 1);
+ strcpy(ep->e_key, key);
+ ep->e_value = getbytes(strlen(value) + 1);
+ strcpy(ep->e_value, value);
+ ep->e_next = 0;
+ return (ep);
+}
+
+static void propelem_free(t_propelem *ep)
+{
+ if (ep->e_key) freebytes(ep->e_key, strlen(ep->e_key) + 1);
+ if (ep->e_value) freebytes(ep->e_value, strlen(ep->e_value) + 1);
+ freebytes(ep, sizeof(*ep));
+}
+
+/* Returns zero if the key was found (and value replaced),
+ nonzero if a new element was added. */
+static t_propelem *propelem_add(t_propelem *ep, char *key, char *value)
+{
+ while (ep)
+ {
+ if (strcmp(ep->e_key, key))
+ ep = ep->e_next;
+ else
+ break;
+ }
+ if (ep)
+ {
+ if (strcmp(ep->e_value, value))
+ {
+ if (ep->e_value)
+ ep->e_value = resizebytes(ep->e_value, strlen(ep->e_value) + 1,
+ strlen(value) + 1);
+ else
+ ep->e_value = getbytes(strlen(value) + 1);
+ strcpy(ep->e_value, value);
+ }
+ return (0);
+ }
+ else return (propelem_new(key, value));
+}
+
+static void props_dictadd(t_props *pp, t_symbol *s, int ac, t_atom *av)
+{
+ if (s && *s->s_name && s->s_name[1] && ac)
+ {
+ t_propelem *ep;
+ char *value = pp->p_resolver(pp->p_owner, ac, av);
+ if (value &&
+ (ep = propelem_add(pp->p_dict, s->s_name + 1, value)))
+ {
+ ep->e_next = pp->p_dict;
+ pp->p_dict = ep;
+ }
+ }
+}
+
+static int props_atstart(t_props *pp, char *buf)
+{
+ if (*buf == pp->p_thisescape)
+ {
+ char c = buf[1];
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
+ || (pp->p_thisinitial && strchr(pp->p_thisinitial, c)))
+ return (PROPS_THIS);
+ }
+ return (PROPS_NONE);
+}
+
+static char *props_otherinitial(t_props *pp, char c)
+{
+ t_props *pp1 = pp->p_otherprops;
+ while (pp1)
+ {
+ if (pp1 != pp && pp1->p_thisescape == c)
+ return (pp1->p_thisinitial);
+ pp1 = pp1->p_next;
+ }
+ bug("props_otherinitial");
+ post("(%c \"%s\")", c, pp->p_otherescapes);
+ return (0);
+}
+
+static int props_atnext(t_props *pp, char *buf)
+{
+ char *otherinitial;
+ if (*buf == pp->p_thisescape)
+ {
+ char c = buf[1];
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
+ || (pp->p_thisinitial && strchr(pp->p_thisinitial, c)))
+ return (PROPS_THIS);
+ }
+ else if (*pp->p_otherescapes && strchr(pp->p_otherescapes, *buf))
+ {
+ char c = buf[1];
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
+ || ((otherinitial = props_otherinitial(pp, *buf))
+ && *otherinitial && strchr(otherinitial, c)))
+ return (PROPS_OTHER);
+ }
+ return (PROPS_NONE);
+}
+
+/* Search for a property, replace its value if found, otherwise add.
+ Assuming s is valid. Returning nafter - nbefore. */
+static int props_update(t_props *pp, t_symbol *s, int ac, t_atom *av, int doit)
+{
+ int nadd, ndiff, ibeg, iend = 0;
+ t_atom *ap;
+ for (nadd = 0, ap = av; nadd < ac; nadd++, ap++)
+ if (ap->a_type == A_SYMBOL
+ && props_atnext(pp, ap->a_w.w_symbol->s_name))
+ break;
+ if (!nadd)
+ {
+ pp->p_badupdate = 1;
+ return (0);
+ }
+ pp->p_badupdate = 0;
+ nadd++;
+ for (ibeg = 0, ap = pp->p_buffer; ibeg < pp->p_natoms; ibeg++, ap++)
+ {
+ if (ap->a_type == A_SYMBOL && ap->a_w.w_symbol == s)
+ {
+ for (iend = ibeg + 1, ap++; iend < pp->p_natoms; iend++, ap++)
+ if (ap->a_type == A_SYMBOL
+ && props_atnext(pp, ap->a_w.w_symbol->s_name))
+ break;
+ break;
+ }
+ }
+ ndiff = (iend > ibeg ? nadd - (iend - ibeg) : nadd);
+ if (doit)
+ {
+ int i, newnatoms = pp->p_natoms + ndiff;
+ if (newnatoms > pp->p_size)
+ {
+ bug("props_update");
+ return (0);
+ }
+#ifdef PROPS_DEBUG
+ post("%s %s, [%d..%d), ndiff %d",
+ (iend > ibeg ? "replacing" : "adding"), s->s_name,
+ ibeg, iend, ndiff);
+#endif
+ if (iend > ibeg)
+ {
+ if (ndiff > 0)
+ {
+ t_atom *ap2 = pp->p_buffer + newnatoms;
+ t_atom *ap1 = ap2 - ndiff;
+ for (i = iend; i < pp->p_natoms; i++) *--ap2 = *--ap1;
+ }
+ else if (ndiff < 0)
+ {
+ t_atom *ap2 = pp->p_buffer + iend;
+ t_atom *ap1 = ap2 + ndiff;
+ for (i = iend; i < pp->p_natoms; i++) *ap1++ = *ap2++;
+ }
+ ap = pp->p_buffer + ibeg;
+ }
+ else
+ {
+ ap = pp->p_buffer + pp->p_natoms;
+ SETSYMBOL(ap, s);
+ }
+ ap++;
+ nadd--;
+ if (pp->p_resolver) props_dictadd(pp, s, nadd, av);
+ for (i = 0; i < nadd; i++) *ap++ = *av++;
+ pp->p_natoms = newnatoms;
+ }
+ return (ndiff);
+}
+
+/* If there is an empty property, do not parse beyond.
+ Return the offending switch, if any. */
+t_symbol *props_add(t_props *pp, t_symbol *s, int ac, t_atom *av)
+{
+ t_symbol *empty = 0;
+ t_atom *av1, *ap;
+ int ac1, i, ngrown = 0;
+ if (s && props_atstart(pp, s->s_name))
+ ngrown += props_update(pp, s, ac, av, 0);
+ if (pp->p_badupdate)
+ empty = s;
+ else for (i = 0, ap = av; i < ac; i++, ap++)
+ {
+ if (ap->a_type == A_SYMBOL
+ && props_atstart(pp, ap->a_w.w_symbol->s_name))
+ {
+ ngrown += props_update(pp, ap->a_w.w_symbol, ac - i - 1, ap + 1, 0);
+ if (pp->p_badupdate)
+ {
+ empty = ap->a_w.w_symbol;
+ break;
+ }
+ }
+ }
+ ngrown += pp->p_natoms;
+ if (ngrown > pp->p_size)
+ {
+ int nrequested = ngrown;
+ pp->p_buffer = grow_withdata(&nrequested, &pp->p_natoms,
+ &pp->p_size, pp->p_buffer,
+ PROPS_INISIZE, pp->p_bufini,
+ sizeof(*pp->p_buffer));
+ if (nrequested != ngrown)
+ goto done;
+ }
+ ac1 = (s ? ac + 1 : ac);
+ if (!(av1 = getbytes(ac1 * sizeof(*av1))))
+ goto done;
+ ap = av1;
+ if (s)
+ {
+ SETSYMBOL(ap, s);
+ ap++;
+ }
+ while (ac--) *ap++ = *av++;
+ ac = ac1;
+ av = av1;
+ for (i = 0, ap = av; i < ac; i++, ap++)
+ {
+ if (ap->a_type == A_SYMBOL
+ && props_atstart(pp, ap->a_w.w_symbol->s_name))
+ {
+ props_update(pp, ap->a_w.w_symbol, ac - i - 1, ap + 1, 1);
+ if (pp->p_badupdate)
+ {
+ empty = ap->a_w.w_symbol;
+ break;
+ }
+ }
+ }
+ freebytes(av1, ac1 * sizeof(*av1));
+done:
+ return (empty);
+}
+
+/* FIXME remove from p_dict */
+int props_remove(t_props *pp, t_symbol *s)
+{
+ int ac;
+ t_atom *av = props_getone(pp, s, &ac);
+ if (av)
+ {
+ int i;
+ t_atom *ap = av + ac;
+ t_atom *guard = pp->p_buffer + pp->p_natoms;
+ while (ap < guard) *av++ = *ap++;
+ pp->p_natoms -= ac;
+ return (1);
+ }
+ else return (0);
+}
+
+/* LATER think about 'deep' cloning, i.e. propagating source atoms into
+ the destination buffer. Since cloning, unless requested by the user,
+ should never be persistent (source atoms should not stick to the
+ destination object in a .pd file), deep cloning requires introducing
+ a two-buffer scheme. There is no reason for deep cloning of arguments,
+ or handlers, but options could benefit. */
+
+void props_clone(t_props *to, t_props *from)
+{
+ if (to->p_resolver)
+ {
+ /* LATER make this into a generic traversing method */
+ int ibeg = 0, iend = 0;
+ t_atom *abeg = from->p_buffer;
+ t_atom *ap = abeg;
+ while (ibeg < from->p_natoms)
+ {
+ if (ap->a_type == A_SYMBOL &&
+ props_atstart(from, ap->a_w.w_symbol->s_name))
+ {
+ for (iend = ibeg + 1, ap++; iend < from->p_natoms; iend++, ap++)
+ if (ap->a_type == A_SYMBOL
+ && props_atnext(from, ap->a_w.w_symbol->s_name))
+ break;
+ props_dictadd(to, abeg->a_w.w_symbol,
+ iend - ibeg - 1, abeg + 1);
+ if (iend < from->p_natoms)
+ {
+ ibeg = iend;
+ abeg = ap;
+ }
+ else break;
+ }
+ else
+ {
+ ibeg++;
+ ap++;
+ }
+ }
+ }
+ else
+ {
+ /* LATER */
+ }
+}
+
+/* only dictionary-enabled properties handle props_...value() calls */
+
+char *props_getvalue(t_props *pp, char *key)
+{
+ if (pp->p_resolver)
+ {
+ t_propelem *ep = pp->p_dict;
+ while (ep)
+ {
+ if (strcmp(ep->e_key, key))
+ ep = ep->e_next;
+ else
+ return (ep->e_value);
+ }
+ }
+ return (0);
+}
+
+char *props_nextvalue(t_props *pp, char **keyp)
+{
+ if (pp->p_nextelem)
+ {
+ char *value = pp->p_nextelem->e_value;
+ *keyp = pp->p_nextelem->e_key;
+ pp->p_nextelem = pp->p_nextelem->e_next;
+ return (value);
+ }
+ return (0);
+}
+
+char *props_firstvalue(t_props *pp, char **keyp)
+{
+ if (pp->p_resolver)
+ pp->p_nextelem = pp->p_dict;
+ return (props_nextvalue(pp, keyp));
+}
+
+t_atom *props_getone(t_props *pp, t_symbol *s, int *npp)
+{
+ int ibeg, iend = 0;
+ t_atom *ap;
+ if (!(s && props_atstart(pp, s->s_name)))
+ return (0);
+ for (ibeg = 0, ap = pp->p_buffer; ibeg < pp->p_natoms; ibeg++, ap++)
+ {
+ if (ap->a_type == A_SYMBOL && ap->a_w.w_symbol == s)
+ {
+ for (iend = ibeg + 1, ap++; iend < pp->p_natoms; iend++, ap++)
+ if (ap->a_type == A_SYMBOL
+ && props_atnext(pp, ap->a_w.w_symbol->s_name))
+ break;
+ break;
+ }
+ }
+ if (iend > ibeg)
+ {
+ *npp = iend - ibeg;
+ return (pp->p_buffer + ibeg);
+ }
+ else return (0);
+}
+
+t_atom *props_getall(t_props *pp, int *npp)
+{
+ *npp = pp->p_natoms;
+ return (pp->p_buffer);
+}
+
+char *props_getname(t_props *pp)
+{
+ return (pp ? pp->p_name : "property");
+}
+
+static void props_freeone(t_props *pp)
+{
+ if (pp->p_buffer != pp->p_bufini)
+ freebytes(pp->p_buffer, pp->p_size * sizeof(*pp->p_buffer));
+ while (pp->p_dict)
+ {
+ t_propelem *ep = pp->p_dict->e_next;
+ propelem_free(pp->p_dict);
+ pp->p_dict = ep;
+ }
+ freebytes(pp, sizeof(*pp));
+}
+
+void props_freeall(t_props *pp)
+{
+ if (pp && (pp = pp->p_otherprops))
+ {
+ while (pp)
+ {
+ t_props *pp1 = pp->p_next;
+ props_freeone(pp);
+ pp = pp1;
+ }
+ }
+ else bug("props_freeall");
+}
+
+void props_setupothers(t_props *pp, t_props *otherprops)
+{
+ t_props *pp1;
+ pp->p_next = (otherprops ? otherprops->p_otherprops : 0);
+ for (pp1 = pp; pp1; pp1 = pp1->p_next)
+ {
+ t_props *pp2;
+ char *bp = pp1->p_otherescapes;
+ int i;
+ pp1->p_otherprops = pp;
+ for (pp2 = pp, i = 1; pp2 && i < PROPS_MAXOTHERS;
+ pp2 = pp2->p_next, i++)
+ if (pp2 != pp1)
+ *bp++ = pp2->p_thisescape;
+ *bp = 0;
+#ifdef PROPS_DEBUG
+ startpost("%c \"%s\" ", pp1->p_thisescape, pp1->p_otherescapes);
+#endif
+ }
+#ifdef PROPS_DEBUG
+ endpost();
+#endif
+}
+
+/* nonzero resolver requires the owner to be nonzero */
+t_props *props_new(t_pd *owner, char *name, char *thisdelim,
+ t_props *otherprops, t_propsresolver resolver)
+{
+ t_props *pp = getbytes(sizeof(*pp));
+ if (pp)
+ {
+ pp->p_name = name;
+ if (thisdelim && *thisdelim)
+ {
+ pp->p_thisescape = *thisdelim++;
+ pp->p_thisinitial = (*thisdelim ? thisdelim : 0);
+ }
+ else
+ {
+ bug("props_new (no escape)");
+ pp->p_thisescape = '-';
+ pp->p_thisinitial = 0;
+ }
+ props_setupothers(pp, otherprops);
+ pp->p_size = PROPS_INISIZE;
+ pp->p_natoms = 0;
+ pp->p_buffer = pp->p_bufini;
+ if (pp->p_owner = owner)
+ pp->p_resolver = resolver;
+ else
+ {
+ if (resolver)
+ bug("props_new (no owner)");
+ pp->p_resolver = 0;
+ }
+ pp->p_dict = 0;
+ pp->p_nextelem = 0;
+ }
+ return (pp);
+}
diff --git a/shared/common/props.h b/shared/common/props.h
new file mode 100644
index 0000000..0eef345
--- /dev/null
+++ b/shared/common/props.h
@@ -0,0 +1,26 @@
+/* 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 __PROPS_H__
+#define __PROPS_H__
+
+EXTERN_STRUCT _props;
+#define t_props struct _props
+
+typedef char *(*t_propsresolver)(t_pd *, int, t_atom *);
+
+t_symbol *props_add(t_props *pp, t_symbol *s, int ac, t_atom *av);
+int props_remove(t_props *pp, t_symbol *s);
+void props_clone(t_props *to, t_props *from);
+char *props_getvalue(t_props *pp, char *key);
+char *props_firstvalue(t_props *pp, char **keyp);
+char *props_nextvalue(t_props *pp, char **keyp);
+t_atom *props_getone(t_props *pp, t_symbol *s, int *npp);
+t_atom *props_getall(t_props *pp, int *npp);
+char *props_getname(t_props *pp);
+void props_freeall(t_props *pp);
+t_props *props_new(t_pd *owner, char *name, char *thisdelim,
+ t_props *otherprops, t_propsresolver resolver);
+
+#endif
diff --git a/shared/toxy/Makefile b/shared/toxy/Makefile
new file mode 100644
index 0000000..5dcb2c8
--- /dev/null
+++ b/shared/toxy/Makefile
@@ -0,0 +1,4 @@
+ROOT_DIR = ../..
+include $(ROOT_DIR)/Makefile.common
+
+all: $(OBJECTS)
diff --git a/shared/toxy/Makefile.objects b/shared/toxy/Makefile.objects
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shared/toxy/Makefile.objects
diff --git a/shared/toxy/Makefile.sources b/shared/toxy/Makefile.sources
new file mode 100644
index 0000000..5f34f42
--- /dev/null
+++ b/shared/toxy/Makefile.sources
@@ -0,0 +1,2 @@
+OTHER_SOURCES = \
+scriptlet.c
diff --git a/shared/toxy/scriptlet.c b/shared/toxy/scriptlet.c
new file mode 100644
index 0000000..2592cee
--- /dev/null
+++ b/shared/toxy/scriptlet.c
@@ -0,0 +1,666 @@
+/* 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 <stdio.h>
+#include <string.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#endif
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "common/grow.h"
+#include "common/props.h"
+#include "scriptlet.h"
+
+//#define SCRIPTLET_DEBUG
+
+#define SCRIPTLET_INISIZE 1024
+#define SCRIPTLET_MARGIN 64
+#define SCRIPTLET_MAXARGS 9 /* do not increase (parser's constraint) */
+#define SCRIPTLET_MAXPUSH 20000 /* Tcl limit? LATER investigate */
+
+enum { SCRIPTLET_CVOK, SCRIPTLET_CVUNKNOWN, SCRIPTLET_CVMISSING };
+
+struct _scriptlet
+{
+ t_pd *s_owner;
+ t_glist *s_glist; /* containing glist (possibly null) */
+ t_symbol *s_rptarget; /* reply target */
+ t_symbol *s_cbtarget; /* callback target */
+ t_symbol *s_item;
+ t_scriptlet_cvfn s_cvfn;
+ t_canvas *s_cv;
+ int s_cvstate;
+ int s_size;
+ char *s_buffer;
+ char s_bufini[SCRIPTLET_INISIZE];
+ char *s_head; /* ptr to the command part of a scriptlet */
+ char *s_tail;
+ char s_separator; /* current separator, set before a new token */
+ int s_ac; /* the actual count */
+ t_atom s_av[SCRIPTLET_MAXARGS]; /* always padded with zeros (if used) */
+};
+
+static t_canvas *scriptlet_canvasvalidate(t_scriptlet *sp, int visedonly)
+{
+ t_canvas *cv;
+ if (sp->s_cvstate == SCRIPTLET_CVUNKNOWN)
+ {
+ if (sp->s_cvfn)
+ cv = sp->s_cv = sp->s_cvfn(sp->s_owner);
+ else
+ {
+ bug("scriptlet_canvasvalidate");
+ return (0);
+ }
+ if (cv && (!visedonly || glist_isvisible(cv)))
+ sp->s_cvstate = SCRIPTLET_CVOK;
+ else
+ sp->s_cvstate = SCRIPTLET_CVMISSING;
+ }
+ else cv = sp->s_cv;
+ return (sp->s_cvstate == SCRIPTLET_CVOK ? cv : 0);
+}
+
+static int scriptlet_ready(t_scriptlet *sp)
+{
+ int len = sp->s_tail - sp->s_head;
+ if (len > 0 && *sp->s_head && sp->s_cvstate != SCRIPTLET_CVMISSING)
+ {
+ if (len < SCRIPTLET_MAXPUSH)
+ return (1);
+ else
+ loud_error(sp->s_owner,
+ "scriptlet too long to be pushed (%d bytes)", len);
+ }
+ return (0);
+}
+
+static int scriptlet_doappend(t_scriptlet *sp, char *buf)
+{
+ if (buf)
+ {
+ int nprefix = sp->s_head - sp->s_buffer;
+ int nused = sp->s_tail - sp->s_buffer;
+ int newsize = nused + strlen(buf) + SCRIPTLET_MARGIN;
+ if (newsize > sp->s_size)
+ {
+ int nrequested = newsize;
+ sp->s_buffer = grow_withdata(&nrequested, &nused,
+ &sp->s_size, sp->s_buffer,
+ SCRIPTLET_INISIZE, sp->s_bufini,
+ sizeof(*sp->s_buffer));
+ if (nrequested != newsize)
+ {
+ scriptlet_reset(sp);
+ return (0);
+ }
+ sp->s_head = sp->s_buffer + nprefix;
+ sp->s_tail = sp->s_buffer + nused;
+ }
+ if (sp->s_separator && sp->s_tail > sp->s_head)
+ *sp->s_tail++ = sp->s_separator;
+ *sp->s_tail = 0;
+ strcpy(sp->s_tail, buf);
+ sp->s_tail += strlen(sp->s_tail);
+ }
+ sp->s_separator = 0;
+ return (1);
+}
+
+static char *scriptlet_dedot(t_scriptlet *sp, char *ibuf, char *obuf,
+ int resolveall, int visedonly,
+ int ac, t_atom *av, t_props *argprops)
+{
+ int len = 0;
+ switch (*ibuf)
+ {
+ case '#':
+ /* ac is ignored -- assuming av is padded to SCRIPTLET_MAXARGS atoms */
+ if (resolveall)
+ {
+ int which = ibuf[1] - '1';
+ if (which >= 0 && which < SCRIPTLET_MAXARGS)
+ {
+ if (av)
+ {
+ if (av[which].a_type == A_FLOAT)
+ {
+ sprintf(obuf, "%g", av[which].a_w.w_float);
+ len = 2;
+ }
+ else if (av[which].a_type == A_SYMBOL)
+ {
+ strcpy(obuf, av[which].a_w.w_symbol->s_name);
+ len = 2;
+ }
+ }
+ }
+ else if (argprops)
+ {
+ char *ptr;
+ int cnt;
+ for (ptr = ibuf + 1, cnt = 1; *ptr; ptr++, cnt++)
+ {
+ char c = *ptr;
+ if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z'))
+ {
+ cnt = 0;
+ break;
+ }
+ }
+ if (cnt && (ptr = props_getvalue(argprops, ibuf + 1)))
+ {
+ strcpy(obuf, ptr);
+ len = cnt;
+ }
+ }
+ }
+ break;
+ case '-':
+ if (resolveall && sp->s_item)
+ {
+ t_canvas *cv;
+ if (cv = scriptlet_canvasvalidate(sp, visedonly))
+ {
+ sprintf(obuf, ".x%x.c.%s%x", (int)cv, sp->s_item->s_name,
+ (int)sp->s_owner);
+ len = 1;
+ }
+ }
+ break;
+ case '^':
+ if (resolveall)
+ {
+ t_canvas *cv;
+ if (cv = scriptlet_canvasvalidate(sp, visedonly))
+ {
+ sprintf(obuf, ".x%x", (int)cv);
+ len = 1;
+ }
+ }
+ break;
+ case '|':
+ if (resolveall)
+ {
+ strcpy(obuf, sp->s_cbtarget->s_name);
+ len = 1;
+ }
+ break;
+ case '~':
+ if (resolveall)
+ {
+ t_canvas *cv;
+ if (cv = scriptlet_canvasvalidate(sp, visedonly))
+ {
+ /* FIXME */
+ if (!strcmp(&ibuf[1], "x1"))
+ {
+ sprintf(obuf, "%d", cv->gl_screenx1);
+ len = 3;
+ }
+ else if (!strcmp(&ibuf[1], "x2"))
+ {
+ sprintf(obuf, "%d", cv->gl_screenx2);
+ len = 3;
+ }
+ else if (!strcmp(&ibuf[1], "y1"))
+ {
+ sprintf(obuf, "%d", cv->gl_screeny1);
+ len = 3;
+ }
+ else if (!strcmp(&ibuf[1], "y2"))
+ {
+ sprintf(obuf, "%d", cv->gl_screeny2);
+ len = 3;
+ }
+ else if (!strcmp(&ibuf[1], "edit"))
+ {
+ sprintf(obuf, "%d", cv->gl_edit);
+ len = 5;
+ }
+ else loud_error(sp->s_owner, "bad field '%s'", &ibuf[1]);
+ }
+ }
+ break;
+ case '`':
+ sprintf(obuf, "\\");
+ len = 1;
+ break;
+ case ':':
+ sprintf(obuf, ";");
+ len = 1;
+ break;
+ case '(':
+ sprintf(obuf, "{");
+ len = 1;
+ break;
+ case ')':
+ sprintf(obuf, "}");
+ len = 1;
+ break;
+ case '<':
+ if (resolveall)
+ {
+ if (ibuf[1] == ':')
+ {
+ sprintf(obuf, "{::toxy::callback ");
+ len = 2;
+ }
+ else if (ibuf[1] == '|')
+ {
+ sprintf(obuf, "{::toxy::callback %s ",
+ sp->s_rptarget->s_name);
+ len = 2;
+ }
+ else
+ {
+ sprintf(obuf, "{::toxy::callback %s _cb ",
+ sp->s_cbtarget->s_name);
+ len = 1;
+ }
+ }
+ break;
+ case '>':
+ if (resolveall)
+ {
+ sprintf(obuf, "}");
+ len = 1;
+ }
+ break;
+ }
+ return (len ? ibuf + len : 0);
+}
+
+void scriptlet_reset(t_scriptlet *sp)
+{
+ sp->s_cvstate = SCRIPTLET_CVUNKNOWN;
+ sp->s_separator = 0;
+ strcpy(sp->s_buffer, "namespace eval ::toxy {\
+ proc query {} {set ::toxy::reply [\n");
+ sp->s_head = sp->s_tail = sp->s_buffer + strlen(sp->s_buffer);
+}
+
+void scriptlet_prealloc(t_scriptlet *sp, int sz, int mayshrink)
+{
+ if (sz < SCRIPTLET_INISIZE)
+ sz = SCRIPTLET_INISIZE;
+ if (sz < sp->s_size && mayshrink)
+ {
+ if (sp->s_buffer != sp->s_bufini)
+ freebytes(sp->s_buffer, sp->s_size * sizeof(*sp->s_buffer));
+ else
+ bug("scriptlet_prealloc");
+ sp->s_size = SCRIPTLET_INISIZE;
+ sp->s_buffer = sp->s_bufini;
+ }
+ if (sz > sp->s_size)
+ sp->s_buffer = grow_nodata(&sz, &sp->s_size, sp->s_buffer,
+ SCRIPTLET_INISIZE, sp->s_bufini,
+ sizeof(*sp->s_buffer));
+ scriptlet_reset(sp);
+}
+
+int scriptlet_addstring(t_scriptlet *sp, char *ibuf,
+ int resolveall, int visedonly,
+ int ac, t_atom *av, t_props *argprops)
+{
+ int result = 1;
+ char *bp = ibuf, *ep = ibuf, *ep1;
+ char dotbuf[64]; /* LATER reestimation */
+ if (!sp->s_separator)
+ sp->s_separator = ' ';
+ while (*ep)
+ {
+ if (*ep == '.'
+ && (ep1 = scriptlet_dedot(sp, ep + 1, dotbuf,
+ resolveall, visedonly, ac, av, argprops)))
+ {
+ *ep = 0;
+ if (!(result = scriptlet_doappend(sp, bp)))
+ break;
+ *ep = '.';
+ if (!(result = scriptlet_doappend(sp, dotbuf)))
+ break;
+ bp = ep = ep1;
+ }
+ else ep++;
+ }
+ if (result)
+ result = scriptlet_doappend(sp, bp);
+ sp->s_separator = 0;
+ return (result);
+}
+
+int scriptlet_addfloat(t_scriptlet *sp, t_float f)
+{
+ char buf[64];
+ if (!sp->s_separator)
+ sp->s_separator = ' ';
+ sprintf(buf, "%g ", f);
+ return (scriptlet_doappend(sp, buf));
+}
+
+int scriptlet_add(t_scriptlet *sp,
+ int resolveall, int visedonly, int ac, t_atom *av)
+{
+ while (ac--)
+ {
+ int result = 1;
+ if (av->a_type == A_SYMBOL)
+ result = scriptlet_addstring(sp, av->a_w.w_symbol->s_name,
+ resolveall, visedonly, 0, 0, 0);
+ else if (av->a_type == A_FLOAT)
+ result = scriptlet_addfloat(sp, av->a_w.w_float);
+ if (!result)
+ return (0);
+ av++;
+ }
+ return (1);
+}
+
+void scriptlet_setseparator(t_scriptlet *sp, char c)
+{
+ sp->s_separator = c;
+}
+
+void scriptlet_push(t_scriptlet *sp)
+{
+ if (scriptlet_ready(sp))
+ {
+ char *tail = sp->s_tail;
+ strcpy(tail, "\n");
+ sys_gui(sp->s_head);
+ *tail = 0;
+ }
+}
+
+void scriptlet_qpush(t_scriptlet *sp)
+{
+ if (scriptlet_ready(sp))
+ {
+ char buf[MAXPDSTRING];
+ char *tail = sp->s_tail;
+ strcpy(tail, "]}}\n");
+ sys_gui(sp->s_buffer);
+ *tail = 0;
+ sprintf(buf, "after 0 {::toxy::query}\nvwait ::toxy::reply\n\
+ pd [concat %s _rp $::toxy::reply \\;]\n", sp->s_rptarget->s_name);
+ sys_gui(buf);
+ }
+}
+
+int scriptlet_evaluate(t_scriptlet *insp, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops)
+{
+ if (scriptlet_ready(insp))
+ {
+ t_atom *ap;
+ int i;
+ char *bp;
+ char separator = 0;
+ insp->s_ac = ac;
+ for (i = 0, ap = insp->s_av; i < SCRIPTLET_MAXARGS; i++, ap++)
+ {
+ if (ac)
+ {
+ if (av->a_type == A_FLOAT ||
+ (av->a_type == A_SYMBOL && av->a_w.w_symbol))
+ *ap = *av;
+ else
+ SETFLOAT(ap, 0);
+ ac--; av++;
+ }
+ else SETFLOAT(ap, 0);
+ }
+ /* FIXME pregrowing of the transient scriptlet */
+ scriptlet_reset(outsp);
+ /* LATER abstract this into scriptlet_parse() */
+ bp = insp->s_head;
+ while (*bp)
+ {
+ if (*bp == '\n')
+ separator = '\n';
+ else if (*bp == ' ' || *bp == '\t')
+ {
+ if (!separator) separator = ' ';
+ }
+ else
+ {
+ int done = 1;
+ char *ep = bp;
+ char c = ' ';
+ while (*++ep)
+ {
+ if (*ep == ' ' || *bp == '\t' || *ep == '\n')
+ {
+ done = 0;
+ c = *ep;
+ *ep = 0;
+ break;
+ }
+ }
+ outsp->s_separator = separator;
+ scriptlet_addstring(outsp, bp, 1, visedonly,
+ ac, insp->s_av, argprops);
+ if (done)
+ break;
+ *ep = c;
+ bp = ep;
+ separator = (c == '\t' ? ' ' : c);
+ }
+ bp++;
+ }
+ return (outsp->s_cvstate != SCRIPTLET_CVMISSING);
+ }
+ else return (0);
+}
+
+/* utility function to be used in a comment-parsing callback */
+char *scriptlet_nextword(char *buf)
+{
+ while (*++buf)
+ {
+ if (*buf == ' ' || *buf == '\t')
+ {
+ char *ptr = buf + 1;
+ while (*ptr == ' ' || *ptr == '\t') ptr++;
+ *buf = 0;
+ return (*ptr ? ptr : 0);
+ }
+ }
+ return (0);
+}
+
+static int scriptlet_doread(t_scriptlet *sp, FILE *fp, char *rc,
+ t_scriptlet_cmntfn cmntfn)
+{
+ t_scriptlet *outsp = sp, *newsp;
+ char buf[MAXPDSTRING];
+ scriptlet_reset(outsp);
+ while (!feof(fp))
+ {
+ if (fgets(buf, MAXPDSTRING - 1, fp))
+ {
+ char *ptr = buf;
+ while (*ptr == ' ' || *ptr == '\t') ptr++;
+ if (*ptr == '#')
+ {
+ if (cmntfn)
+ {
+ char sel = *++ptr;
+ if (sel && sel != '\n')
+ {
+ ptr++;
+ while (*ptr == ' ' || *ptr == '\t') ptr++;
+ if (*ptr == '\n')
+ *ptr = 0;
+ if (*ptr)
+ {
+ char *ep = ptr + strlen(ptr) - 1;
+ while (*ep == ' ' || *ep == '\t' || *ep == '\n')
+ ep--;
+ ep[1] = 0;
+ }
+ newsp = cmntfn(sp->s_owner, rc, sel, ptr);
+ if (newsp && newsp != outsp)
+ scriptlet_reset(outsp = newsp);
+ }
+ }
+ }
+ else if (*ptr && *ptr != '\n')
+ scriptlet_doappend(outsp, buf);
+ }
+ else break;
+ }
+ return (SCRIPTLET_OK);
+}
+
+int scriptlet_rcload(t_scriptlet *sp, char *rc, char *ext,
+ t_scriptlet_cmntfn cmntfn)
+{
+ char filename[MAXPDSTRING], buf[MAXPDSTRING], *nameptr, *dir;
+ int fd;
+ if (sp->s_glist)
+ dir = canvas_getdir(sp->s_glist)->s_name;
+ else
+ dir = "";
+ if ((fd = open_via_path(dir, rc, ext, buf, &nameptr, MAXPDSTRING, 0)) < 0)
+ {
+ return (SCRIPTLET_NOFILE);
+ }
+ else
+ {
+ FILE *fp;
+ close(fd);
+ strcpy(filename, buf);
+ strcat(filename, "/");
+ strcat(filename, nameptr);
+ sys_bashfilename(filename, filename);
+ if (fp = fopen(filename, "r"))
+ {
+ int result = scriptlet_doread(sp, fp, rc, cmntfn);
+ fclose(fp);
+ return (result);
+ }
+ else
+ {
+ bug("scriptlet_rcload");
+ return (SCRIPTLET_NOFILE);
+ }
+ }
+}
+
+int scriptlet_read(t_scriptlet *sp, t_symbol *fn)
+{
+ FILE *fp;
+ char buf[MAXPDSTRING];
+ post("loading scriptlet file \"%s\"", fn->s_name);
+ if (sp->s_glist)
+ canvas_makefilename(sp->s_glist, fn->s_name, buf, MAXPDSTRING);
+ else
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ sys_bashfilename(buf, buf);
+ if (fp = fopen(buf, "r"))
+ {
+ int result = scriptlet_doread(sp, fp, 0, 0);
+ fclose(fp);
+ return (result);
+ }
+ else
+ {
+ loud_error(sp->s_owner, "error while loading file \"%s\"", fn->s_name);
+ return (SCRIPTLET_NOFILE);
+ }
+}
+
+int scriptlet_write(t_scriptlet *sp, t_symbol *fn)
+{
+ int size = sp->s_tail - sp->s_head;
+ if (size > 0 && *sp->s_head)
+ {
+ FILE *fp;
+ char buf[MAXPDSTRING];
+ post("saving scriptlet file \"%s\"", fn->s_name);
+ if (sp->s_glist)
+ canvas_makefilename(sp->s_glist, fn->s_name, buf, MAXPDSTRING);
+ else
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ sys_bashfilename(buf, buf);
+ if (fp = fopen(buf, "w"))
+ {
+ int result = fwrite(sp->s_head, 1, size, fp);
+ fclose(fp);
+ if (result == size)
+ return (SCRIPTLET_OK);
+ }
+ loud_error(sp->s_owner, "error while saving file \"%s\"", fn->s_name);
+ return (fp ? SCRIPTLET_BADFILE : SCRIPTLET_NOFILE);
+ }
+ else
+ {
+ loud_warning(sp->s_owner, "empty scriptlet not written");
+ return (SCRIPTLET_IGNORED);
+ }
+}
+
+char *scriptlet_getcontents(t_scriptlet *sp, int *lenp)
+{
+ *lenp = sp->s_tail - sp->s_head;
+ return (sp->s_head);
+}
+
+char *scriptlet_getbuffer(t_scriptlet *sp, int *sizep)
+{
+ *sizep = sp->s_size;
+ return (sp->s_buffer);
+}
+
+void scriptlet_clone(t_scriptlet *to, t_scriptlet *from)
+{
+ scriptlet_reset(to);
+ to->s_separator = ' ';
+ /* LATER use from's buffer with refcount */
+ scriptlet_doappend(to, from->s_head);
+}
+
+void scriptlet_free(t_scriptlet *sp)
+{
+ if (sp)
+ {
+ if (sp->s_buffer != sp->s_bufini)
+ freebytes(sp->s_buffer, sp->s_size * sizeof(*sp->s_buffer));
+ freebytes(sp, sizeof(*sp));
+ }
+}
+
+t_scriptlet *scriptlet_new(t_pd *owner, t_symbol *rptarget, t_symbol *cbtarget,
+ t_symbol *item, t_scriptlet_cvfn cvfn)
+{
+ t_scriptlet *sp = getbytes(sizeof(*sp));
+ if (sp)
+ {
+ static int configured = 0;
+ if (!configured)
+ {
+ sys_gui("namespace eval ::toxy {\
+ proc callback {args} {pd $args \\;}}\n");
+ sys_gui("image create bitmap ::toxy::img::empty -data {}\n");
+ }
+ sp->s_owner = owner;
+ sp->s_glist = canvas_getcurrent();
+ sp->s_rptarget = rptarget;
+ sp->s_cbtarget = cbtarget;
+ sp->s_item = item;
+ sp->s_cvfn = cvfn;
+ sp->s_size = SCRIPTLET_INISIZE;
+ sp->s_buffer = sp->s_bufini;
+ scriptlet_reset(sp);
+ }
+ return (sp);
+}
diff --git a/shared/toxy/scriptlet.h b/shared/toxy/scriptlet.h
new file mode 100644
index 0000000..4b057b9
--- /dev/null
+++ b/shared/toxy/scriptlet.h
@@ -0,0 +1,42 @@
+/* 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 __SCRIPTLET_H__
+#define __SCRIPTLET_H__
+
+enum { SCRIPTLET_OK = 0, SCRIPTLET_NOFILE, SCRIPTLET_BADFILE,
+ SCRIPTLET_IGNORED };
+
+EXTERN_STRUCT _scriptlet;
+#define t_scriptlet struct _scriptlet
+
+typedef t_canvas *(*t_scriptlet_cvfn)(t_pd *);
+typedef t_scriptlet *(*t_scriptlet_cmntfn)(t_pd *, char *, char, char *);
+
+void scriptlet_reset(t_scriptlet *sp);
+void scriptlet_prealloc(t_scriptlet *sp, int sz, int mayshrink);
+int scriptlet_add(t_scriptlet *sp,
+ int resolveall, int visedonly, int ac, t_atom *av);
+int scriptlet_addstring(t_scriptlet *sp, char *ibuf,
+ int resolveall, int visedonly,
+ int ac, t_atom *av, t_props *argprops);
+int scriptlet_addfloat(t_scriptlet *sp, t_float f);
+void scriptlet_setseparator(t_scriptlet *sp, char c);
+void scriptlet_push(t_scriptlet *sp);
+void scriptlet_qpush(t_scriptlet *sp);
+int scriptlet_evaluate(t_scriptlet *insp, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops);
+char *scriptlet_nextword(char *buf);
+int scriptlet_rcload(t_scriptlet *sp, char *rc, char *ext,
+ t_scriptlet_cmntfn cmntfn);
+int scriptlet_read(t_scriptlet *sp, t_symbol *fn);
+int scriptlet_write(t_scriptlet *sp, t_symbol *fn);
+char *scriptlet_getcontents(t_scriptlet *sp, int *lenp);
+char *scriptlet_getbuffer(t_scriptlet *sp, int *sizep);
+void scriptlet_clone(t_scriptlet *to, t_scriptlet *from);
+void scriptlet_free(t_scriptlet *sp);
+t_scriptlet *scriptlet_new(t_pd *owner, t_symbol *rptarget, t_symbol *cbtarget,
+ t_symbol *item, t_scriptlet_cvfn cvfn);
+
+#endif