aboutsummaryrefslogtreecommitdiff
path: root/shared/toxy/scriptlet.c
diff options
context:
space:
mode:
authorN.N. <krzyszcz@users.sourceforge.net>2003-09-24 10:46:19 +0000
committerN.N. <krzyszcz@users.sourceforge.net>2003-09-24 10:46:19 +0000
commit9680b47879dfc58f884208f7abf2f945b3b41d25 (patch)
tree93eda19deb61daff60c533a3bbd1efe79e9cdc9b /shared/toxy/scriptlet.c
parentedab184352cd14788a37c76dce147ac19f7464b4 (diff)
adding toxy project
svn path=/trunk/externals/miXed/; revision=1024
Diffstat (limited to 'shared/toxy/scriptlet.c')
-rw-r--r--shared/toxy/scriptlet.c666
1 files changed, 666 insertions, 0 deletions
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);
+}