diff options
Diffstat (limited to 'shared/common/port.c')
-rw-r--r-- | shared/common/port.c | 612 |
1 files changed, 612 insertions, 0 deletions
diff --git a/shared/common/port.c b/shared/common/port.c new file mode 100644 index 0000000..f1471bf --- /dev/null +++ b/shared/common/port.c @@ -0,0 +1,612 @@ +/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* CHECKME inlet/outlet vs inlet~/outlet~ */ +/* LATER think about abstractions */ +/* LATER sort out escaping rules (also revisit binport.c) */ +/* LATER quoting */ +/* LATER resolve object names (preserve connections of unknown dummies?) */ + +#ifdef UNIX +#include <unistd.h> +#endif +#ifdef NT +#include <io.h> +#endif +#include <stdio.h> +#include <string.h> +#include "m_pd.h" +#include "common/loud.h" +#include "common/grow.h" +#include "common/binport.h" +#include "common/port.h" + +#define PORT_INISTACK 256 /* LATER rethink */ +#define PORT_INISIZE 512 /* LATER rethink */ + +enum { PORT_OK, + PORT_NEXT, /* next line, please */ + PORT_UNKNOWN, PORT_CORRUPT, PORT_FATAL }; + +#define PORT_DEFFONTSIZE 10. +#define PORT_XSTRETCH 1.25 +#define PORT_YSTRETCH 1.1 +#define PORT_WSTRETCH 1.25 + +typedef struct _port +{ + t_binbuf *x_oldbb; + t_binbuf *x_newbb; + int x_nobj; + int x_inatoms; + t_atom *x_inmess; + int x_outsize; + int x_outatoms; + t_atom *x_outmess; + t_atom x_outini[PORT_INISIZE]; + int x_stacksize; + int x_stackdepth; + int *x_stack; + int x_stackini[PORT_INISTACK]; +} t_port; + +static t_float port_floatarg(t_port *x, int ndx) +{ + if (ndx < x->x_inatoms) + { + t_atom *av = &x->x_inmess[ndx]; + return (av->a_type == A_FLOAT ? av->a_w.w_float : 0); + } + else return (0); +} + +static t_symbol *port_symbolarg(t_port *x, int ndx) +{ + if (ndx < x->x_inatoms) + { + t_atom *av = &x->x_inmess[ndx]; + return (av->a_type == A_SYMBOL ? av->a_w.w_symbol : &s_); + } + else return (&s_); +} + +static int port_xstretch(float f) +{ + return ((int)(f * PORT_XSTRETCH + 0.5)); +} + +static int port_ystretch(float f) +{ + return ((int)(f * PORT_YSTRETCH + 0.5)); +} + +static int port_wstretch(float f) +{ + return ((int)(f * PORT_WSTRETCH + 0.5)); +} + +static t_float port_xarg(t_port *x, int ndx) +{ + return ((t_float)port_xstretch(port_floatarg(x, ndx))); +} + +static t_float port_yarg(t_port *x, int ndx) +{ + return ((t_float)port_ystretch(port_floatarg(x, ndx))); +} + +static t_float port_widtharg(t_port *x, int ndx) +{ + return ((t_float)port_wstretch(port_floatarg(x, ndx))); +} + +static void port_setxy(t_port *x, int ndx, t_atom *ap) +{ + float f = port_xarg(x, ndx); + SETFLOAT(ap, f); + ndx++; ap++; + f = port_yarg(x, ndx); + SETFLOAT(ap, f); +} + +static int import_obj(t_port *x, char *name) +{ + int ndx = (x->x_inmess[1].a_w.w_symbol == gensym("user") ? 3 : 2); + binbuf_addv(x->x_newbb, "ssffs;", + gensym("#X"), gensym("obj"), + port_xarg(x, ndx), port_yarg(x, ndx + 1), + (name ? gensym(name) : + x->x_inmess[ndx == 2 ? 6 : 2].a_w.w_symbol)); + x->x_nobj++; + return (PORT_NEXT); +} + +static int import_objarg(t_port *x, char *name) +{ + int ndx = (x->x_inmess[1].a_w.w_symbol == gensym("user") ? 3 : 2); + if (x->x_inatoms > 6) + { + t_atom *in = x->x_inmess + ndx + 4; + t_atom *out = x->x_outmess; + SETSYMBOL(out, gensym("#X")); out++; + SETSYMBOL(out, gensym("obj")); out++; + port_setxy(x, ndx, out); out++; out++; + if (name) + { + SETSYMBOL(out, gensym(name)); out++; + if (ndx == 2) in++; + } + else *out++ = (ndx == 2 ? *in++ : x->x_inmess[2]); + for (ndx = 7; ndx < x->x_inatoms; ndx++) + *out++ = *in++; + SETSEMI(out); + binbuf_add(x->x_newbb, x->x_inatoms - 1, x->x_outmess); + x->x_nobj++; + return (PORT_NEXT); + } + else return (PORT_CORRUPT); +} + +static int imaction_vpatcher(t_port *x, char *arg) +{ + if (x->x_stackdepth >= x->x_stacksize) + { + int rqsz = x->x_stackdepth + 1; + int sz = rqsz; + x->x_stack = grow_withdata(&rqsz, &x->x_stackdepth, + &x->x_stacksize, x->x_stack, + PORT_INISTACK, x->x_stackini, + sizeof(*x->x_stack)); + if (rqsz != sz) + { + post("too many embedded patches"); + return (PORT_FATAL); + } + } + x->x_stack[x->x_stackdepth++] = x->x_nobj; + x->x_nobj = 0; + binbuf_addv(x->x_newbb, "ssfffff;", + gensym("#N"), gensym("canvas"), + port_xarg(x, 2), port_yarg(x, 3), + (float)port_xstretch(port_floatarg(x, 4) - port_floatarg(x, 2)), + (float)port_ystretch(port_floatarg(x, 5) - port_floatarg(x, 3)), + PORT_DEFFONTSIZE); + return (PORT_NEXT); +} + +static int imaction_patcher(t_port *x, char *arg) +{ + binbuf_addv(x->x_newbb, "ssffss;", + gensym("#X"), gensym("restore"), + port_xarg(x, 2), port_yarg(x, 3), + gensym("pd"), port_symbolarg(x, 7)); + if (x->x_stackdepth) /* LATER consider returning PORT_FATAL otherwise */ + x->x_stackdepth--; + x->x_nobj = x->x_stack[x->x_stackdepth]; + x->x_nobj++; + return (PORT_NEXT); +} + +static int imaction_trigger(t_port *x, char *arg) +{ + int i; + for (i = 7; i < x->x_inatoms; i++) + if (x->x_inmess[i].a_type == A_SYMBOL && + x->x_inmess[i].a_w.w_symbol == gensym("i")) + x->x_inmess[i].a_w.w_symbol = gensym("f"); + return (PORT_OK); +} + +static int imaction_scope(t_port *x, char *name) +{ + if (x->x_inatoms > 6) + { + t_atom *in = x->x_inmess + 7; + t_atom *out = x->x_outmess; + int i, xpix, ypix; + SETSYMBOL(out, gensym("#X")); out++; + SETSYMBOL(out, gensym("obj")); out++; + port_setxy(x, 3, out); + xpix = (int)out++->a_w.w_float; + ypix = (int)out++->a_w.w_float; + if (name) + { + SETSYMBOL(out, gensym(name)); out++; + } + else *out++ = x->x_inmess[2]; + port_setxy(x, 5, out); + out++->a_w.w_float -= xpix; + out++->a_w.w_float -= ypix; + for (i = 7; i < x->x_inatoms; i++) + *out++ = *in++; + SETSEMI(out); + binbuf_add(x->x_newbb, x->x_inatoms + 1, x->x_outmess); + x->x_nobj++; + return (PORT_NEXT); + } + else return (PORT_CORRUPT); +} + +/* width fontsize fontfamily encoding fontprops red green blue text... */ +static int imaction_comment(t_port *x, char *arg) +{ + int outatoms; + SETSYMBOL(x->x_outmess, gensym("#X")); + SETSYMBOL(x->x_outmess + 1, gensym("obj")); + port_setxy(x, 2, x->x_outmess + 2); + SETSYMBOL(x->x_outmess + 4, gensym("comment")); + if (x->x_inatoms > 5) + { + int i, fontsize, fontprops; + float width = port_widtharg(x, 4); + t_atom *ap = x->x_inmess + 5; + SETFLOAT(x->x_outmess + 5, width); + if (ap->a_type == A_FLOAT) + { + fontsize = ((int)ap->a_w.w_float) & 0x0ff; + fontprops = ((int)ap->a_w.w_float) >> 8; + } + else fontsize = 10, fontprops = 0; + SETFLOAT(x->x_outmess + 6, fontsize); + SETSYMBOL(x->x_outmess + 7, gensym("helvetica")); + SETSYMBOL(x->x_outmess + 8, gensym("?")); + SETFLOAT(x->x_outmess + 9, fontprops); + SETFLOAT(x->x_outmess + 10, 0); + SETFLOAT(x->x_outmess + 11, 0); + SETFLOAT(x->x_outmess + 12, 0); + outatoms = x->x_inatoms + 7; + for (i = 13; i < outatoms ; i++) + x->x_outmess[i] = x->x_inmess[i - 7]; + } + else outatoms = 5; + SETSEMI(x->x_outmess + outatoms); + binbuf_add(x->x_newbb, outatoms + 1, x->x_outmess); + x->x_nobj++; + return (PORT_NEXT); +} + +static int imaction_message(t_port *x, char *arg) +{ + int i; + SETSYMBOL(x->x_outmess, gensym("#X")); + SETSYMBOL(x->x_outmess + 1, gensym("msg")); + port_setxy(x, 2, x->x_outmess + 2); + for (i = 6; i < x->x_inatoms; i++) + x->x_outmess[i-2] = x->x_inmess[i]; + SETSEMI(x->x_outmess + x->x_inatoms - 2); + binbuf_add(x->x_newbb, x->x_inatoms - 1, x->x_outmess); + x->x_nobj++; + return (PORT_NEXT); +} + +/* FIXME this is no longer true */ +static int imaction_inlet(t_port *x, char *arg) +{ + return (import_obj(x, (port_floatarg(x, 5) ? "inlet~" : "inlet"))); +} + +/* FIXME this is no longer true */ +static int imaction_outlet(t_port *x, char *arg) +{ + return (import_obj(x, (port_floatarg(x, 5) ? "outlet~" : "outlet"))); +} + +static int imaction_number(t_port *x, char *arg) +{ + binbuf_addv(x->x_newbb, "ssff;", + gensym("#X"), gensym("floatatom"), + port_xarg(x, 2), port_yarg(x, 3)); + x->x_nobj++; + return (PORT_NEXT); +} + +static int imaction_connect(t_port *x, char *arg) +{ + binbuf_addv(x->x_newbb, "ssffff;", + gensym("#X"), gensym("connect"), + x->x_nobj - port_floatarg(x, 2) - 1, + port_floatarg(x, 3), + x->x_nobj - port_floatarg(x, 4) - 1, + port_floatarg(x, 5)); + return (PORT_NEXT); +} + +typedef int (*t_portaction)(t_port *, char *arg); + +typedef struct _portslot +{ + char *s_name; + int s_index; + t_portaction s_action; + char *s_actionarg; + struct _portnode *s_subtree; + t_symbol *s_symbol; +} t_portslot; + +typedef struct _portnode /* a parser's symbol definition, sort of... */ +{ + t_portslot *n_table; + int n_nslots; +} t_portnode; + +#define PORT_NSLOTS(slots) (sizeof(slots)/sizeof(*(slots))) + +static t_portslot imslots__N[] = +{ + { "vpatcher", 1, imaction_vpatcher, 0, 0, 0 } +}; +static t_portnode imnode__N = { imslots__N, PORT_NSLOTS(imslots__N) }; + +static t_portslot imslots_newobj[] = +{ + { "patcher", 6, imaction_patcher, 0, 0, 0 }, + { "p", 6, imaction_patcher, 0, 0, 0 }, + /* state is embedded in #N vtable...; #T set...; */ + { "table", 6, import_obj, "Table", 0, 0 } +}; +static t_portnode imnode_newobj = { imslots_newobj, + PORT_NSLOTS(imslots_newobj) }; + +/* LATER consider merging newobj and newex */ +static t_portslot imslots_newex[] = +{ + { "append", 6, import_objarg, "Append", 0, 0 }, + { "biquad~", 6, import_objarg, "Biquad~", 0, 0 }, + { "change", 6, import_objarg, "Change", 0, 0 }, + { "clip", 6, import_objarg, "Clip", 0, 0 }, + { "clip~", 6, import_objarg, "Clip~", 0, 0 }, + { "key", 6, import_obj, "Key", 0, 0 }, + { "keyup", 6, import_obj, "Keyup", 0, 0 }, + { "line", 6, import_objarg, "Line", 0, 0 }, + { "line~", 6, import_objarg, "Line~", 0, 0 }, + { "poly", 6, import_objarg, "Poly", 0, 0 }, + { "snapshot~", 6, import_objarg, "Snapshot~", 0, 0 }, + { "trigger", 6, imaction_trigger, 0, 0, 0 }, + { "t", 6, imaction_trigger, 0, 0, 0 } +}; +static t_portnode imnode_newex = { imslots_newex, + PORT_NSLOTS(imslots_newex) }; + +static t_portslot imslots_user[] = +{ + { "GSwitch", 2, import_objarg, "Gswitch", 0, 0 }, + { "GSwitch2", 2, import_objarg, "Ggate", 0, 0 }, + { "number~", 2, import_obj, 0, 0, 0 }, + { "scope~", 2, imaction_scope, "Scope~", 0, 0 }, + { "uslider", 2, import_obj, "vsl", 0, 0 } /* LATER range and offset */ +}; +static t_portnode imnode_user = { imslots_user, + PORT_NSLOTS(imslots_user) }; + +static t_portslot imslots__P[] = +{ + { "comment", 1, imaction_comment, 0, 0, 0 }, + { "message", 1, imaction_message, 0, 0, 0 }, + { "newobj", 1, import_objarg, 0, &imnode_newobj, 0 }, + { "newex", 1, import_objarg, 0, &imnode_newex, 0 }, + { "inlet", 1, imaction_inlet, 0, 0, 0 }, + { "inlet~", 1, imaction_inlet, 0, 0, 0 }, + { "outlet", 1, imaction_outlet, 0, 0, 0 }, + { "outlet~", 1, imaction_outlet, 0, 0, 0 }, + { "number", 1, imaction_number, 0, 0, 0 }, + { "flonum", 1, imaction_number, 0, 0, 0 }, + { "button", 1, import_obj, "bng", 0, 0 }, + { "slider" , 1, import_obj, "vsl", 0, 0 }, /* LATER range and offset */ + { "hslider", 1, import_obj, "hsl", 0, 0 }, /* LATER range and offset */ + { "toggle", 1, import_obj, "tgl", 0, 0 }, + { "user", 1, import_objarg, 0, &imnode_user, 0 }, + /* state is embedded in #N vpreset <nslots>; #X append... */ + { "preset", 1, import_obj, "preset", 0, 0 }, + /* an object created from the "Paste Picture" menu, + state is embedded in #N picture; #K...; */ + { "vpicture", 1, import_obj, "vpicture", 0, 0 }, + { "connect", 1, imaction_connect, 0, 0, 0 }, + { "fasten", 1, imaction_connect, 0, 0, 0 } +}; +static t_portnode imnode__P = { imslots__P, PORT_NSLOTS(imslots__P) }; + +static t_portslot imslots_[] = +{ + { "#N", 0, 0, 0, &imnode__N, 0 }, + { "#P", 0, 0, 0, &imnode__P, 0 } +}; +static t_portnode imnode_ = { imslots_, PORT_NSLOTS(imslots_) }; + +static int port_doit(t_port *x, t_portnode *node) +{ + int nslots = node->n_nslots; + if (nslots > 0) + { + t_portslot *slot = node->n_table; + t_symbol *s = port_symbolarg(x, slot->s_index); + while (nslots--) + { + if (slot->s_symbol == s) + { + if (slot->s_subtree) + { + int nobj = x->x_nobj; + int result = port_doit(x, slot->s_subtree); + if (result == PORT_FATAL || result == PORT_CORRUPT || + result == PORT_NEXT) + return (result); + } + if (slot->s_action) + return (slot->s_action(x, slot->s_actionarg)); + else + return (PORT_OK); /* LATER rethink */ + } + slot++; + } + } + else bug("port_doit"); + return (PORT_UNKNOWN); +} + +static void port_dochecksetup(t_portnode *node) +{ + t_portslot *slots = node->n_table; + int i, nslots = node->n_nslots; + for (i = 0; i < nslots; i++) + { + t_portnode *subtree = slots[i].s_subtree; + slots[i].s_symbol = gensym(slots[i].s_name); + if (subtree) + port_dochecksetup(subtree); + } +} + +static void port_checksetup(void) +{ + static int done = 0; + if (!done) + { + port_dochecksetup(&imnode_); + done = 1; + } +} + +static t_port *port_new(void) +{ + t_port *x = (t_port *)getbytes(sizeof(*x)); + x->x_oldbb = binbuf_new(); + x->x_outsize = PORT_INISIZE; + x->x_outatoms = 0; + x->x_outmess = x->x_outini; + x->x_stacksize = PORT_INISTACK; + x->x_stackdepth = 0; + x->x_stack = x->x_stackini; + return (x); +} + +static void port_free(t_port *x) +{ + if (x->x_outmess != x->x_outini) + freebytes(x->x_outmess, x->x_outsize * sizeof(*x->x_outmess)); + if (x->x_stack != x->x_stackini) + freebytes(x->x_stack, x->x_stacksize * sizeof(*x->x_stack)); + freebytes(x, sizeof(*x)); +} + +static int import_binbuf(t_port *x) +{ + t_atom *av = binbuf_getvec(x->x_oldbb); + int ac = binbuf_getnatom(x->x_oldbb); + int startmess, endmess; + x->x_newbb = binbuf_new(); + for (startmess = 0; startmess < ac; startmess = endmess + 1) + { + t_atom *mess = av + startmess, *ap; + int i; + for (endmess = startmess, ap = mess; + ap->a_type != A_SEMI; endmess++, ap++) + if (endmess == ac) + return (PORT_CORRUPT); /* no final semi */ + if (endmess == startmess || endmess == startmess + 1 + || mess->a_type != A_SYMBOL || mess[1].a_type != A_SYMBOL) + { + startmess = endmess + 1; + continue; + } + if (mess[1].a_w.w_symbol == gensym("hidden")) + { + t_symbol *sel = mess[1].a_w.w_symbol; + mess[1].a_w.w_symbol = mess->a_w.w_symbol; + startmess++; + mess++; + if (endmess == startmess + 1 || mess[1].a_type != A_SYMBOL) + { + startmess = endmess + 1; + continue; + } + } + x->x_inatoms = endmess - startmess; + x->x_inmess = mess; + if ((i = x->x_inatoms + 16) > x->x_outsize) /* LATER rethink */ + { + int sz = i; + x->x_outmess = grow_nodata(&sz, &x->x_outsize, x->x_outmess, + PORT_INISIZE, x->x_outini, + sizeof(*x->x_outmess)); + if (sz != i) + { + startmess = endmess + 1; + continue; /* LATER rethink */ + } + } + + /* dollar signs in file translate to symbols, + LATER rethink, also #-signs */ + for (i = 0, ap = x->x_inmess; i < x->x_inatoms; i++, ap++) + { + if (ap->a_type == A_DOLLAR) + { + char buf[100]; + sprintf(buf, "$%d", ap->a_w.w_index); + SETSYMBOL(ap, gensym(buf)); + } + else if (ap->a_type == A_DOLLSYM) + { + char buf[100]; + sprintf(buf, "$%s", ap->a_w.w_symbol->s_name); + SETSYMBOL(ap, gensym(buf)); + } + } + if (port_doit(x, &imnode_) == PORT_FATAL) + return (PORT_FATAL); + } + return (PORT_OK); +} + +void import_max(char *fn, char *dir) +{ + t_port *x; + int failure, fd, ftype; + char buf[MAXPDSTRING], *bufp; + t_pd *stackp = 0; + int dspstate = canvas_suspend_dsp(); + port_checksetup(); + if ((fd = open_via_path(dir, fn, "", buf, &bufp, MAXPDSTRING, 0)) < 0) + { + loud_error(0, "%s: can't open", fn); + return; + } + else close (fd); + + x = port_new(); + glob_setfilename(0, gensym(bufp), gensym(buf)); + ftype = binport_read(x->x_oldbb, bufp, buf); + if (ftype == BINPORT_MAXTEXT || ftype == BINPORT_PDFILE) + failure = binbuf_read(x->x_oldbb, bufp, buf, 0); + else + failure = (ftype != BINPORT_OK); /* LATER rethink */ + if (failure) + { + perror(fn); /* FIXME */ + binbuf_free(x->x_oldbb); + } + else + { + if (ftype == BINPORT_PDFILE) x->x_newbb = x->x_oldbb; + else + { + import_binbuf(x); + binbuf_free(x->x_oldbb); +#if 1 + binbuf_write(x->x_newbb, "import-result.pd", "", 0); +#endif + } + binbuf_eval(x->x_newbb, 0, 0, 0); + binbuf_free(x->x_newbb); + } + port_free(x); + + glob_setfilename(0, &s_, &s_); + canvas_resume_dsp(dspstate); + while ((stackp != s__X.s_thing) && (stackp = s__X.s_thing)) + vmess(stackp, gensym("pop"), "i", 1); +#if 0 /* LATER */ + pd_doloadbang(); +#endif +} |